Responding to MPMoviePlayerController notifications during background media playback - iphone

I have an app that streams video from the net and plays it using an MPMoviePlayerController object for playback on the device or via AirPlay.
The app supports background operation and has the 'audio' option listed within the required UIBackgroundModes key in its plist file.
When playing over AirPlay, the app can successfully be pushed to the background and the video continues to play properly. So far, so good.
According to the Apple documentation:
Including the audio key tells the system frameworks that they should
continue playing and make the necessary callbacks to the app at
appropriate intervals. If the app does not include this key, any audio
being played by the app stops when the app moves to the background.
However, these callbacks are not being made.
The app uses two types of callback: those associated with notifications MPMoviePlayerController and AVPlayer send during playback together with timer based callbacks that monitor the playback position and performance stats for monitoring purposes.
Looking at Apple's notes, I would certainly expect to receive the first type of callback so that the app can respond to MPMoviePlayerPlaybackStateDidChangeNotification, MPMoviePlayerPlaybackDidFinishNotification and MPMoviePlayerLoadStateDidChangeNotification, but this doesn't happen.
Does anyone know if it is possible to receive these during background AirPlay playback and, if so, how was this achieved?
**Please note: the app works correctly when running in the foreground and receives the notifications fine. It is only when pushed to the background and playing over AirPlay that the notifications are not received.
Likewise, the video plays over AirPlay in the background properly. It is only the notifications which are not received**

I had this issue and have fixed it though it was a few months back. I could send you my entire class for movie playback if this doesn't work. Note it is using the navigation controller model.
NOTE: This is tested on iPad 2 not on the iPhone.
I show my VC like this:
- (IBAction)playMovie:(id)sender {
MovieVC* movController = [[MovieVC alloc] initWithID:2];
movController.view.backgroundColor = [UIColor blackColor];
AppDelegate *appDel = [[UIApplication sharedApplication] delegate];
[appDel.navigationController pushViewController:movController animated:NO];
[movController release];
}
Then in my MovieVC view controller class i set up the video playback like this:
- (void)initMoviePlayer {
mMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[self getMovieURL]];
mMoviePlayer.allowsAirPlay = YES;
mMoviePlayer.view.frame = [self.view bounds];
mMoviePlayer.view.backgroundColor = [UIColor clearColor];
mMoviePlayer.shouldAutoplay = YES;
mMoviePlayer.fullscreen = YES;
mMoviePlayer.scalingMode = MPMovieScalingModeAspectFit;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePreloadDidFinish:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:mMoviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
}
This fixed it for me, if it doesn't fix comment and ill edit with the entire class file.

In one of my projects I did what you did, and it worked for me.
Two differences in my project :
I am not streaming via airPlay (device playback only),
I am just playing audio files.
My step-by-step :
Add the audio option to UIBackgroundModes in the plist file,
Register to the NotificationCenter for MPMoviePlayerPlaybackDidFinishNotification and MPMoviePlayerPlaybackStateDidChangeNotification with the following code :
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(playbackStateChanged:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:moviePlayer];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(playbackEnded:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
It works like a charm.

For completeness, I ought to add that at present I believe there is no solution to this problem.
I've discussed it directly with Apple via tech support and there was no practical work-around available.
This functionality was needed to allow the app to record stats about the playback of the stream at regular intervals. While this is fine when the video is played on the device's screen and over AirPlay while the app is in the foreground, it isn't possible to do with the app in the background.
The solution I've gone with instead is to disable the idle timer during all types of playback and to re-enable afterwards using:
[UIApplication sharedApplication].idleTimerDisabled = YES;
and
[UIApplication sharedApplication].idleTimerDisabled = NO;
While this isn't a solution to the original question, it's a workaround for avoiding the issue in the first place.

Related

MPMoviePlayerViewController can not play mp4 file

I'm working on a test application that will run an mp4 file from internet.
code is :
-(IBAction)playRemoteVideo
{
NSString *mp4File = #"http://archive.org/download/Pbtestfilemp4videotestmp4/video_test_512kb.mp4";
MPMoviePlayerViewController *playerController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:mp4File]];
[self presentMoviePlayerViewControllerAnimated:playerController];
playerController.moviePlayer.movieSourceType=MPMovieSourceTypeStreaming;
[playerController.moviePlayer play];
[playerController release];
playerController=nil;
}
When I run the application and played the video the player tries to load the video for a while but after I got this exception on console
2012-04-18 22:45:11.309 VideoPlayer[891:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An AVPlayerItem can occupy only one position in a player's queue at a time.'
*** First throw call stack:
(0x1df1052 0x1333d0a 0x27cfb31 0x27cbb2a 0x27e45cc 0x103b73 0xd4e6a 0x2ff2445 0x2ff44f0 0x1d28833 0x1d27db4 0x1d27ccb 0x16d8879 0x16d893e 0x24ea9b 0x1d12 0x1c85)
terminate called throwing an exception(gdb)
If I execute the same code with an m3u8 file , for instance;
http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8
I can get the video running but same does not work for mp4 file.
Do you have any idea why I got this exception and what's wrong with my code?
I run the application on Iphone simulator and I have XCode 4.2
Best Regards
Tugrul
Set the movie player's control style like so.
[self.mPlayer.moviePlayer setControlStyle:MPMovieControlStyleDefault];
Also, local files have the MPMovieSourceTypeFile, not MPMovieSourceTypeStreaming property set.
One more scenario where this can happen is, as the log quite helpfully tells you, when "An AVPlayerItem can occupy only one position in a player's queue at a time." Basically, when you're trying to get two videos to start playing at the same time, or even INTERACT with two videos/MPMoviePlayerController objects at the same time.
In my app I use two MPMoviePlayerController's and keep swapping them around to create the illusion for the user of infinitely moving and swapping between different videos.
This was working fine so far, but I recently added notifications for some events that should result in the videos being paused and resumed. However I didn't realize both my player objects were listening to the notifications at the same time, and hence tried to trigger either "Pause" or "Play" at the same time. This caused the framework to think I was trying to play multiple videos at the same time, and threw this exception.
All I had to do now was make sure that only one player object was listening to notifications at any given point. Just a small tweak in my application logic.
So if you're getting a weird error, it need not be the framework that has a problem, a malicious operating system bent on making your life hell or an act of god. It could just be pure, good old-fashioned bad code. :)
I know this error. Try this code here.
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL: url];
self.movieController = player;
self.movieController.fullscreen = YES;
self.movieController.controlStyle = MPMovieControlStyleDefault;
// Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.movieController];
// Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerDidExitFullscreenNotification
object:self.movieController];
[self.movieController prepareToPlay];
[self.movieController.view setFrame: self.view.bounds]; // player's frame must match parent's
[self.view addSubview: self.movieController.view];
// ...
[self.movieController play];

MPMoviePlayerController not firing notifications in iPhone 5 Simulator

I ran into a problem... perhaps someone bumped into something similar: I have an application that uses a MPMoviePlayerController, and used to work perfectly well.
Trying to compile and run it with new Xcode 4.2 using iPhone 5 Simulator, MPMoviePlayerController is not sending notifications when I load a movie. Looks like it fails to properly detect the video file.
The code looks more or less like that (simplified code):
// First I'm initializing the player with a URL from a file
MPMoviePlayerController *player;
player = [[MPMoviePlayerController alloc] init];
player.shouldAutoplay = NO;
NSURL *url = [NSURL fileURLWithPath:path];
player.contentURL = url;
// Then I'm adding an observer in order to wait for the player to find movie duration
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(durationAvailable:)
After the above, I'm waiting in a loop for the notification to get called, by waiting for about 10 seconds, during which I'm calling the run loop.
Using the same code, same Xcode 4.2 version, but with iPhone 4.3 Simulator, after about a second the notification gets called, and I can read the player duration. However, when running the exact same code on iPhone 5 Simulator, the notification function never gets called, and if I try to read the movie duration afterwards it contains 0.
Any idea?
Thanks,
Ariel
OK, I managed to find a workaround to the problem.
Apparently, adding this line after adding the observer does the trick:
[player pause];
It looks like if you don't "activate" the player somehow, the notifications will not be fired. In my case, I just wanted to get a notification for the duration of the movie without starting a playback, and it worked well in versions prior to iOS5, but it looks like they changed the behavior. Anyway, the above line solves the problem.
Ariel
try this MPMoviePlayerPlaybackStateDidChangeNotification :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(stop)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:nil];

play two video in iPhone simultaneously

I want to play two video in iPhone simultaneously.
There are two way to play video in iphone, One is use AVQueuePlayer. but in this controller I don't get how get the video playing is completed and how to restart video again.
Another way is MPMoviePlayerController . but in this controller I don't get how to seek video at particular time and also it is not able to play two video simultaneously as the AVQueuePlayer is able to play.
as a solution i am using AVQueuePlayer to play video and but can any one help me to restart video and get method to detect end point of the video. or know any other api to so this
Thanks in advance.
I have found the solution to play two video . You can use AVQueuePlayer to play video. Using this controller you can play two video at the same time .
I wonder if this is even possible. Video playback on the iPhone is ensured thanks to a hardware video decoder. And I really think the hardware decoder can only handle one video stream at a time.
Ecco is correct. You're limited to one video at a time due to hardware restrictions.
However, if you're after 7KV7's suggestion of one video ending and triggering the playback of another, you can make use of the MPMoviePlayerPlaybackDidFinishNotification notification in the following way:
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(firstMoviePlayerDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
}
- (void)moviePlayerDidFinish:(NSNotification *)notification {
if (firstMovie) {
[moviePlayerController setContentURL:nextMovieURL];
[moviePlayerController play];
} else {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
Also, note that you can find the current playback point in a MPMoviePlayerController instance by examining the currentPlaybackTime property.

MPMoviePlayerViewController stops playback when unplugging headphones

I'm currently developing a web-tv application that uses MPMoviePlayerViewController resp. MPMoviePlayer to playback streaming video content on the iphone.
the issue I've got here is that once i unplug my headphones (while watching tv) the player stops.
Due to the fact that I'm not showing the standard controls (previous button, play/pause button, next button) but my custom controlls, the user is stuck with the frozen picture unless he switches to a new channel..
is there any way to detect a playback interuption caused by unplugging the headphones?
thanks for your tipps and tricks in advance,
sam
I don't have a direct answer to your question. But I think MPMoviePlayerPlaybackStateDidChangeNotification will be good enough to solve your issue. Once you are notified, Get the playback state from the playbackState property of the movie player object and take appropriate action.
Elaborating on the accepted answer with some code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoPlaybackStateChanged:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:moviePlayer];
- (void)videoPlaybackStateChanged :(NSNotification *)notification
{
if (moviePlayer != nil && [moviePlayer playbackState] == MPMoviePlaybackStatePaused)
{
[moviePlayer play];
}
}

writing an iPhone application with embedded video

I am researching video streaming for an iPhone application that I may have to write in the near future. The application does a whole lot other than stream video, but video aspect is the part that I have no experience with.
Anyone know of any good articles on writing streaming video apps?
Google seems to inundate me with links that have everything not to do what I seek.
Thanks,
m
Apple provide good documentation on the media framework i ntheir docs.
Search for MPMoviePlayerController. The following sample code plays a movie from a URL. (disclaimer, this code lifted from Apple).
-(void)playMovieAtURL:(NSURL*)theURL
{
MPMoviePlayerController* theMovie=[[MPMoviePlayerController alloc] initWithContentURL:theURL];
theMovie.scalingMode=MPMovieScalingModeAspectFill;
theMovie.userCanShowTransportControls=NO;
// Register for the playback finished notification.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
// Movie playback is asynchronous, so this method returns immediately.
[theMovie play];
}
// When the movie is done,release the controller.
-(void)myMovieFinishedCallback:(NSNotification*)aNotification
{
MPMoviePlayerController* theMovie=[aNotification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
// Release the movie instance created in playMovieAtURL
[theMovie release];
}
I am looking at this issue as well. I would like to embed a video in an iPad app, something like how the Associated Press iPad application handles videos.
Apparently you can do this type of embedded video in OS 3.2 and later. Apple's documentation for MPMoviePlayerController describes how this can be done:
http://developer.apple.com/iphone/library/documentation/MediaPlayer/Reference/MPMoviePlayerController_Class/MPMoviePlayerController/MPMoviePlayerController.html