BES2600播放音乐卡顿调试
在使用BES2600芯片做耳机的项目的时候, 播放音乐时总是偶尔会有一些播放卡顿的情况, 本篇文章简单列举了BES2600 SDK中几种常见的播放卡顿情况.
本文是BES2600播放音乐卡顿调试 (一)的续篇, 上篇文章主要描述的是因蓝牙干扰导致数据包接收不正常导致的卡顿, 需要参考的小伙伴可以阅读上一篇文章.
af_thread warning 导致的卡顿
播放过程中出现af_thread warning, 也是导致播放音乐卡顿常见的原因之一, 如下图
从log中可以看到这里报了af_thread线程警告, 同时可以看到有nv_extension_callback的打印, 所以可以初步判断这个卡顿是播放过程中刷写flash导致的. 跟踪SDK代码进入nv_record_extension_flush_main()刷写flash操作可以看到, 刷flash之前有对中断上锁动作, 这会导致刷flash过程中播放af线程得不到调度导致无法播放, 线程提示WARNING. 可以在播放音乐的过程中避免flash刷写操作来解决此问题
还有一种可能会出现af_thread warning的情况, 就是在播放的过程中加了一些其他非常占用时间的代码程序, 这样同样也会影响到af线程得不到调度. 比如加入了一些复杂的音频算法或UI上比较复杂的操作, 这种情况下可能会出现持续的af thread warning导致的卡顿.
这种情况的解决方法是提升播放音乐时候的主频来解决.在app_stream.cpp中的sbc_player()函数中修改播放音乐时候的freq设置来提升播放时的主频, 或使用boost的方式临时提高主频. 下图为播放的时候提升播放音乐主频设置的位置, 可以从log中的CPU USEAGE来初步判断需要多少主频. 播放主频会与功耗相关, SDK默认只开了26M, 如果播放功耗要求不严格的情况应该酌情提高
list full 导致的卡顿
之前的文章有提到过手机与耳机之间音频流大致处理方式如下
接收缓存: 先把接收的音频流数据缓存下来, 延时一段时间后再去播放. 这样如果偶尔有某些音频流来的比较晚, 也可以先播放提前缓存下来的包. 从而减少由于干扰原因导致的音频流来的数据太晚, 而造成的数据播放过程的中断, 出现卡顿现象.
解码: 接收到的音频流是经过编码(sbc, aac, ldac等)的, 需要解码后, 才能送到硬件外设去播放.
播放: 把解码后的数字音频流转换成模拟波形, 输出到喇叭(常用的做法是数据送去dma, dma送给喇叭播放)
与上一篇文章提到的cache underflow error相反, 播放过程中如果出现提示list full MTU_LIMTER so discards_packet等字眼时, 代表的是cache overflow接收到的缓存溢出了, 这里可能原因为音频trigger不成功, 左右音乐包对不上, 没有给dma送数据进行解码动作, 导致缓存list溢出
缓存完成后, 需要开始stream trigger. trigger是为了左右audio sync, 完成后才可以decoder 解码播放, 因此音频同步必须在trigger OK前完成, audio sync mismatch会导致音频播放卡顿的问题
trigger time 的配置主要有A2DP_PLAYER_PLAYBACK_DELAY_SBC_US 以及frame nums of per packet ,修改这两个参数会影响trigger time , 注意不能影响左右音频同步. 下图以SBC编码为例, 其他音频编码类似