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)
{
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
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];
}
- (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;
- (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)
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 );
}
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