Recover from buffering stopping MPMoviePlayer - ios

I am not sure what code to add, so let me know what you need to see. I am using MPMoviePlayer in conjunction with Widevine. I am having an issue where the movie stops playing. I check the MoviePlaybackStates and rarely, if ever does it catch. Most of the time it just stops. I want to believe it has something to do with buffering. I am streaming the video, and widevine callbacks gives me no errors. Any ideas how I can track this down or what the issue is?

You should follow loadState instead of playbackState.
The way to do it is to observe MPMoviePlayerLoadStateDidChangeNotification notification, to see how's that buffering going.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(loadStateChanged:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
somewhere before initializing your player.
and
-(void)loadStateChanged:(NSNotification *)notif
{
NSString *loadState=#"";
switch (self.player.loadState) {
case MPMovieLoadStateUnknown: {
loadState=#"MPMovieLoadStateUnknown";
break;
}
case MPMovieLoadStatePlayable: {
loadState=#"MPMovieLoadStatePlayable";
break;
}
case MPMovieLoadStatePlaythroughOK: {
loadState=#"MPMovieLoadStatePlaythroughOK";
break;
}
case MPMovieLoadStateStalled: {
loadState=#"MPMovieLoadStateStalled";
break;
}
}
NSLog(#"%#", loadState);
}

Related

Youtube embeded video callbacks in webview + iOS [duplicate]

I’m embedding YouTube videos in a UIWebView for an iOS app. I’m using “Method 2” at this YouTube blog post to embed the video. This works great, except that because iOS manages the media player, I can’t determine whether the video is playing or is done. I don’t want to swap that view out with another one while the video is playing, but I don’t see a good way to determine that. Any ideas? If there’s a way to get a JavaScript callback, that will work, or if there’s a way to embed YouTube videos using the HTML5 <video> tag, that will work as well (I’ve tried that and not gotten success).
Just add observer for MPAVControllerPlaybackStateChangedNotification.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playbackStateDidChange:)
name:#"MPAVControllerPlaybackStateChangedNotification"
object:nil];
then start listening:
- (void)playbackStateDidChange:(NSNotification *)note
{
NSLog(#"note.name=%# state=%d", note.name, [[note.userInfo objectForKey:#"MPAVControllerNewStateParameter"] intValue]);
int playbackState = [[note.userInfo objectForKey:#"MPAVControllerNewStateParameter"] intValue];
switch (playbackState) {
case 1: //end
;
break;
case 2: //start
;
break;
default:
break;
}
}
Explore other states if you're curious. Additionally everyone interested in bunch of other notifications can register to see all:
CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(),
NULL,
noteCallbackFunction,
NULL,
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
then check what's coming on:
void noteCallbackFunction (CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo)
{
NSLog(#"notification name: %#", name);
NSLog(#"notification info: %#", userInfo);
}
Have fun!
you can inject javascript into a UIWebView (see http://iphoneincubator.com/blog/windows-views/how-to-inject-javascript-functions-into-a-uiwebview)... other interesting stuff about javascript and UIWebView can be found here and here.
try using this together with this experimental youtube API (see http://code.google.com/apis/youtube/iframe_api_reference.html)... this should be able to get you what you want.
Another useful resource for this to make a callback from javascript to your code is here.
For iPhone I used some tricky method. You could get a notification when video modal view controller was dismissed.
-(void) onUIWebViewButtonTouch:(id) sender
{
self.isWatchForNotifications = YES;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(windowNowVisible:)
name:UIWindowDidBecomeVisibleNotification
object:self.view.window
];
}
- (void)windowNowVisible:(NSNotification *)note
{
if (isWatchForNotifications == YES)
{
//modal viewcontroller was dismissed
}
self.isWatchForNotifications = NO;
}

iOS get notified when microphone can be accessed

I would like my app to be notified when microphone interruption has ended before i start recording.
say for example my application is trying to start recording from background and during this time if any other applications like skype is accessing microphone and i shouldn't do. so i want to start register/observe for interruption so that when skype call ended, my app should be notified.
I can able to achieve only when app is recording and interruption began . i will be notified when interruption ended not on while about to start recording .
please help .
I tried to register using
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleAudioSessionInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
// observe the interruption begin / end
- (void)handleAudioSessionInterruption:(NSNotification*)notification
{
AVAudioSessionInterruptionType interruptionType = [notification.userInfo[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
AVAudioSessionInterruptionOptions interruptionOption = [notification.userInfo[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
NSLog(#"interruptionType:%lu",(unsigned long)interruptionType);
switch (interruptionType) {
case AVAudioSessionInterruptionTypeBegan:{
NSLog(#"interruption began");
break;
}
case AVAudioSessionInterruptionTypeEnded:{
NSLog(#"interruption ended");
break;
}
default:
break;
}
}

Application stops when I hit the "Done" button

So, when I hit the "Done" button, whenever I am in the Movie Player, my app goes back to the previous menu, while a loading sign is in the middle of the screen. Then my app stops completely, without any error messages.
Here's my code:
_streamPlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
if(self.streamPlayer != nil){
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_streamPlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doneButtonClick:)
name:MPMoviePlayerDidExitFullscreenNotification
object:_streamPlayer];
EDIT: I implemented the 2 functions like this:
-(void) moviePlayBackDidFinish:(NSNotification*)notification {
NSNumber *reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason intValue]) {
case MPMovieFinishReasonPlaybackEnded:
NSLog(#"Playback ended");
break;
case MPMovieFinishReasonPlaybackError:
[self alertWithMessage:NSLocalizedString(#"The video can't open!", #"The video can't open!")];
break;
case MPMovieFinishReasonUserExited:
NSLog(#"User Exited");
break;
default:
break;
}
}
-(IBAction) doneButtonClicked:(id)sender
{
[self.streamPlayer.view removeFromSuperview];
self.streamPlayer = nil;
}
I'm not sure about the second one! Still the same problem!
Any ideas?
Your code to add a notification center observer references a method named doneButtonClick:. However, the method you implemented is named doneButtonClicked: (note the 'ed' at the end!). As such, you'll get a crash when the notification comes in because the method you specified doesn't exit. You need to either:
Change the addObserver call to reference the actual method: #selector(doneButtonClicked:) or
Rename your method to match the addObserver call: - (IBAction)doneButtonClick:(id)sender
Incidentally, I'd rename the method and #selector reference to doneButtonTapped - users tap on a touch device, they don't 'click'.
I solved it!
I commented the second method (doneButtonClick:) and it's implementation and then, when the video player should stop playing, i added this:
[_streamPlayer stop];
[_streamPlayer.view removeFromSuperview];
[self dismissLoadingView];
[SVProgressHUD dismiss];

iOS 7 MPMoviePlayerController seek forward button brings the video to the End and displays Black screen

I am facing an issue with MPMoviePlayerController in iOS 7. I enter the fullscreen and then click (just a single tap) on seek forward button (>>|) , and the video playback ends and gives a black screen with a text "Loading" on the header.
I registered notification for "MPMoviePlayerPlaybackStateDidChangeNotification".
**[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackStateDidChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.player];**
It does not get fired on a single click of seek forward button.
Also on registration of "MPMoviePlayerPlaybackDidFinishNotification"
**[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];**
I get "MPMovieFinishReasonPlaybackEnded" event fired on that single click of seek forward button.
Any one knows the reason why? Is this a bug in apple?
I need to either stop this behavior of showing a black screen on single click , or just disable single click of seek forward button so that nothing happens.
Any one knows how to achieve this?
I fixed this by removing the MPMoviePlayer object completely, setting it to nil, removing it from it's superview and re-adding it using the original video Url. Code below:
- (void)addPlayerForUrl:(NSURL *)url {
self.player = [[MPMoviePlayerController alloc] initWithContentURL:url];
self.player.view.frame = self.videoView.bounds;
self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.player.controlStyle = MPMovieControlStyleDefault;
[self.videoView insertSubview:self.player.view atIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateDidChangedNotification:)
name:MPMoviePlayerReadyForDisplayDidChangeNotification
object:self.player];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackStateDidChangeNotification:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.player];
}
#pragma mark - Notifications
- (void)moviePlayerLoadStateDidChangedNotification:(NSNotification *)notification {
self.isVideoPreloaded = YES;
self.videoPlayButton.hidden = YES;
self.photoImageView.hidden = YES;
self.videoLoadingImageView.hidden = YES;
}
- (void)moviePlayerPlaybackStateDidChangeNotification:(NSNotification *)notification {
NSURL *url = self.player.contentURL;
switch (self.player.playbackState) {
case MPMoviePlaybackStateSeekingBackward:
case MPMoviePlaybackStateSeekingForward:
break;
case MPMoviePlaybackStatePlaying:
self.videoPlayButton.hidden = YES;
if (!self.isVideoPreloaded) {
self.videoLoadingImageView.hidden = NO;
[self.videoLoadingImageView startAnimating];
} else {
self.videoLoadingImageView.hidden = YES;
}
break;
case MPMoviePlaybackStatePaused:
case MPMoviePlaybackStateStopped:
self.videoPlayButton.hidden = NO;
self.videoLoadingImageView.hidden = YES;
[self.player endSeeking];
[self.player.view removeFromSuperview];
[self.player setFullscreen:NO];
self.player = nil;
[self addPlayerForUrl:url];
break;
default:
break;
}
}
Notice how I keep the NSURL, right before the switch statement in the moviePlayerPlaybackStateDidChangeNotification. That way, I can re-initialize and re-add the MPMoviePlayer object.
Btw, my mpmovieplayer is on a tableviewCell if you're wondering. Hope this helps and let me know if you have questions. Good luck!
MPMoviePlayerLoadStateDidChangeNotification will be called when you single tap on the fast-forward or rewind button. You should check the loadState and just give it the path to your video and prepareToPlay again.
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification {
MPMoviePlayerController *moviePlayer = notification.object;
MPMovieLoadState loadState = moviePlayer.loadState;
if(loadState == MPMovieLoadStateUnknown) {
moviePlayer.contentURL = [NSURL fileURLWithPath:videoPath]
[moviePlayer prepareToPlay];
}
.....
}
The reason you're getting MPMovieFinishReasonPlaybackEnded is because playback reached the end of the video (sorry if this is obvious). So it seem's your seek forward actions are seeking all the way to the end of the video. You can check the playback state with MPMoviePlaybackStateSeekingForward.
A quick solution could be to create your own forward button that seek's ahead by a specified time (ie. 5 seconds). But perhaps this isn't the functionality you're looking for.

Media Callbacks with Embedded YouTube Videos on iOS

I’m embedding YouTube videos in a UIWebView for an iOS app. I’m using “Method 2” at this YouTube blog post to embed the video. This works great, except that because iOS manages the media player, I can’t determine whether the video is playing or is done. I don’t want to swap that view out with another one while the video is playing, but I don’t see a good way to determine that. Any ideas? If there’s a way to get a JavaScript callback, that will work, or if there’s a way to embed YouTube videos using the HTML5 <video> tag, that will work as well (I’ve tried that and not gotten success).
Just add observer for MPAVControllerPlaybackStateChangedNotification.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playbackStateDidChange:)
name:#"MPAVControllerPlaybackStateChangedNotification"
object:nil];
then start listening:
- (void)playbackStateDidChange:(NSNotification *)note
{
NSLog(#"note.name=%# state=%d", note.name, [[note.userInfo objectForKey:#"MPAVControllerNewStateParameter"] intValue]);
int playbackState = [[note.userInfo objectForKey:#"MPAVControllerNewStateParameter"] intValue];
switch (playbackState) {
case 1: //end
;
break;
case 2: //start
;
break;
default:
break;
}
}
Explore other states if you're curious. Additionally everyone interested in bunch of other notifications can register to see all:
CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(),
NULL,
noteCallbackFunction,
NULL,
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
then check what's coming on:
void noteCallbackFunction (CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo)
{
NSLog(#"notification name: %#", name);
NSLog(#"notification info: %#", userInfo);
}
Have fun!
you can inject javascript into a UIWebView (see http://iphoneincubator.com/blog/windows-views/how-to-inject-javascript-functions-into-a-uiwebview)... other interesting stuff about javascript and UIWebView can be found here and here.
try using this together with this experimental youtube API (see http://code.google.com/apis/youtube/iframe_api_reference.html)... this should be able to get you what you want.
Another useful resource for this to make a callback from javascript to your code is here.
For iPhone I used some tricky method. You could get a notification when video modal view controller was dismissed.
-(void) onUIWebViewButtonTouch:(id) sender
{
self.isWatchForNotifications = YES;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(windowNowVisible:)
name:UIWindowDidBecomeVisibleNotification
object:self.view.window
];
}
- (void)windowNowVisible:(NSNotification *)note
{
if (isWatchForNotifications == YES)
{
//modal viewcontroller was dismissed
}
self.isWatchForNotifications = NO;
}

Resources