cocos creater 鸿蒙 音频卡死 播放失败 不回调

Posted 丶党玲儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cocos creater 鸿蒙 音频卡死 播放失败 不回调相关的知识,希望对你有一定的参考价值。

cocos creater音频播放失败 || 不回调 || 卡死 || 鸿蒙

问题背景

  1. 开发过程中 未发现问题

  2. 线上 部分鸿蒙用户反馈: 页面卡死没反应 || 页面不能继续下一步

  3. so: 问题有可能是 音频没播出来, 或者回调没回来, 或者 获取音频的时长错误

测试现场1

  1. 经过测试的重复复现问题 得到一个现场数据 如下

    2022-08-09 17:10:54.792 21491-21981/com.zuoyebang.bangbangshizi V/AudioEngineImpl: play2d, _audioPlayers.size=0
    2022-08-09 17:10:54.792 21491-21981/com.zuoyebang.bangbangshizi V/AudioPlayerProvider: (@assets/assets/bundle_common/native/5b/5b1f43ed-ff53-42f2-ae62-b8770d2533ad.mp3) file size: 979728
    2022-08-09 17:10:54.792 21491-21981/com.zuoyebang.bangbangshizi V/UrlAudioPlayer: Current UrlAudioPlayer instance count: 1
    2022-08-09 17:10:54.792 21491-21981/com.zuoyebang.bangbangshizi V/UrlAudioPlayer: UrlAudioPlayer::prepare: @assets/assets/bundle_common/native/5b/5b1f43ed-ff53-42f2-ae62-b8770d2533ad.mp3, SL_DATALOCATOR_androidFD, 147, 190559016, 979728
    2022-08-09 17:10:54.792 21491-21981/com.zuoyebang.bangbangshizi I/Audiosystem: getDeviceConnectionState , Connecting to the Bluetooth device
    2022-08-09 17:10:54.792 21491-21981/com.zuoyebang.bangbangshizi I/IAudioPolicyService: getDeviceConnectionState, BpAudioPolicy: Bluetooth device
    2022-08-09 17:10:54.796 21491-21981/com.zuoyebang.bangbangshizi V/AudioEngineImpl: play2d, _audioPlayers.size=1
    2022-08-09 17:10:54.796 21491-21981/com.zuoyebang.bangbangshizi V/AudioPlayerProvider: (@assets/assets/bundle_common/native/be/be1894f3-7064-4479-94fe-cfaabe1a07c6.mp3) file size: 202477
    2022-08-09 17:10:54.796 21491-21981/com.zuoyebang.bangbangshizi V/UrlAudioPlayer: Current UrlAudioPlayer instance count: 2
    2022-08-09 17:10:54.796 21491-21981/com.zuoyebang.bangbangshizi V/UrlAudioPlayer: UrlAudioPlayer::prepare: @assets/assets/bundle_common/native/be/be1894f3-7064-4479-94fe-cfaabe1a07c6.mp3, SL_DATALOCATOR_ANDROIDFD, 151, 387146732, 202477
    2022-08-09 17:10:54.796 21491-21981/com.zuoyebang.bangbangshizi I/AudioSystem: getDeviceConnectionState , Connecting to the Bluetooth device
    2022-08-09 17:10:54.796 21491-21981/com.zuoyebang.bangbangshizi I/IAudioPolicyService: getDeviceConnectionState, BpAudioPolicy: Bluetooth device
    2022-08-09 17:10:54.880 21491-28436/com.zuoyebang.bangbangshizi E/libOpenSLES: Error after prepare: 1
    2022-08-09 17:10:54.885 21491-28433/com.zuoyebang.bangbangshizi E/libOpenSLES: Error after prepare: 1
    2022-08-09 17:11:01.042 21491-22407/com.zuoyebang.bangbangshizi E/NLog: start or restart send timer, sendInterval=30.
    
  2. 上边的数据可以看到: E/libOpenSLES: Error after prepare: 1

  3. 查找相关资料 : https://www.twblogs.net/a/5c83723dbd9eee35fc13cb3e/?lang=zh-cn

  4. 查阅资料可知:

    (1) E/libOpenSLES(25131): Too many objects
    (2) E/libOpenSLES: Error after prepare: 1
    
    第一个, 是SLPlayItf对象没有及时销毁,不同的平台SLPlayItf同时支持的数量不同,大约是2-10左右,所以音频播放完成之后,需要及时销毁。否则,出现(1)的错误,就会播放不出来声音,到一定程度就会导致崩溃。
    
    第二个, 是因为播放文件的格式OpenSLES不支持,或是文件有问题,无法正确播放。并且出现这种问题后,会让SLPlayItf的回调函数无法正确执行,最终导致SLPlayItf越来越多,从而出现(1)的情况和结局。
    
    那么,解决(1)的问题,就是在音频播放完成后及时销毁,我们可以使用回调来实现,但是(2)的问题又会导致回调不正确。
    
  5. 所以, 现在分析错误原因: 是因为调用关系, 或者别的位置原因 导致音频播放失败

测试现场1 解决方案

  1. 由于 代码中频繁的调用 cc.audioEngine.stopAll

  2. 这个错误 是 io 还挺快的鸿蒙机器上发现的

  3. 怀疑 stopAll 和 play 调用时间不确定。 stop 还未完成 直接调play 导致播放失败

  4. 顺着这个思路 尝试解决的方案 就是

    1. 切换场景 和 切换页面 调用 stopAll 之后 等待 0.1s 在初始化场景
    2. 0.1s 用户感知上 未见明显延迟
    

测试现场2

  1. 测试现场2 是 比较老的 鸿蒙pad 上发现的

    08-08 15:29:06.345   588   806 I APM_AudioPolicyManager: getNewOutputDevice() selected device 2 connectdeDevices(10002)
    08-08 15:29:06.346   588   806 D APM::AudioOutputDescriptor: stop, profile name: primary out,  curActiveCount: 0
    08-08 15:29:06.346 13482 14264 E libOpenSLES: frameworks/wilhelm/src/android/AudioPlayer_to_android.cpp:889: pthread_mutex_lock_timeout_np returned 110
    08-08 15:29:06.346   817   894 I dubaid  : [AudioHandler.cpp] stopSession# Failed to find audio session: 3753
    08-08 15:29:06.354  9599  9893 W ContentSensor_AudioInfoCapture: No need notify, resultList is empty
    08-08 15:29:06.354  9599  9893 W ContentSensor_AudioInfoCapture: insert info list is empty
    08-08 15:29:06.354  9599  9893 W ContentSensor_AudioInfoCapture: insert info list is empty
    08-08 15:29:06.372  2494  3160 D nStackXCoAP: ParseServiceDiscover:[416] :new device join
    08-08 15:29:06.372  2494  3160 E nStackXDFinder: DatabaseAllocRecord:[136] :DB max limit exceeded maxcnt:20, usecnt:20
    08-08 15:29:06.372  2494  3160 E nStackXDFinder: CreateNewDevice:[227] :Failed to allocate device info
    08-08 15:29:06.376 13482 14264 E libOpenSLES: frameworks/wilhelm/src/android/AudioPlayer_to_android.cpp:889: pthread_mutex_lock_timeout_np returned 110
    08-08 15:29:06.382  9599  9893 W ContentSensor_AudioInfoCapture: No need notify, resultList is empty
    08-08 15:29:06.382  9599  9893 W ContentSensor_AudioInfoCapture: insert info list is empty
    08-08 15:29:06.382  9599  9893 W ContentSensor_AudioInfoCapture: insert info list is empty
    08-08 15:29:06.384  9599  9893 W ContentSensor_AudioInfoCapture: No need notify, resultList is empty
    08-08 15:29:06.384  9599  9893 W ContentSensor_AudioInfoCapture: insert info list is empty
    08-08 15:29:06.384  9599  9893 W ContentSensor_AudioInfoCapture: insert info list is empty
    08-08 15:29:06.385  1589  1598 I system_server: Background concurrent copying GC freed 826201(24MB) AllocSpace objects, 3(60KB) LOS objects, 40% free, 34MB/58MB, paused 839us total 209.358ms
    08-08 15:29:06.386 13482 14263 D         : TrackPlayerBase::~TrackPlayerBase()
    08-08 15:29:06.386 13482 14263 D         : PlayerBase::~PlayerBase()
    08-08 15:29:06.387 13482 14263 D         : TrackPlayerBase::~TrackPlayerBase()
    08-08 15:29:06.387 13482 14263 D         : PlayerBase::~PlayerBase()
    08-08 15:29:06.399  9599  9893 W ContentSensor_AudioInfoCapture: No need notify, resultList is empty
    08-08 15:29:06.399  9599  9893 W ContentSensor_AudioInfoCapture: insert info list is empty
    08-08 15:29:06.399  9599  9893 W ContentSensor_AudioInfoCapture: insert info list is empty
    08-08 15:29:06.416 13482 14264 E libOpenSLES: frameworks/wilhelm/src/android/AudioPlayer_to_android.cpp:889: pthread_mutex_lock_timeout_np returned 110
    08-08 15:29:06.433  1589  1815 I HwFingersSnapshooter: handleMotionEvent first finger(0) touch down at (106.9443,115.90342)
    08-08 15:29:06.467 13482 14264 E libOpenSLES: frameworks/wilhelm/src/android/AudioPlayer_to_android.cpp:889: pthread_mutex_lock_timeout_np returned 110
    
  2. 表现为: 页面不能点击 动画不播放 , 连接V8 调试模式 连接失败

  3. 怀疑 V8 引擎崩溃 或者卡死

  4. 但是 查看上述 log 发现

    libOpenSLES: frameworks/wilhelm/src/android/AudioPlayer_to_android.cpp:889: pthread_mutex_lock_timeout_np returned 110
    
  5. 所以 最后怀疑: 音频线程死锁,把主线程 卡死

  6. 查找资料: https://developer.aliyun.com/article/580467

  7. 查找资料:https://forum.cocos.org/t/topic/115287 论坛中有人提到:卡死的问题我也遇到过,是短时间内停止、播放音效导致的,上层做下管理,避免这种情况的出现。

  8. 结合 复现机器, io 很慢,

  9. 所以 分析原因: 有可能是 因为io慢, 音频加载的时间变长, 刚播放 就调用 stop ,导致音频线程锁死

测试现场2 解决方案

  1. 由于 代码中频繁的调用 cc.audioEngine.stopAll

  2. 这个错误 是 io 非常慢的鸿蒙机器 发现的

  3. 音频加载的时间变长, 刚播放 就调用 stop ,导致音频线程锁死

  4. 顺着这个思路 尝试解决的方案 就是

    1. 调用 cc.audioEngine.play 之后 0.1s 之内 不允许stopAll
    2. 调用play之前 记录一下 当前时间戳
    3. 调用 stopAll之前 判断 是否 超过记录时间戳的 0.1s  如果不够的话 等待到0.1s 再stop
    记录的代码如下
    
        public static initFuncForAudioEngine()
            let playFunc = cc.audioEngine.play
            cc.audioEngine.play = (clip: cc.AudioClip, loop: boolean, volume: number):number=>
                AudioUtils._lastTimeSound = new Date().getTime()
                return playFunc.call(cc.audioEngine, clip, loop, volume)
            
    
            let playEffectFunc = cc.audioEngine.playEffect
            cc.audioEngine.playEffect = (clip: cc.AudioClip, loop: boolean):number=>
                AudioUtils._lastTimeSound = new Date().getTime()
                return playEffectFunc.call(cc.audioEngine, clip, loop)
            
    
            let playMusicFunc = cc.audioEngine.playMusic
            cc.audioEngine.playMusic = (clip: cc.AudioClip, loop: boolean):number=>
                AudioUtils._lastTimeMusic = new Date().getTime()
                return playMusicFunc.call(cc.audioEngine, clip, loop)
            
        
    
    

如何在 Cocos2d 中播放音频文件的特定部分

【中文标题】如何在 Cocos2d 中播放音频文件的特定部分【英文标题】:How to play a particular portion of an audio file in Cocos2d 【发布时间】:2014-10-01 09:44:34 【问题描述】:

我正在使用 SimpleAudioEngine 播放名为“myTrack.mp3”的音频文件:

[[SimpleAudioEngine sharedEngine]playBackgroundMusic:@"myTrack.mp3" loop:NO];

00:17 秒时长的音频,我播放整个文件。但现在我只需要播放时间 00:0800:14 之间的部分。在 Cocos2d 中可以吗?

谢谢。

【问题讨论】:

【参考方案1】:

我不熟悉 SimpleAudioEngine,但您可以使用标准的 AVQueuePlayer:

1) seekToTime。例如([_player seekToTime:CMTimeMakeWithSeconds(8.0, 1.0)])

2) 然后给播放器添加时间观察器:

 _timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1.0, 1.0)
                                                  queue:NULL
                                             usingBlock:^(CMTime time) 
                                                 check current duration and stop the playback. 
                                             ];

【讨论】:

如果我没记错的话,CocosDenshion 在后台使用 AVAudioPlayer 进行(背景)音乐播放。不要以为可以通过简单的接口访问,必须在 CDAudioManager 之类的。 抱歉,'timeObserver' 对象类型是什么?在添加这些行时,我收到了 Mach-O 链接器错误:“架构 i386 的未定义符号:”。你能帮我吗? id timeObserver。最后你可以做 [_player removeTimeObserver:_timeObserver] 并将其设置为 nil。 i386的奇怪问题。什么符号?

以上是关于cocos creater 鸿蒙 音频卡死 播放失败 不回调的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Cocos2d 中播放音频文件的特定部分

cocos2d-JS Cocos Creater

cocos creater 简单的跳跃动作。

cocos2d-JS 第三炮Helloworld及Cocos Creater简介(宝贵的经验!)

cocos2d-JS 第二炮Cocos Creater(使用当下最新的编辑器,带你ZB装带你fly)

尝试播放音频文件