我遇到了AVAudioPlayer类的奇怪问题,有时未调用audioPlayerDidFinishPlaying:successfully:回调。开始播放的精简代码看起来像这样,

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];

有一个计时器,每16毫秒运行一次,以显示播放进度。每当音频播放结束并且调用audioPlayerDidFinishPlaying:successfully:回调时,计时器将失效。回调代码是,
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    [self.progressTimer invalidate];
    self.progressTimer = nil;
}

但是,偶尔(一次播放20-30次)此回调不会被调用。我添加了断点并记录了调用,以验证未调用此回调方法。

要播放的numberOfLoops设置为0,因此不再重复。

如果有帮助,这里还有一些其他信息。正在创建的重复计时器将使用当前播放进度更新UI。它的代码看起来像
- (void)updatePlaybackProgress {
    SoundCell *soundCell = [self soundCellForCurrentlyPlayingSound];

    NSTimeInterval progress = player.currentTime / player.duration;
    if (progress >= 0) {
        soundCell.progress = progress;
    }
}

有时不会调用完成回调,因此计时器不会无效,并且每16毫秒调用一次。我在player.currentTime方法中记录了progressupdatePlaybackProgress的值,看来回放一遍又一遍。 currentTime的值从0.01.0不断增加,然后又回到0.0并重新开始。但是,音频只会在第一次播放,而不会按照currentTime的值连续播放。

对于持续时间为1秒到30秒以上的声音,此问题已经发生。

目前我还没有主意,Google和Apple开发者论坛没有任何关联。

最佳答案

  • 您的计时器不能保证在您指定的时间触发。如果您试图构建一个播放器进度指示器,我建议您使用CADisplayLink为您提供类似nstimer的功能,而不会增加开销(它会根据屏幕刷新来触发)。
  • 我将实现与播放相关的所有AVAudioPlayerDelegate协议(protocol)方法。

    响应声音播放完成
    – audioPlayerDidFinishPlaying:成功:
    响应音频解码错误
    – audioPlayerDecodeErrorDidOccur:错误:
    处理音频中断
    – audioPlayerBeginInterruption:
    – audioPlayerEndInterruption:
    – audioPlayerEndInterruption:withFlags:

    播放停止时,很可能会调用其中之一。您还可以注册NSNotifications进行音频播放,在实现方法中,您只需要将音频播放器与本地播放器进行比较,就可以知道您对此感兴趣。

  • 10-07 19:49
    查看更多