]> git.sesse.net Git - vlc/blobdiff - extras/MacOSX/Framework/Sources/VLCMediaPlayer.m
MacOSX/Framework/VLCMediaPlayer.m: -isSeekable.
[vlc] / extras / MacOSX / Framework / Sources / VLCMediaPlayer.m
index aa52aabcb3254ba486f7137a89222ba45b12d336..5fba9401e4d7579db18160687fb869fae471ab09 100644 (file)
 NSString *VLCMediaPlayerTimeChanged   = @"VLCMediaPlayerTimeChanged";
 NSString *VLCMediaPlayerStateChanged  = @"VLCMediaPlayerStateChanged";
 
+NSString *VLCMediaPlayerStateToString(VLCMediaPlayerState state)
+{
+    static NSString *stateToStrings[] = {
+        [VLCMediaPlayerStateStopped]      = @"VLCMediaPlayerStateStopped",
+        [VLCMediaPlayerStateOpening]      = @"VLCMediaPlayerStateOpening",
+        [VLCMediaPlayerStateBuffering]    = @"VLCMediaPlayerStateBuffering",
+        [VLCMediaPlayerStateEnded]        = @"VLCMediaPlayerStateEnded",
+        [VLCMediaPlayerStateError]        = @"VLCMediaPlayerStateError",
+        [VLCMediaPlayerStatePlaying]      = @"VLCMediaPlayerStatePlaying",
+        [VLCMediaPlayerStatePaused]       = @"VLCMediaPlayerStatePaused"
+    };
+    return stateToStrings[state];
+}
+
 /* libvlc event callback */
 static void HandleMediaInstanceVolumeChanged(const libvlc_event_t *event, void *self)
 {
@@ -43,53 +57,86 @@ static void HandleMediaInstanceVolumeChanged(const libvlc_event_t *event, void *
 
 static void HandleMediaTimeChanged(const libvlc_event_t * event, void * self)
 {
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
+                                                 withMethod:@selector(mediaPlayerTimeChanged:) 
+                                       withArgumentAsObject:[NSNumber numberWithLongLong:event->u.media_instance_time_changed.new_time]];
+
     [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
                                                    withDelegateMethod:@selector(mediaPlayerTimeChanged:)
                                                  withNotificationName:VLCMediaPlayerTimeChanged];
-        
+    [pool release];
+}
+
+static void HandleMediaPositionChanged(const libvlc_event_t * event, void * self)
+{
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
+                                                 withMethod:@selector(mediaPlayerPositionChanged:) 
+                                       withArgumentAsObject:[NSNumber numberWithFloat:event->u.media_instance_position_changed.new_position]];
+    [pool release];
 }
 
 static void HandleMediaInstanceStateChanged(const libvlc_event_t *event, void *self)
 {
+    VLCMediaPlayerState newState;
+    
+    if( event->type == libvlc_MediaInstancePlayed )
+        newState = VLCMediaPlayerStatePlaying;
+    else if( event->type == libvlc_MediaInstancePaused )
+        newState = VLCMediaPlayerStatePaused;
+    else if( event->type == libvlc_MediaInstanceReachedEnd )
+        newState = VLCMediaPlayerStateStopped;
+    else
+    {
+        NSLog(@"%s: Unknown event", __FUNCTION__);
+        return;
+    }
+
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+    [[VLCEventManager sharedManager] callOnMainThreadObject:self 
+                                                 withMethod:@selector(mediaPlayerStateChanged:) 
+                                       withArgumentAsObject:[NSNumber numberWithInt:newState]];
+
     [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
                                                    withDelegateMethod:@selector(mediaPlayerStateChanged:)
                                                  withNotificationName:VLCMediaPlayerStateChanged];
-}
 
-NSString *VLCMediaPlayerStateToString(VLCMediaPlayerState state)
-{
-    static NSString *stateToStrings[] = {
-        [VLCMediaPlayerStateStopped]      = @"VLCMediaPlayerStateStopped",
-        [VLCMediaPlayerStateOpening]      = @"VLCMediaPlayerStateOpening",
-        [VLCMediaPlayerStateBuffering]    = @"VLCMediaPlayerStateBuffering",
-        [VLCMediaPlayerStateEnded]        = @"VLCMediaPlayerStateEnded",
-        [VLCMediaPlayerStateError]        = @"VLCMediaPlayerStateError",
-        [VLCMediaPlayerStatePlaying]      = @"VLCMediaPlayerStatePlaying",
-        [VLCMediaPlayerStatePaused]       = @"VLCMediaPlayerStatePaused"
-    };
-    return stateToStrings[state];
+    [pool release];
+
 }
 
+
 // TODO: Documentation
 @interface VLCMediaPlayer (Private)
 - (void)registerObservers;
 - (void)unregisterObservers;
+- (void)mediaPlayerTimeChanged:(NSNumber *)newTime;
+- (void)mediaPlayerPositionChanged:(NSNumber *)newTime;
+- (void)mediaPlayerStateChanged:(NSNumber *)newState;
 @end
 
 @implementation VLCMediaPlayer
+
 - (id)init
 {
-    self = [self initWithVideoView:nil];
-    return self;
+    return [self initWithVideoView:nil];
 }
 
 - (id)initWithVideoView:(VLCVideoView *)aVideoView
 {
     if (self = [super init])
     {
+        [VLCMediaPlayer setKeys:[NSArray arrayWithObject:@"state"] triggerChangeNotificationsForDependentKey:@"playing"];
+        [VLCMediaPlayer setKeys:[NSArray arrayWithObjects:@"state", @"media", nil] triggerChangeNotificationsForDependentKey:@"seekable"];
         delegate = nil;
         media = nil;
-        
+        cachedTime = [[VLCTime nullTime] retain];
+        position = 0.0f;
+        cachedState = VLCMediaPlayerStateStopped;
+
         // Create a media instance, it doesn't matter what library we start off with
         // it will change depending on the media descriptor provided to the media
         // instance
@@ -105,21 +152,33 @@ NSString *VLCMediaPlayerStateToString(VLCMediaPlayerState state)
     return self;
 }
 
+- (void)release
+{
+    @synchronized(self)
+    {
+        if([self retainCount] <= 1)
+        {
+            /* We must make sure we won't receive new event after an upcoming dealloc
+             * We also may receive a -retain in some event callback that may occcur
+             * Before libvlc_event_detach. So this can't happen in dealloc */
+            [self unregisterObservers];
+        }
+        [super release];
+    }
+}
+
 - (void)dealloc
 {
     // Always get rid of the delegate first so we can stop sending messages to it
     // TODO: Should we tell the delegate that we're shutting down?
     delegate = nil;
 
-    // Next get rid of the event managers so we can stop trapping events
-    [self unregisterObservers];
     libvlc_media_instance_release((libvlc_media_instance_t *)instance);
     
     // Get rid of everything else
-    instance = nil;
-    videoView = nil;
     [media release];
-    
+    [cachedTime release];
+
     [super dealloc];
 }
 
@@ -282,18 +341,7 @@ NSString *VLCMediaPlayerStateToString(VLCMediaPlayerState state)
 
 - (VLCTime *)time
 {
-    libvlc_exception_t ex;
-    libvlc_exception_init( &ex );
-    
-    // Results are returned in seconds...duration is returned in milliseconds
-    long long time = libvlc_media_instance_get_time( (libvlc_media_instance_t *)instance, &ex ) * 1000;
-    if (libvlc_exception_raised( &ex ))
-    {
-        libvlc_exception_clear( &ex );
-        return [VLCTime nullTime];        // Error in obtaining the time, return a null time defintition (--:--:--)
-    }
-    else
-        return [VLCTime timeWithNumber:[NSNumber numberWithLongLong:time]];
+    return cachedTime;
 }
 
 - (void)setChapter:(int)value;
@@ -490,21 +538,31 @@ static const VLCMediaPlayerState libvlc_to_local_state[] =
 
 - (VLCMediaPlayerState)state
 {
-    // If there is no instance, assume that we're in a stopped state
-    if (!instance)
-        return VLCMediaPlayerStateStopped;
-    
+    return cachedState;
+}
+
+- (float)position
+{
+    return position;
+}
+
+- (void)setPosition:(float)newPosition
+{
     libvlc_exception_t ex;
     libvlc_exception_init( &ex );
-    libvlc_state_t libvlc_state = libvlc_media_instance_get_state( (libvlc_media_instance_t *)instance, &ex );
-    if (libvlc_exception_raised( &ex ))
-    {
-        libvlc_exception_clear( &ex );
-        return VLCMediaPlayerStateError;
-    }
-    else
-        return libvlc_to_local_state[libvlc_state];
+    libvlc_media_instance_set_position( instance, newPosition, &ex );
+    quit_on_exception( &ex );
+}
+
+- (BOOL)isSeekable
+{
+    libvlc_exception_t ex;
+    libvlc_exception_init( &ex );
+    BOOL ret = libvlc_media_instance_is_seekable( instance, &ex );
+    quit_on_exception( &ex );
+    return ret;
 }
+
 @end
 
 @implementation VLCMediaPlayer (Private)
@@ -518,7 +576,9 @@ static const VLCMediaPlayerState libvlc_to_local_state[] =
     libvlc_event_attach( p_em, libvlc_MediaInstancePlayed,          HandleMediaInstanceStateChanged, self, &ex );
     libvlc_event_attach( p_em, libvlc_MediaInstancePaused,          HandleMediaInstanceStateChanged, self, &ex );
     libvlc_event_attach( p_em, libvlc_MediaInstanceReachedEnd,      HandleMediaInstanceStateChanged, self, &ex );
-    libvlc_event_attach( p_em, libvlc_MediaInstancePositionChanged, HandleMediaTimeChanged,            self, &ex );
+    /* FIXME: We may want to turn that off when none is interested by that */
+    libvlc_event_attach( p_em, libvlc_MediaInstancePositionChanged, HandleMediaPositionChanged,      self, &ex );
+    libvlc_event_attach( p_em, libvlc_MediaInstanceTimeChanged,     HandleMediaTimeChanged,          self, &ex );
     quit_on_exception( &ex );
 }
 
@@ -529,5 +589,30 @@ static const VLCMediaPlayerState libvlc_to_local_state[] =
     libvlc_event_detach( p_em, libvlc_MediaInstancePaused,          HandleMediaInstanceStateChanged, self, NULL );
     libvlc_event_detach( p_em, libvlc_MediaInstanceReachedEnd,      HandleMediaInstanceStateChanged, self, NULL );
     libvlc_event_detach( p_em, libvlc_MediaInstancePositionChanged, HandleMediaTimeChanged,            self, NULL );
+    libvlc_event_detach( p_em, libvlc_MediaInstanceTimeChanged,     HandleMediaTimeChanged,            self, NULL );
+}
+
+- (void)mediaPlayerTimeChanged:(NSNumber *)newTime
+{
+    [self willChangeValueForKey:@"time"];
+    [cachedTime release];
+    cachedTime = [[VLCTime timeWithNumber:newTime] retain];
+    [self didChangeValueForKey:@"time"];
 }
-@end
\ No newline at end of file
+
+- (void)mediaPlayerPositionChanged:(NSNumber *)newPosition
+{
+    if( [newPosition floatValue] - position < 0.005 && position - [newPosition floatValue] < 0.005 )
+        return; /* Forget that, this is too much precision for our uses */
+    [self willChangeValueForKey:@"position"];
+    position = ((float)((int)([newPosition floatValue]*1000)))/1000.;
+    [self didChangeValueForKey:@"position"];
+}
+
+- (void)mediaPlayerStateChanged:(NSNumber *)newState
+{
+    [self willChangeValueForKey:@"state"];
+    cachedState = [newState intValue];
+    [self didChangeValueForKey:@"state"];
+}
+@end