1 /*****************************************************************************
2 * VLCMediaPlayer.m: VLC.framework VLCMediaPlayer implementation
3 *****************************************************************************
4 * Copyright (C) 2007 Pierre d'Herbemont
5 * Copyright (C) 2007 the VideoLAN team
8 * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
9 * Faustion Osuna <enrique.osuna # gmail.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 #import "VLCLibrary.h"
27 #import "VLCMediaPlayer.h"
28 #import "VLCEventManager.h"
29 #import "VLCLibVLCBridging.h"
32 /* Notification Messages */
33 NSString *VLCMediaPlayerTimeChanged = @"VLCMediaPlayerTimeChanged";
34 NSString *VLCMediaPlayerStateChanged = @"VLCMediaPlayerStateChanged";
36 /* libvlc event callback */
37 static void HandleMediaInstanceVolumeChanged(const libvlc_event_t *event, void *self)
39 [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
40 withDelegateMethod:@selector(mediaPlayerVolumeChanged:)
41 withNotificationName:VLCMediaPlayerVolumeChanged];
44 static void HandleMediaTimeChanged(const libvlc_event_t * event, void * self)
46 [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
47 withDelegateMethod:@selector(mediaPlayerTimeChanged:)
48 withNotificationName:VLCMediaPlayerTimeChanged];
52 static void HandleMediaInstanceStateChanged(const libvlc_event_t *event, void *self)
54 [[VLCEventManager sharedManager] callOnMainThreadDelegateOfObject:self
55 withDelegateMethod:@selector(mediaPlayerStateChanged:)
56 withNotificationName:VLCMediaPlayerStateChanged];
59 NSString *VLCMediaPlayerStateToString(VLCMediaPlayerState state)
61 static NSString *stateToStrings[] = {
62 [VLCMediaPlayerStateStopped] = @"VLCMediaPlayerStateStopped",
63 [VLCMediaPlayerStateOpening] = @"VLCMediaPlayerStateOpening",
64 [VLCMediaPlayerStateBuffering] = @"VLCMediaPlayerStateBuffering",
65 [VLCMediaPlayerStateEnded] = @"VLCMediaPlayerStateEnded",
66 [VLCMediaPlayerStateError] = @"VLCMediaPlayerStateError",
67 [VLCMediaPlayerStatePlaying] = @"VLCMediaPlayerStatePlaying",
68 [VLCMediaPlayerStatePaused] = @"VLCMediaPlayerStatePaused"
70 return stateToStrings[state];
73 // TODO: Documentation
74 @interface VLCMediaPlayer (Private)
75 - (void)registerObservers;
76 - (void)unregisterObservers;
79 @implementation VLCMediaPlayer
82 self = [self initWithVideoView:nil];
86 - (id)initWithVideoView:(VLCVideoView *)aVideoView
88 if (self = [super init])
93 // Create a media instance, it doesn't matter what library we start off with
94 // it will change depending on the media descriptor provided to the media
96 libvlc_exception_t ex;
97 libvlc_exception_init( &ex );
98 instance = (void *)libvlc_media_instance_new([VLCLibrary sharedInstance], &ex);
99 quit_on_exception( &ex );
101 [self registerObservers];
103 [self setVideoView:aVideoView];
110 // Always get rid of the delegate first so we can stop sending messages to it
111 // TODO: Should we tell the delegate that we're shutting down?
114 // Next get rid of the event managers so we can stop trapping events
115 [self unregisterObservers];
116 libvlc_media_instance_release((libvlc_media_instance_t *)instance);
118 // Get rid of everything else
126 - (void)setDelegate:(id)value
136 - (void)setVideoView:(VLCVideoView *)value
140 // Make sure that this instance has been associated with the drawing canvas.
141 libvlc_exception_t ex;
142 libvlc_exception_init( &ex );
143 libvlc_media_instance_set_drawable ((libvlc_media_instance_t *)instance,
144 (libvlc_drawable_t)videoView,
146 quit_on_exception( &ex );
149 - (VLCVideoView *)videoView
154 - (void)setFullscreen:(BOOL)value
156 libvlc_set_fullscreen(instance, value, NULL);
161 libvlc_exception_t ex;
162 libvlc_exception_init( &ex );
163 int result = libvlc_get_fullscreen( instance, &ex );
164 quit_on_exception( &ex );
168 - (void)setVideoAspectRatio:(char *)value
170 libvlc_video_set_aspect_ratio( instance, value, NULL );
173 - (char *)videoAspectRatio
175 libvlc_exception_t ex;
176 libvlc_exception_init( &ex );
177 char *result = libvlc_video_get_aspect_ratio( instance, &ex );
178 quit_on_exception( &ex );
182 - (void)setVideoSubTitles:(int)value
184 libvlc_video_set_spu( instance, value, NULL );
187 - (int)videoSubTitles
189 libvlc_exception_t ex;
190 libvlc_exception_init( &ex );
191 int result = libvlc_video_get_spu( instance, &ex );
192 quit_on_exception( &ex );
196 - (void)setVideoCropGeometry:(char *)value
198 libvlc_video_set_crop_geometry( instance, value, NULL );
201 - (char *)videoCropGeometry
203 libvlc_exception_t ex;
204 libvlc_exception_init( &ex );
205 char *result = libvlc_video_get_crop_geometry( instance, &ex );
206 quit_on_exception( &ex );
210 - (void)setVideoTeleText:(int)value
212 libvlc_video_set_teletext( instance, value, NULL );
217 libvlc_exception_t ex;
218 libvlc_exception_init( &ex );
219 int result = libvlc_video_get_teletext( instance, &ex );
220 quit_on_exception( &ex );
224 - (void)setRate:(int)value
226 libvlc_media_instance_set_rate( instance, value, NULL );
231 libvlc_exception_t ex;
232 libvlc_exception_init( &ex );
233 float result = libvlc_media_instance_get_rate( instance, &ex );
234 quit_on_exception( &ex );
240 libvlc_exception_t ex;
241 libvlc_exception_init( &ex );
242 NSSize result = NSMakeSize(libvlc_video_get_height((libvlc_media_instance_t *)instance, &ex),
243 libvlc_video_get_width((libvlc_media_instance_t *)instance, &ex));
244 quit_on_exception( &ex );
250 libvlc_exception_t ex;
251 libvlc_exception_init( &ex );
252 BOOL result = libvlc_media_instance_has_vout((libvlc_media_instance_t *)instance, &ex);
253 if (libvlc_exception_raised( &ex ))
255 libvlc_exception_clear( &ex );
262 - (float)framesPerSecond
264 libvlc_exception_t ex;
265 libvlc_exception_init( &ex );
266 float result = libvlc_media_instance_get_fps( (libvlc_media_instance_t *)instance, &ex );
267 quit_on_exception( &ex );
271 - (void)setTime:(VLCTime *)value
273 libvlc_exception_t ex;
274 libvlc_exception_init( &ex );
275 // Time is managed in seconds, while duration is managed in microseconds
276 // TODO: Redo VLCTime to provide value numberAsMilliseconds, numberAsMicroseconds, numberAsSeconds, numberAsMinutes, numberAsHours
277 libvlc_media_instance_set_time( (libvlc_media_instance_t *)instance,
278 (value ? [[value numberValue] longLongValue] / 1000 : 0),
280 quit_on_exception( &ex );
285 libvlc_exception_t ex;
286 libvlc_exception_init( &ex );
288 // Results are returned in seconds...duration is returned in milliseconds
289 long long time = libvlc_media_instance_get_time( (libvlc_media_instance_t *)instance, &ex ) * 1000;
290 if (libvlc_exception_raised( &ex ))
292 libvlc_exception_clear( &ex );
293 return [VLCTime nullTime]; // Error in obtaining the time, return a null time defintition (--:--:--)
296 return [VLCTime timeWithNumber:[NSNumber numberWithLongLong:time]];
299 - (void)setChapter:(int)value;
301 libvlc_media_instance_set_chapter( instance, value, NULL );
306 libvlc_exception_t ex;
307 libvlc_exception_init( &ex );
308 int result = libvlc_media_instance_get_chapter( instance, &ex );
309 quit_on_exception( &ex );
313 - (int)countOfChapters
315 libvlc_exception_t ex;
316 libvlc_exception_init( &ex );
317 int result = libvlc_media_instance_get_chapter_count( instance, &ex );
318 quit_on_exception( &ex );
322 - (void)setAudioTrack:(int)value
324 libvlc_audio_set_track( instance, value, NULL );
329 libvlc_exception_t ex;
330 libvlc_exception_init( &ex );
331 int result = libvlc_audio_get_track( instance, &ex );
332 quit_on_exception( &ex );
336 - (int)countOfAudioTracks
338 libvlc_exception_t ex;
339 libvlc_exception_init( &ex );
340 int result = libvlc_audio_get_track_count( instance, &ex );
341 quit_on_exception( &ex );
345 - (void)setAudioChannel:(int)value
347 libvlc_audio_set_channel( instance, value, NULL );
352 libvlc_exception_t ex;
353 libvlc_exception_init( &ex );
354 int result = libvlc_audio_get_channel( instance, &ex );
355 quit_on_exception( &ex );
359 - (void)setMedia:(VLCMedia *)value
361 // We only know how to play media files...not media resources with subitems
362 if (media != value && [media subitems] == nil)
364 if (media && [media compare:value] == NSOrderedSame)
368 if (wasPlaying = [self isPlaying])
371 // // TODO: Should we wait until it stops playing?
372 // while ([self isPlaying])
376 [self willChangeValueForKey:@"media"];
378 media = [value retain];
379 [self didChangeValueForKey:@"media"];
381 libvlc_exception_t ex;
382 libvlc_exception_init( &ex );
383 libvlc_media_instance_set_media_descriptor( instance, [media libVLCMediaDescriptor], &ex );
384 quit_on_exception( &ex );
400 // Return if there is no media available or if the stream is already playing something
401 if (!media || [self isPlaying])
402 return [self isPlaying];
404 libvlc_exception_t ex;
405 libvlc_exception_init( &ex );
407 libvlc_media_instance_play( (libvlc_media_instance_t *)instance, &ex );
408 quit_on_exception( &ex );
415 // Return if there is no media available or if the stream is not paused or
416 // playing something else
417 if (!media || (![self isPlaying] && [self state] != VLCMediaPlayerStatePaused))
420 // Should never get here.
425 libvlc_exception_t ex;
426 libvlc_exception_init( &ex );
427 libvlc_media_instance_pause( (libvlc_media_instance_t *)instance, &ex );
428 quit_on_exception( &ex );
430 // TODO: Should we record the time in case the media instance is destroyed
436 // Return if there is no media available or if the system is not in play status
438 if (!media || (![self isPlaying] && [self state] != VLCMediaPlayerStatePaused))
441 // The following is not implemented in the core, should I fix it or just
443 // libvlc_exception_t ex;
444 // libvlc_exception_init( &ex );
445 // libvlc_media_instance_stop((libvlc_media_instance_t *)instance, &ex);
446 // quit_on_exception( &ex );
448 // Pause and reposition to the begining of the stream.
451 // TODO: Should we pause this or destroy the media instance so that it appears as being "stopped"?
454 //- (void)fastForward;
455 //- (void)fastForwardAtRate:(int)rate;
457 //- (void)rewindAtRate:(int)rate;
461 VLCMediaPlayerState state = [self state];
462 return ((state == VLCMediaPlayerStateOpening) || (state == VLCMediaPlayerStateBuffering) ||
463 (state == VLCMediaPlayerStatePlaying));
468 libvlc_exception_t ex;
469 libvlc_exception_init( &ex );
470 BOOL ret = libvlc_media_instance_will_play( (libvlc_media_instance_t *)instance, &ex );
471 if (libvlc_exception_raised(&ex))
473 libvlc_exception_clear(&ex);
480 static const VLCMediaPlayerState libvlc_to_local_state[] =
482 [libvlc_Stopped] = VLCMediaPlayerStateStopped,
483 [libvlc_Opening] = VLCMediaPlayerStateOpening,
484 [libvlc_Buffering] = VLCMediaPlayerStateBuffering,
485 [libvlc_Playing] = VLCMediaPlayerStatePlaying,
486 [libvlc_Paused] = VLCMediaPlayerStatePaused,
487 [libvlc_Ended] = VLCMediaPlayerStateEnded,
488 [libvlc_Error] = VLCMediaPlayerStateError
491 - (VLCMediaPlayerState)state
493 // If there is no instance, assume that we're in a stopped state
495 return VLCMediaPlayerStateStopped;
497 libvlc_exception_t ex;
498 libvlc_exception_init( &ex );
499 libvlc_state_t libvlc_state = libvlc_media_instance_get_state( (libvlc_media_instance_t *)instance, &ex );
500 if (libvlc_exception_raised( &ex ))
502 libvlc_exception_clear( &ex );
503 return VLCMediaPlayerStateError;
506 return libvlc_to_local_state[libvlc_state];
510 @implementation VLCMediaPlayer (Private)
511 - (void)registerObservers
513 libvlc_exception_t ex;
514 libvlc_exception_init( &ex );
516 // Attach event observers into the media instance
517 libvlc_event_manager_t *p_em = libvlc_media_instance_event_manager( instance, &ex );
518 libvlc_event_attach( p_em, libvlc_MediaInstancePlayed, HandleMediaInstanceStateChanged, self, &ex );
519 libvlc_event_attach( p_em, libvlc_MediaInstancePaused, HandleMediaInstanceStateChanged, self, &ex );
520 libvlc_event_attach( p_em, libvlc_MediaInstanceReachedEnd, HandleMediaInstanceStateChanged, self, &ex );
521 libvlc_event_attach( p_em, libvlc_MediaInstancePositionChanged, HandleMediaTimeChanged, self, &ex );
522 quit_on_exception( &ex );
525 - (void)unregisterObservers
527 libvlc_event_manager_t *p_em = libvlc_media_instance_event_manager( instance, NULL );
528 libvlc_event_detach( p_em, libvlc_MediaInstancePlayed, HandleMediaInstanceStateChanged, self, NULL );
529 libvlc_event_detach( p_em, libvlc_MediaInstancePaused, HandleMediaInstanceStateChanged, self, NULL );
530 libvlc_event_detach( p_em, libvlc_MediaInstanceReachedEnd, HandleMediaInstanceStateChanged, self, NULL );
531 libvlc_event_detach( p_em, libvlc_MediaInstancePositionChanged, HandleMediaTimeChanged, self, NULL );