AVAudioPlayer audioPlayerDidFinishPlaying:successfully: 未调用

Posted

技术标签:

【中文标题】AVAudioPlayer audioPlayerDidFinishPlaying:successfully: 未调用【英文标题】:AVAudioPlayer audioPlayerDidFinishPlaying:successfully: not called 【发布时间】:2012-02-08 05:45:59 【问题描述】:

我遇到了一个关于 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毫秒调用一次。我在updatePlaybackProgress 方法中记录了player.currentTimeprogress 的值,似乎播放在循环播放。 currentTime 的值不断从0.0 增加到1.0,然后回到0.0 并重新开始。然而,音频只是第一次播放,而不是像currentTime 的值所暗示的那样连续播放。

对于持续时间为 1 秒到超过 30 秒的声音会出现此问题。

我现在没有想法,谷歌和苹果开发者论坛没有任何相关的东西。

【问题讨论】:

您找到解决方案了吗?我也面临同样的问题。 我听从了@drunknbass 的建议,使用CADisplayLink 而不是16ms 的计时器来更新显示。我还将频率设置得足够高,希望能解决问题。显示频率为 60hz(约 16ms),我将其设置为每 5 个刷新周期(约每 80ms)更新一次。这个问题没有那么频繁地发生,但不幸的是我仍然能够重现它。 但我的问题不同。我想在音频播放器播放完后做一些操作。我的整个逻辑取决于 didfinishplaying 回调函数。但有时它不会被解雇。我无法重现该问题。 @gladiator2345 - 您是否在播放音频时使用任何计时器来更新 UI 或其他内容? 没有。在我的情况下,我必须播放一个简短的声音,有时是多个文件,当它完成时我必须做其他事情。我将视图控制器作为我的音频处理类的委托,而它又注册为 avplayer 的委托。大多数情况下,当音频播放完毕时,我都会收到回调。但有时它会错过。我正在为 ipad3 制作这个应用程序。这是一个基于乐器的应用程序。 【参考方案1】:

    不保证您的计时器在您指定的时间触发。如果您正在尝试构建播放器进度指示器,我建议使用 CADisplayLink 为您提供类似 nstimer 的功能而无需开销(它基于屏幕刷新触发)。

    我将实现所有与播放相关的 AVAudioPlayerDelegate 协议方法。

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

播放停止时最有可能调用其中一个。您还可以注册 NSNotifications 以播放音频,并且在您实现的方法中,您只需将音频播放器与本地播放器进行比较即可知道这是您感兴趣的内容。

【讨论】:

感谢CADisplayLink。我没有意识到这一点。我已经实现了AVAudioPlayerDelegate 的所有 4 个委托方法,并且它们都没有基于日志调用被调用。我还没有尝试检查通知。计时器的高频是否会以某种方式阻止回调发生?据我所知,NSNotifications 已排队并没有被丢弃。现在试试看。 我尝试了大约 15 分钟来重现该问题,但还没有发生。行为非常不一致。 NSTimer 更新的频率是 16 毫秒还是 62.5 赫兹? 我使用的是CADisplayLink,但问题发生的频率远低于过去。实际上,自上个月以来,我只看过两次。但它仍然发生的事实令人困扰

以上是关于AVAudioPlayer audioPlayerDidFinishPlaying:successfully: 未调用的主要内容,如果未能解决你的问题,请参考以下文章

试图了解 AVAudioPlayer 和音频电平表

在其他 swift 文件中调用时,AVAudioPlayer 不会播放声音

检查是不是播放音乐[关闭]

查看avaudioplayer的当前播放时间

用 AVAudioPlayer 重放音乐多次?

使用AVAudioPlayer播放音乐文件无声音