I am facing a weird issue with the AVAudioPlayer class with the audioPlayerDidFinishPlaying:successfully: callback not being called sometimes. A stripped down version of the code that starts the playback looks like,
self.player = [[[AVAudioPlayer alloc] initWithContentsOfURL:localFileAudioURL error:&error] autorelease];
self.player.delegate = self;
[player prepareToPlay];
[NSTimer scheduledTimerWithTimeInterval:0.016f target:self selector:@selector(updatePlaybackProgress) userInfo:nil repeats:YES];
[player play];
There is a timer that runs every 16 ms to show the playback progress. Whenever the audio playback finishes, and the audioPlayerDidFinishPlaying:successfully: callback is called, the timer will be invalidated. The callback code is,
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
[self.progressTimer invalidate];
self.progressTimer = nil;
}
However, occasionally (once in 20-30 playbacks) this callback is not called. I've added breakpoints and logging calls to verify that this callback method was not called.
The numberOfLoops for playback is set to 0 so it does not repeat.
Here's some additional information if it helps. The repeating timer that is being created updates the UI with the current playback progress. Its code looks like,
- (void)updatePlaybackProgress {
SoundCell *soundCell = [self soundCellForCurrentlyPlayingSound];
NSTimeInterval progress = player.currentTime / player.duration;
if (progress >= 0) {
soundCell.progress = progress;
}
}
The completion callback is not called sometimes, so the timer is not invalidated and is called after every 16 ms. I logged the values of player.currentTime, and progress inside the updatePlaybackProgress method, and it seems the playback is looping over and over. The value of currentTime keeps increasing from 0.0 to 1.0, then back to 0.0 and starts over. The audio, however, is only played the very first time, and not continuously as the value of currentTime suggests.
This problem has happened for sounds with a duration of 1 second to over 30 seconds.
I am out of ideas at this point, and Google and the Apple Developer Forums don't have anything related.
your timer is not guaranteed to fire at the time you specify. If you are trying to build a player progress indicator i suggest using a CADisplayLink to give you nstimer like functionality without the overhead(its fired based off screen refresh).
i would implement ALL of the AVAudioPlayerDelegate Protocol methods associated with playback..
Responding to Sound Playback Completion – audioPlayerDidFinishPlaying:successfully: Responding to an Audio Decoding Error – audioPlayerDecodeErrorDidOccur:error: Handling Audio Interruptions – audioPlayerBeginInterruption: – audioPlayerEndInterruption: – audioPlayerEndInterruption:withFlags:
Most likely one of them is called when playback stops. You can also register for NSNotifications for audio playback, and in the method you implement you'd just need to compare the audioplayer with your local player to know this was something youd be interested in.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With