3.15ios平台的AudioEngine疑问

版本3.15,不知道以前的版本是不是也这样,AudioEngine-inl.mm里面,我看到AudioEngine在处理系统notification的时候,竟然调用了Director类的resume,pause方法,这个是不是有问题,一个音效类不应该有权限操作Director的生命周期啊,还是我的理解有问题?有没有引擎组的大大科普下。@minggo

@dumganhar 能否解释一下?

AudioEngine内部通过监听AVAudioSessionInterruptionNotification, UIApplicationDidBecomeActiveNotification, UIApplicationWillResignActiveNotification 事件,实现自动暂停、恢复音效播放的功能。
加入Director的pause,resume是为了解决
https://github.com/cocos2d/cocos2d-x/issues/17395
对应的PR:
https://github.com/cocos2d/cocos2d-x/pull/17492

加入director的pause resume是为了解决在不同的ios系统版本上,事件回调顺序不一致的问题:
AVAudioSessionInterruptionTypeBegan
AVAudioSessionInterruptionTypeEnded
UIApplicationWillResignActiveNotification
UIApplicationDidBecomeActiveNotification

当通过长按Home呼唤出Siri与关闭Siri的时候,如果执行顺序是:

  1. AVAudioSessionInterruptionTypeBegan -> 2. UIApplicationWillResignActiveNotification -> 3. UIApplicationDidBecomeActiveNotification -> 4. AVAudioSessionInterruptionTypeEnded

在第3步之前,游戏工程中的proj.ios/AppController.mm会触发

- (void)applicationDidBecomeActive:(UIApplication *)application {
    /*
     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
     */
    cocos2d::Director::getInstance()->resume();
}

进行Director的resume操作,mainloop会继续执行,而由于AVAudioSessionInterruptionTypeEnded事件可能延时一些时间到达,导致了此时间间隔内调用了OpenAL的函数,从而触发A003 的ERROR。触发此Error后就无法再次播放音频了。

所以如果是这样的事件回调顺序,AudioEngine-inl.mm内部通过检测isAudioSessionInterrupted这个变量,如果UIApplicationDidBecomeActiveNotification事件来了,但是isAudioSessionInterrupted还是true的状态,则继续pause住Director,防止OpenAL的代码被触发而引起错误。在AVAudioSessionInterruptionTypeEnded的时候在Resume director.