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)setAudioTrack:(int)value
301 libvlc_audio_set_track(instance, value, NULL);
306 libvlc_exception_t ex;
307 libvlc_exception_init(&ex);
308 int result = libvlc_audio_get_track(instance, &ex);
309 quit_on_exception(&ex);
313 - (void)setAudioChannel:(int)value
315 libvlc_audio_set_channel(instance, value, NULL);
320 libvlc_exception_t ex;
321 libvlc_exception_init(&ex);
322 int result = libvlc_audio_get_channel(instance, &ex);
323 quit_on_exception(&ex);
327 - (void)setMedia:(VLCMedia *)value
329 // We only know how to play media files...not media resources with subitems
330 if (media != value && [media subitems] == nil)
332 if (media && [media compare:value] == NSOrderedSame)
336 if (wasPlaying = [self isPlaying])
339 // // TODO: Should we wait until it stops playing?
340 // while ([self isPlaying])
344 [self willChangeValueForKey:@"media"];
346 media = [value retain];
347 [self didChangeValueForKey:@"media"];
349 libvlc_exception_t ex;
350 libvlc_exception_init(&ex);
351 libvlc_media_instance_set_media_descriptor(instance, [media libVLCMediaDescriptor], &ex);
352 quit_on_exception(&ex);
368 // Return if there is no media available or if the stream is already playing something
369 if (!media || [self isPlaying])
370 return [self isPlaying];
372 libvlc_exception_t ex;
373 libvlc_exception_init(&ex);
375 libvlc_media_instance_play((libvlc_media_instance_t *)instance, &ex);
376 quit_on_exception(&ex);
383 // Return if there is no media available or if the stream is not paused or
384 // playing something else
385 if (!media || (![self isPlaying] && [self state] != VLCMediaPlayerStatePaused))
388 // Should never get here.
393 libvlc_exception_t ex;
394 libvlc_exception_init(&ex);
395 libvlc_media_instance_pause((libvlc_media_instance_t *)instance, &ex);
396 quit_on_exception(&ex);
398 // TODO: Should we record the time in case the media instance is destroyed
404 // Return if there is no media available or if the system is not in play status
406 if (!media || (![self isPlaying] && [self state] != VLCMediaPlayerStatePaused))
409 // The following is not implemented in the core, should I fix it or just
411 // libvlc_exception_t ex;
412 // libvlc_exception_init(&ex);
413 // libvlc_media_instance_stop((libvlc_media_instance_t *)instance, &ex);
414 // quit_on_exception(&ex);
416 // Pause and reposition to the begining of the stream.
419 // TODO: Should we pause this or destroy the media instance so that it appears as being "stopped"?
422 //- (void)fastForward;
423 //- (void)fastForwardAtRate:(int)rate;
425 //- (void)rewindAtRate:(int)rate;
429 VLCMediaPlayerState state = [self state];
430 return ((state == VLCMediaPlayerStateOpening) || (state == VLCMediaPlayerStateBuffering) ||
431 (state == VLCMediaPlayerStatePlaying));
436 libvlc_exception_t ex;
437 libvlc_exception_init(&ex);
438 BOOL ret = libvlc_media_instance_will_play((libvlc_media_instance_t *)instance, &ex);
439 if (libvlc_exception_raised(&ex))
441 libvlc_exception_clear(&ex);
448 static VLCMediaPlayerState libvlc_to_local_state [] =
450 [libvlc_Stopped] = VLCMediaPlayerStateStopped,
451 [libvlc_Opening] = VLCMediaPlayerStateOpening,
452 [libvlc_Buffering] = VLCMediaPlayerStateBuffering,
453 [libvlc_Playing] = VLCMediaPlayerStatePlaying,
454 [libvlc_Paused] = VLCMediaPlayerStatePaused,
455 [libvlc_Ended] = VLCMediaPlayerStateEnded,
456 [libvlc_Error] = VLCMediaPlayerStateError
459 - (VLCMediaPlayerState)state
461 // If there is no instance, assume that we're in a stopped state
463 return VLCMediaPlayerStateStopped;
465 libvlc_exception_t ex;
466 libvlc_exception_init(&ex);
467 libvlc_state_t libvlc_state = libvlc_media_instance_get_state((libvlc_media_instance_t *)instance, &ex);
468 if (libvlc_exception_raised(&ex))
470 libvlc_exception_clear(&ex);
471 return VLCMediaPlayerStateError;
474 return libvlc_to_local_state[libvlc_state];
478 @implementation VLCMediaPlayer (Private)
479 - (void)registerObservers
481 libvlc_exception_t ex;
482 libvlc_exception_init(&ex);
484 // Attach event observers into the media instance
485 libvlc_event_manager_t *p_em = libvlc_media_instance_event_manager(instance, &ex);
486 libvlc_event_attach(p_em, libvlc_MediaInstancePlayed, HandleMediaInstanceStateChanged, self, &ex);
487 libvlc_event_attach(p_em, libvlc_MediaInstancePaused, HandleMediaInstanceStateChanged, self, &ex);
488 libvlc_event_attach(p_em, libvlc_MediaInstanceReachedEnd, HandleMediaInstanceStateChanged, self, &ex);
489 libvlc_event_attach(p_em, libvlc_MediaInstancePositionChanged, HandleMediaTimeChanged, self, &ex);
490 quit_on_exception(&ex);
493 - (void)unregisterObservers
495 libvlc_event_manager_t *p_em = libvlc_media_instance_event_manager(instance, NULL);
496 libvlc_event_detach(p_em, libvlc_MediaInstancePlayed, HandleMediaInstanceStateChanged, self, NULL);
497 libvlc_event_detach(p_em, libvlc_MediaInstancePaused, HandleMediaInstanceStateChanged, self, NULL);
498 libvlc_event_detach(p_em, libvlc_MediaInstanceReachedEnd, HandleMediaInstanceStateChanged, self, NULL);
499 libvlc_event_detach(p_em, libvlc_MediaInstancePositionChanged, HandleMediaTimeChanged, self, NULL);