Playing AVAudioPlayer causes delay - ios

I use AVAudioPlayer object to play an aif sound file that should go on unless the game is over. I have an ivar of AVAudioPlayer called backgroundPlayer and I set it up in viewDidLoad method:
-(void)viewDidLoad{
NSURL *backgroundURL=[NSURL fileURLWithPath:[[NSBundle
mainBundle]pathForResource:#"bgLoop" ofType:#"aif"]];
backgroundPlayer=[[[AVAudioPlayer alloc] initWithContentsOfURL:backgroundURL
error:nil] retain];
backgroundAudioPlayer.numberOfLoops=-1;
}
And then I play it in viewWillAppear method:
-(void)viewWillAppear:(BOOL)animated{
TrafficAppDelegate *delegate=[UIApplication sharedApplication].delegate;
if (delegate.shouldPlaySFX)
[backgroundPlayer play];
}
With this all set when I push my button to push the view controller to the stack I hangs for about 2-3 seconds and only after that the view appears. If I comment the [backgroundPlayer play] command in viewWillAppear method the delay goes away. Shouldn't I use AVAudioPlayer class for playing this kind of sounds? I mean the sound can go on for minutes, even hours.If the choose is not the issue then what can cause the delay? Thanks in advance

Have you tried this case after adding [backgroundPlayer prepareToPlay] in your code? I believe this will solve the delay issue.

It happens the first time you try to play a sound. You can play short silent sound in your appdelegate to make the AVAudioPlayer responsive when you really need it.

Related

Why doesn't AVPlayer stop loading data?

When I watch my mac's network connectivity I can tell that a movie is still buffering even after I remove the view which had the AVPlayer on it.
Does anyone know how to force AVPlayer to stop loading data?
Maybe it's late to answer this question, but I've just solved the same one.
Just save here in case anyone need...
[self.player.currentItem cancelPendingSeeks];
[self.player.currentItem.asset cancelLoading];
There's no cancel method in AVPlayer class, but in AVPlayerItem and AVAsset class, there are!
PS: player here is AVPlayer class, not AVQueuePlayer class.
An AVPlayer is not a view. You may have "removed the view" but that does not mean you have removed or stopped the AVPlayer. I would guess that the way to do what you want is to destroy the AVPlayer itself.
I figured it out.
When you want to stop an AVPlayerItem from loading, use AVQueuePlayer's removeAllItems and then re-initialize it.
[self.avPlayer removeAllItems];
self.avPlayer = [AVQueuePlayer playerWithURL:[NSURL URLWithString:#""]];
self.avPlayer = nil;
This will stop the current item from loading -- it is the only way I found to accomplish this.

iOS: play audio file at a specific time and stop after a specific duration

I have an audio file with length of 500 miniseconds for my app. I want app users to play the audio at minisecond 100 (by pressing a button) and the audio will automatically stops at minisecond 150. This is a code that I have done so far:
AVAudioPlayer *audioPlayer = [[[AVAudioPlayer alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:filePath]
error:nil] autorelease];
[audioPlayer setCurrentTime:100.00f];
[audioPlayer play];
Would you please help me with the stopping part? Thank you
You could create an instance of NSTimer with the desired play interval, then when the timer fires, stop audio. Create the timer on the main thread, and in a place in your code in an applicable area where you can get a reference for the audioPlayer. Make sure you handle interruptions, IE, User pauses or stops audio somehow, or if the audioPlayer is deallocated somewhere, your app goes into the background, or whatever else you need to handle, by invalidating and disposing of the timer. See the docs for information on NSTimer. http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html

AVAudioPlayer Loses "Playing" Status

I have an AVAudioPlayer that needs to continue in the background.
Audio is set as the background mode in the plist & this runs on launch:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[[RootController shared].view becomeFirstResponder];
AVAudioSession* session = [AVAudioSession sharedInstance];
[session setDelegate: self];
[session setActive:YES error:nil];
[session setCategory: AVAudioSessionCategoryPlayback error:nil];
- (BOOL)canBecomeFirstResponder { return YES; }
The Problem
Occasionally the AVAudioPlayer gets in this strange state where:
It's playing, but the play icon in the status bar disappears
If I pause then play, the icon shows up for maybe a second, then disappears
Here's the kicker - if I call setCurrentTime while playing, the play icon shows & stays
I've sunk about 20 hours into this & would love any ideas.
Description of the Bug
If you are playing an AVAudioPlayer then you create an AVPlayer, the playing icon will disappear. Apparently AVPlayer immediately takes precedence & since it is not playing yet the play icon disappears from the status bar.
This causes some serious issues:
If the app is in the background, iOS will shut down your AVAudioPlayer within 5 seconds (because it doesn't realize you're playing audio)
The iOS remote shows a play button even though audio is playing
The play icon is not showing in the status bar
The Workaround
First off, if you don't have to use AVPlayer, then don't. I use it because I need to play a remote MP3 without downloading it first. I used to use this AudioStreamer class but gave up because it pops up an alert when the stream becomes disconnected along with a few other bugs that I couldn't fix.
So if you're stuck with AVPlayer, there's only one way to re-connect playing status with your AVAudioPlayer. If you call setCurrentTime on the AVAudioPlayer then it will magically re-associate itself as the current player for the app. So you'll need to call it after any AVPlayer is initialized and anytime you resume playback on your AVAudioPlayer.
I decided to subclass AVAudioPlayer so I could register it in a global list (when it is initialized) and unregister it when it is deallocated. I also overrode the play method so that any calls to resume playback would also call setCurrentTime. Then I subclassed AVPlayer so that any time one is initialized, all active AVAudioPlayers call setCurrentTime on themselves. Last thing - you'll have to call setCurrentTime after a short, maybe 1 second, delay or else it will have no effect.
No kidding, this is the result of nearly 40 hours of troubleshooting.

MPMoviePlayerController: Removing ±1sec black screen, when changing contentURL?

I'm working on an iPad project where i have to play short video files one after another smoothly. For playing the videos i'm using MPMoviePlayerController. The problem i'm facing is that when i call
[self.moviePlayer setContentURL:videoURL]
it does start the next video, but there is ±1 sec delay of black screen before it starts to play the next video (the videos are read from the disk, not streamed). I need to avoid this black screen as well as the delay.
So maybe some of you also experienced this problem and have some solutions? Thanks.
Btw, for now, as to at least avoid the black screen, I capture the last frame of the ending video, show it in a UIImageView, and remove it after 1 sec delay. But i'm hoping to find a more elegant fix.
The effect you are talking about is actually a combination of two problems: a black blink when you change the video (which doesn't happen upon assigning the video for the first time) and the delay before the controller starts playing video.
I'm currently screwed with the second one and don't know how to solve yet. As for the first one, just try to use another instance of MPMoviePlayerController. I mean when a video finishes playing (you can subscribe to a corresponding notification) just remove the old player, create a new one and put video there. This way you will avoid blinking, but there will be a delay (not sure, because of loading the video or because of player creation) before the next video starts playing.
Hope this helps a bit.
Fond solution here
http://joris.kluivers.nl/blog/2010/01/04/mpmovieplayercontroller-handle-with-care/
you need to use [self.moviePlayer prepareToPlay]; and catch MPMoviePlayerReadyForDisplayDidChangeNotification to use [self.moviePlayer play];
Old post but Googlers will still come. :)
Creating a new MPMoviePlayerController then assigning it back to my previous player worked for me, no more black screen!
...
[self playVideoWithFilename:#"video1.mp4"];
}
- (void)playVideoWithFilename:(NSString *)fileName
{
MPMoviePlayerController *player = [MPMoviePlayerController new];
_myVidPlayer = player;
player = nil;
NSURL *vidPath = [[NSBundle mainBundle] URLForResource:fileName withExtension:nil];
[_myVidPlayer.view setBackgroundColor:[UIColor whiteColor]];
[_myVidPlayer.view setFrame:CGRectMake(0, 64, 320, 320)];
[_myVidPlayer setContentURL:vidPath];
[_myVidPlayer setControlStyle:MPMovieControlStyleNone];
[_myVidPlayer setRepeatMode:MPMovieRepeatModeOne];
[_myVidPlayer prepareToPlay];
[self.view addSubview: _myVidPlayer.view];
[_myVidPlayer play];
}
Note:
Available in iOS 2.0 and later
Deprecated in iOS 9.0
"Use AVPlayerViewController in AVKit."
I think that the problem is that the controller will fade out and back in between the movies.
You can control the background view color and contents, but I'm not sure that you can eliminate the fade in/out.

Tell video loaded in MPMoviePlayerViewController to stop playing

I've got a navigation view with a table view in it, listing some videos. When a row is selected, it loads MPMoviePlayerViewController and inits it with a video from file URL. When I go back to the table view, the movie is still playing. I tried getting the underlying MPMoviePlayerController and giving it a "pause" message in the viewDidDisappear method, but this doesn't seem to ever get called (NSLog statement in method never appears). So I'm sure there's a simple way to tell MPMoviePlayerController via MPMoviePlayerViewController to stop playing it's movie programmatically, right?
Simply needed to subclass MPMoviePlayerViewController, load the subclass from the table/navigation on selection, then add this to that subclass:
-(void)viewWillDisappear:(BOOL)animated {
[self.moviePlayer stop];
}
You need to register for some notifications. See the 'Notifications' section of the MPMoviePlayerController class reference:
http://developer.apple.com/library/ios/#documentation/MediaPlayer/Reference/MPMoviePlayerController_Class/MPMoviePlayerController/MPMoviePlayerController.html
In particular, register to receive MPMoviePlayerDidExitFullscreenNotification and MPMoviePlayerPlaybackDidFinishNotification and in your method that is called when these notifications are sent, stop the movie from playing by sending the 'stop' message.
But what about when you want to stop downloading the video before it is finished playing. For example, when you go to a different screen.
For me, i try to stop the video when the videoWillDisappear method gets called. Yet, the video still downloads even when the current video is gone!

Resources