AVPlayerLayer lock screen control - ios

I am using AVPlayerLayer to play video and playing the audio of video when app goes in background. Is there any way I can manage controls when screen is locked. User wants to stop play the audio.
My app is working in background but controls are not visible so user have to open the app and stop the video.

I got the solution simply used MPRemoteCommandCenter and added details about video see code in Objetive C
// to setup the playing info
- (void) setupNowPlayingInfoCenter{
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[commandCenter.togglePlayPauseCommand setEnabled:YES];
[commandCenter.playCommand setEnabled:YES];
[commandCenter.pauseCommand setEnabled:YES];
[commandCenter.nextTrackCommand setEnabled:NO];
[commandCenter.previousTrackCommand setEnabled:NO];
[commandCenter.playCommand addTargetWithHandler: ^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[self->_player play];
return MPRemoteCommandHandlerStatusSuccess;
}];
[commandCenter.pauseCommand addTargetWithHandler: ^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
[self->_player pause];
return MPRemoteCommandHandlerStatusSuccess;
}];
}
// to update the playing info when enter in background
- (void) updateNowPlayingInfoCenter {
NSDictionary *metadata = [self.media metaData];
MPNowPlayingInfoCenter *playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
[songInfo setObject:metadata[MIBMediaMetaDataTrackNameKey] forKey:MPMediaItemPropertyTitle];
[songInfo setObject:metadata[MIBMediaMetaDataTrackNameKey] forKey:MPMediaItemPropertyArtist];
[songInfo setObject:metadata[MIBMediaMetaDataTrackDurationKey] forKey:MPMediaItemPropertyPlaybackDuration];
[songInfo setObject:[NSNumber numberWithDouble:(!self.playing ? 0.0f : 1.0f)] forKey:MPNowPlayingInfoPropertyPlaybackRate];
[playingInfoCenter setNowPlayingInfo:songInfo];
}
// add this line of code in init or viewdidload
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(applicationDidEnterBackgroundNotification:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
Called these 2 methods when enter in background
- (void)applicationDidEnterBackgroundNotification:(NSNotification *)notification {
[self setupNowPlayingInfoCenter];
[self updateNowPlayingInfoCenter];
}

Related

Apple Music conflicting with MPNowPlayingInfoCenter

I need some help with an issue when my music player app is playing on background.
I'm able to play the musics in the app and in the background with both services. I'm also able to set the MPNowPlayingInfoCenter and it displays the correct info, but the play/pause, next track and previous tracks are working only when the user is authenticated with Spotify:
notifications are received correctly by the app when the user authenticates with Spotify
but it doesn't work when user authenticates with Apple Music. In this case it seems that Apple Music is the one receiving the notifications.
I'm using an AVPlayer to play the musics when synced with Apple Music and SPTAudioStreamingController when synced with Spotify.
Here is the code of the Media center setup:
- (void)setMediaCenterinfoForPlayer:(id)player {
SPTAudioStreamingController *spotifyPlayer;
AVPlayer *localPlayer;
NSMutableDictionary *trackInfo = [[NSMutableDictionary alloc] initWithDictionary: #{ MPMediaItemPropertyTitle: self.currentTrack.name,
MPMediaItemPropertyArtist: ((SPTArtist *)self.currentTrack.artists[0]).name,
MPMediaItemPropertyAlbumTitle : self.currentTrack.album.name,
MPNowPlayingInfoPropertyPlaybackRate: #(1.0)
}];
if ([player isKindOfClass:[SPTAudioStreamingController class]]) {
spotifyPlayer = (SPTAudioStreamingController *)player;
[trackInfo setObject:[NSNumber numberWithFloat:spotifyPlayer.currentPlaybackPosition] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
[trackInfo setObject:[NSNumber numberWithFloat:spotifyPlayer.currentTrackDuration] forKey:MPMediaItemPropertyPlaybackDuration];
} else {
localPlayer = (AVPlayer *)player;
NSTimeInterval playbackTime = [self currentPlaybackTimeForPlayer:player];
[trackInfo setObject:#(playbackTime) forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
[trackInfo setObject:#(CMTimeGetSeconds(localPlayer.currentItem.asset.duration)) forKey:MPMediaItemPropertyPlaybackDuration];
}
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = trackInfo;
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
Class playingInfoCenter = NSClassFromString(#"MPNowPlayingInfoCenter");
if (playingInfoCenter) {
[self albumURLCoverForCurrentTrackWithBlock:^(UIImage *albumImage) {
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:albumImage];
[trackInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:trackInfo];
}];
}
}
Here is the code for the event handling:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
if (event.type == UIEventTypeRemoteControl) {
MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
NSMutableDictionary *playingInfo = [NSMutableDictionary dictionaryWithDictionary:center.nowPlayingInfo];
[playingInfo setObject:[NSNumber numberWithFloat:[AudioPlayerManager sharedInstance].spotifyPlayer.currentPlaybackPosition] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
center.nowPlayingInfo = playingInfo;
if (event.subtype == UIEventSubtypeRemoteControlPlay) {
[[AudioPlayerManager sharedInstance] playTrack];
} else if (event.subtype == UIEventSubtypeRemoteControlPause) {
[[AudioPlayerManager sharedInstance] pauseTrack];
} else if (event.subtype == UIEventSubtypeRemoteControlPreviousTrack) {
[[AudioPlayerManager sharedInstance] previousTrack];
} else if (event.subtype == UIEventSubtypeRemoteControlNextTrack) {
[[AudioPlayerManager sharedInstance] nextTrack];
}
[[NSNotificationCenter defaultCenter] postNotificationName:kEventTypeRemoteControlUpdateState object:self];
}
}
Could anyone please point me a way to tackle this situation?

iOS MediaPlayer Remote control events not working

I'am trying to add remote control events to a music player app, but can't get it working.
Some facts:
I'm using [MPMusicPlayerController applicationMusicPlayer];
I added Audio, AirPlay and Picture in Picture background modes;
The example is playing audio;
It does not receive remote notifications from the lock screen and control center;
I've made an example project which can be downloaded here:
example project
The main source:
#import "ViewController.h"
#import <MediaPlayer/MPMediaPickerController.h>
#import <MediaPlayer/MPMediaQuery.h>
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController ()
#property (strong, nonatomic) MPMusicPlayerController *MusicPlayer;
#property (strong, nonatomic) MPMediaItemCollection *MusicPlayerSongs;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_MusicPlayerSongs = [MPMediaItemCollection alloc];
_MusicPlayer = [MPMusicPlayerController applicationMusicPlayer];
[_MusicPlayer setShuffleMode: MPMusicShuffleModeOff];
[_MusicPlayer setRepeatMode: MPMusicRepeatModeNone];
[_MusicPlayer beginGeneratingPlaybackNotifications];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSMutableArray *selectedTracks = [NSMutableArray new];
//Find all tracks that contains an 'a'
MPMediaPropertyPredicate *songPredicate =
[MPMediaPropertyPredicate predicateWithValue:#"a"
forProperty:MPMediaItemPropertyTitle
comparisonType:MPMediaPredicateComparisonContains];
MPMediaQuery *mediaQuery = [[MPMediaQuery alloc] init];
[mediaQuery addFilterPredicate:songPredicate];
[selectedTracks addObjectsFromArray:[mediaQuery items]];
NSLog(#"Number of tracks containing an 'a': %lu",(unsigned long)selectedTracks.count);
self.MusicPlayerSongs = [[MPMediaItemCollection alloc]initWithItems:selectedTracks];
[self.MusicPlayer setQueueWithItemCollection:self.MusicPlayerSongs];
[self.MusicPlayer play];
[self.MusicPlayer beginGeneratingPlaybackNotifications];
[self basicSetup];
[self updateNowPlayingCenter];
}
- (void)basicSetup {
//Listen to remote control events
[MPRemoteCommandCenter sharedCommandCenter].previousTrackCommand.enabled = NO;
[MPRemoteCommandCenter sharedCommandCenter].nextTrackCommand.enabled = NO;
[MPRemoteCommandCenter sharedCommandCenter].playCommand.enabled = YES;
[MPRemoteCommandCenter sharedCommandCenter].pauseCommand.enabled = YES;
[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand.enabled = YES;
[[MPRemoteCommandCenter sharedCommandCenter].nextTrackCommand addTarget:self action:#selector(remoteNext)];
[[MPRemoteCommandCenter sharedCommandCenter].previousTrackCommand addTarget:self action:#selector(remotePrevious)];
[[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:#selector(remotePlay)];
[[MPRemoteCommandCenter sharedCommandCenter].pauseCommand addTarget:self action:#selector(remotePlay)];
[[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand addTarget:self action:#selector(remoteTogglePlayState)];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
-(void)remotePlay{
NSLog(#"remotePlay");
[self.MusicPlayer play];
}
-(void)remoteNext{
NSLog(#"remoteNext");
[self.MusicPlayer skipToNextItem];
[self updateNowPlayingCenter];
}
-(void)remotePrevious{
NSLog(#"remotePrevious");
[self.MusicPlayer skipToPreviousItem];
[self updateNowPlayingCenter];
}
-(void)remotePause{
NSLog(#"remotePause");
[self.MusicPlayer pause];
}
-(void)remoteTogglePlayState{
NSLog(#"remoteTogglePlayState");
if([self.MusicPlayer playbackState] == MPMusicPlaybackStatePlaying){
[self.MusicPlayer pause];
}else{
[self.MusicPlayer play];
}
}
-(void)updateNowPlayingCenter{
MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
NSMutableDictionary *songInfo = [NSMutableDictionary dictionaryWithDictionary:#{
MPMediaItemPropertyArtist: [self.MusicPlayer nowPlayingItem].artist,
MPMediaItemPropertyTitle: [self.MusicPlayer nowPlayingItem].title,
MPMediaItemPropertyAlbumTitle: [self.MusicPlayer nowPlayingItem].albumTitle,
}];
center.nowPlayingInfo = songInfo;
}
I just can't figure out why it is not working :(
PROGRESS UPDATE'S
What I found out so far, if I reboot my iPhone, it works. But every time after that it won't.
The lock screen and control center both show the right track, but still can't control the app.
Not sure if this helps you at all, but here is how I received any changes (in Swift).
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.getNowPlayingItem), name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification, object: nil)
player.beginGeneratingPlaybackNotifications()
}
deinit {
player.endGeneratingPlaybackNotifications()
NSNotificationCenter.defaultCenter().removeObserver(self)
}
It is necessary to (addObserver and beginGeneratingPlaybackNotifications), but also to (removeObserver and endGeneratingPlaybackNotification). I am not yet familiar with remote control events, but you may want to try ending those notifications as well. Hope this helps!

how to show seek track duration on control center

How do i pass the song info such as song name and track duration to control center.
Player plays music fine and the play and pause control works fine though.
Playing with apple's music app
Playing with my app with the code below, how to pass song information in order to display it ?
//AppDelegate
-(void)setupAudio
{
// Set AVAudioSession
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setDelegate:self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&sessionError];
// Change the default output audio route
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
sizeof(doChangeDefaultRoute), &doChangeDefaultRoute);
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
//Make sure we can recieve remote control events
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
{
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl) {
if (event.subtype == UIEventSubtypeRemoteControlPlay)
{
NSLog(#"UIEventSubtypeRemoteControlPlay");
[[AppMusicPlayer sharedService]playAudio];
}
else if (event.subtype == UIEventSubtypeRemoteControlPause)
{
NSLog(#"UIEventSubtypeRemoteControlPause");
[[AppMusicPlayer sharedService]pauseAudio];
}
else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause)
{
NSLog(#"UIEventSubtypeRemoteControlTogglePlayPause");
}
}
}
AppMusicPlayer.m
+ (id) sharedService
{
static dispatch_once_t _singletonPredicate;
static AppMusicPlayer *_sharedObject = nil;
dispatch_once(&_singletonPredicate, ^{
_sharedObject = [[AppMusicPlayer alloc]init];
});
return _sharedObject;
}
- (id)init
{
self = [super init];
if (self) {
// Work your initialising here as you normally would
}
return self;
}
- (void)playAudio
{
[self.audioPlayer play];
}
- (void)pauseAudio
{
NSLog(#"pause");
[self.audioPlayer pause];
}
- (void)playAudioFromURL:(NSURL *)songURL
{
[self.audioPlayer stop];
//Declare the audio file location and settup the player
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:songURL error:&error];
[self.audioPlayer setNumberOfLoops:-1];
if (error)
{
NSLog(#"%#", [error localizedDescription]);
}
else
{
//Load the audio into memory
[self.audioPlayer prepareToPlay];
[self.audioPlayer play];
}
}
-(void)setUpRemoteControl
{
NSDictionary *nowPlaying = #{MPMediaItemPropertyArtist: songItem.artistName,
MPMediaItemPropertyAlbumTitle: songItem.albumTitle,
MPMediaItemPropertyPlaybackDuration:songItem.playbackDuration,
MPNowPlayingInfoPropertyPlaybackRate:#1.0f,
MPMediaItemPropertyArtwork:[songMedia valueForProperty:MPMediaItemPropertyArtwork]
};
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:nowPlaying];
}
Are you playing songs from iPods music library ?
If yes than You should you MPMusicPlayerViewController, it provides in-build functionality for seek bar properties as well as Info center.
I can see here in your code you have used AVAudioPlayer,
We can set only below details using AVAudioPlayer class, but can't access seekbar change event in our app.
NSMutableDictionary *albumInfo = [[NSMutableDictionary alloc] init];
UIImage *artWork = [UIImage imageNamed:album.imageUrl];
[albumInfo setObject:album.title forKey:MPMediaItemPropertyTitle];
[albumInfo setObject:album.auther forKey:MPMediaItemPropertyArtist];
[albumInfo setObject:album.title forKey:MPMediaItemPropertyAlbumTitle];
[albumInfo setObject:artworkP forKey:MPMediaItemPropertyArtwork];
[albumInfo setObject:album.playrDur forKey:MPMediaItemPropertyPlaybackDuration]
[albumInfo setObject:album.elapsedTime forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:albumInfo]
Here we need to count album.playrDur and album.elapsedTime as per required format.
You are looking for this:
- (IBAction)playButtonTouched:(id)sender {
Class playingInfoCenter = NSClassFromString(#"MPNowPlayingInfoCenter");
if (playingInfoCenter) {
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage: [UIImage imagedNamed:#"AlbumArt"]];
[songInfo setObject:#"Audio Title" forKey:MPMediaItemPropertyTitle];
[songInfo setObject:#"Audio Author" forKey:MPMediaItemPropertyArtist];
[songInfo setObject:#"Audio Album" forKey:MPMediaItemPropertyAlbumTitle];
[songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
}
}
I happen to be working on the same thing today and don't know the answer, but in my app the Control Center does show the app name. I want to be able to show the title of the thing I'm playing. I even have a picture I'd like to show, like an album cover. I don't think I'm doing anything different than you, I didn't code anything to send it the app name, for example.
Wait a second... I see there's something called MPNowPlayingInfoCenter that we should look into..
Not sure but may be this code help you little bit..
- (void) handle_NowPlayingItemChanged: (id) notification
{
MPMediaItem *currentItem = [musicPlayer nowPlayingItem];
NSString *titleString = [currentItem valueForProperty:MPMediaItemPropertyTitle];
if (titleString)
{
titleLabel.text = [NSString stringWithFormat:#"Title: %#",titleString];
}
else
{
titleLabel.text = #"Title: Unknown title";
}
}

AVQueuePlayer AVPlayerItemDidPlayToEndTimeNotification fails to call

Im using AVQueuePlayer to loop through an array of AVPlayerItems.
The way I'm looping it, I listen to the AVPlayerItemDidPlayToEndTimeNotification and every time its called, I add the current object to the end of the queue.
heres the code:
viewWillAppear
{
...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[_queuePlayer currentItem]];
[_queuePlayer play];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
AVPlayerItem *fakeNew = [[AVPlayerItem alloc] initWithAsset:p.asset];
if (_queuePlayer.items.count == 1)
{
[p seekToTime:kCMTimeZero];
[_queuePlayer play];
}
else
{
[_queuePlayer insertItem:fakeNew afterItem:[_queuePlayer.items lastObject]];
}
NSLog(#"array of items to play:%lu", (unsigned long)_queuePlayer.items.count);
}
The problem is, that the method is called only for the first video that plays, after that, the method stops getting called, so if for example i have 2 movies in the array, it would play them both+the first one again, any idea why is this happening?
More Info:
also tried to make a new player every time and set it to layer. failed to send the notification more than once just the same
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[self.playList removeObjectAtIndex:0];
[self.playList addObject:p];
AVPlayer *newPlayer = [[AVPlayer alloc] initWithPlayerItem:[self.playList objectAtIndex:0]];
_player = newPlayer;
self.AVPlayerLayerView.layer.player = self.player;
[_player play];
}
After a lot of messing around, apparently for whatever reason, the view unregistered as observer every time, I just removed and added observer after every notification:
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
AVPlayerItem *fakeNewItem = [[AVPlayerItem alloc] initWithAsset:p.asset];
[self.playList removeObjectAtIndex:0];
[self.playList addObject:fakeNewItem];
AVPlayer *newPlayer = [[AVPlayer alloc] initWithPlayerItem:[self.playList objectAtIndex:0]];
_player = newPlayer;
self.AVPlayerLayerView.layer.player = self.player;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[_player currentItem]];
[_player play];
}
For a clean approach to resolve this issue. I approached with the next piece of code instead
The first is you have to add the code necessary to receive a feedback from the AVPlayer when the reproduction time changes.
- (void)addPeriodicTimeObserverForReproductionChanges {
#weakify(self);
[self.player
addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(kBQDefaultTimeIntervalReproductionChanges, NSEC_PER_SEC)
queue:self.eventsQueue
usingBlock:^(CMTime time) {
#strongify(self);
[self dispatchBlockOnMainQueue:^{
if ([self.delegate respondsToSelector:#selector(playerItemController:didChangeReproductionTime:)])
[self.delegate playerItemController:self
didChangeReproductionTime:time];
[self checkForItemPlayToEnd];
}];
}];
}
- (void)checkForItemPlayToEnd
{
CMTime durationScaled = CMTimeConvertScale(self.duration,self.player.currentTime.timescale, kCMTimeRoundingMethod_Default);
if (CMTIME_COMPARE_INLINE(durationScaled, ==, self.player.currentTime)) {
[self playerDidFinishReproducingItem];
}
}

Video won't play in iPad simulator

I am trying to load a short movie file (.m4v) before the application starts
However, when I using the ipad simulator, only the sound plays. There is no video running.
If I change the simulator to iphone simulator, the video plays just fine.
I use MPMoviePlayerController to play the movie file
I even downloaded the sample mediaPlayer from Apple, and the result is the same. With the sample movie file (.m4v) the iphone simulator can play the movie, but the ipad simulator cannot
Please help!
Here is my solution if you need it:
The solution is integrated with cocos2d, but it should be relatively easy to modify it regardless.
Please refer to the following website for general usage:
Getting MPMoviePlayerController to Work with iOS4, 3.2 (iPad) and Earlier Versions of iPhone SDK
iPad iOS: 3.2.2
#implementation MovieLayer
/*
* name: movie file name
* type: movie file type
* target: target class to handle the selectors
* finish: selector called when the movie is finished
* load: selector called when the movie loading state is changed
*/
+ (id)layerWithMovieName:(NSString*)name type:(NSString*)movieType target:(id)target
finish:(SEL)finishSelector load:(SEL)loadSelector
{
return [[[self alloc] initWithMovieName:name type:movieType target:target
finish:finishSelector load:loadSelector] autorelease];
}
- (id)initWithMovieName:(NSString*)name type:(NSString*)movieType target:(id)target
finish:(SEL)finishSelector load:(SEL)loadSelector
{
if ((self = [super init]) != nil)
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *moviePath = [bundle pathForResource:name ofType:movieType];
if (moviePath)
{
NSURL *moviePathURL = [NSURL fileURLWithPath:moviePath];
[self loadMovieAtURL:moviePathURL];
// Movie finish loading notification
[[NSNotificationCenter defaultCenter]
addObserver:target
selector:loadSelector
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
// Movie finish Notification
[[NSNotificationCenter defaultCenter]
addObserver:target
selector:finishSelector
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
}
}
return self;
}
- (void)dealloc
{
[theMovie.view removeFromSuperview];
theMovie.initialPlaybackTime = -1;
[theMovie stop];
[theMovie release];
[super dealloc];
}
- (void)loadMovieAtURL:(NSURL*)theURL
{
CGSize size = [[CCDirector sharedDirector] winSize];
theMovie = [[MPMoviePlayerController alloc] initWithContentURL:theURL];
[theMovie prepareToPlay];
// > 3.2
[theMovie respondsToSelector:#selector(loadState)];
theMovie.scalingMode = MPMovieScalingModeAspectFill;
[theMovie setFullscreen:TRUE animated:TRUE];
theMovie.controlStyle = MPMovieControlStyleNone;
theMovie.view.frame = CGRectMake(0, 0, size.width, size.height);
theMovie.view.backgroundColor = [UIColor clearColor];
// Transform
theMovie.view.transform = CGAffineTransformMakeRotation(-270.0f * (M_PI/180.0f));
theMovie.view.center = [[CCDirector sharedDirector] openGLView].center;
[[[CCDirector sharedDirector] openGLView] addSubview:theMovie.view];
}
- (void)play
{
[theMovie play];
}
#end
Basic usage using cocos2d
MovieLayer *player = [MovieLayer layerWithMovieName:LOGO_ANIMATION
type:LOGO_ANIMATION_FILE_EXT
target:self
finish:#selector(myMovieFinishedCallback:)
load:#selector(myMovieLoadCallback:)];
[self addChild:player z: 0 tag:1];
}
return self;
}
- (void)myMovieLoadCallback:(NSNotification*)notification
{
MPMovieLoadState state = [(MPMoviePlayerController*)notification.object loadState];
// Remove observer
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
if (state & MPMovieLoadStateUnknown)
{
[self myMovieFinishedCallback:nil];
}
else if (state & MPMovieLoadStatePlayable)
{
[(MovieLayer*)[self getChildByTag:1] play];
}
else if (state & MPMovieLoadStatePlaythroughOK)
{
[(MovieLayer*)[self getChildByTag:1] play];
}
else if (state & MPMovieLoadStateStalled)
{
[self myMovieFinishedCallback:nil];
}
}
- (void)myMovieFinishedCallback:(NSNotification*)notification
{
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
[self removeChildByTag:1 cleanup:YES];
}
Almost certain this is a know bug/limitation in the simulator.

Resources