为啥要写这个呢,因为WebRTC有个关闭房间卡死主线程的问题,真的困扰了我好久。经过我和同事的不懈努力,不断地跟踪源码,终于解决了这个bug,今天先简单记录下,后面有时间再详细整理解决过程吧。
问题背景
在音视频通话过程中,当有设备退出房间时,iOS会发生概率性卡死情况。
分析过程
卡死问题在之前版本的解决过程中,已排除上层调用、内存实例清理和videoView渲染的影响。
从测试复现的场景上看,当操作切换音频的外放和听筒模式时,极易复现卡死现象,通过查代码发现切换音频模式时,会调用
[[AVAudioSession sharedInstance]setActive:YES error:nil];而该方法是会阻塞主线程的,因此将该方法放在了子线程。这在很大程度上减少了一对一音视频的卡死情况,
但是在多人音视频上却并未有很大效果。
通过阅读跟踪WebRTC底层代码逻辑,PC有个media_controller,关闭pc的时候,要在worker_thread中执行media_controller的析构函数,先删除media_controller中的video_receive_stream,video_receive_stream中有个decoder,是H264_Video_toolbox_decoder,删除decoder的时候,如果解码器在子线程中解码的当前帧未完成,那么此时解码器是加了锁的,主线程worker_thread要执行删除decoder操作,因此进入了wait状态,也就卡死了主线程。修改后基本没有再次出现卡死情况,极偶现的一次卡死在了解码线程的pthread_join上,待后续继续跟进。
分析过程中对底层的代码梳理在https://www.processon.com/view/link/5e551997e4b02bc3ad6148e6中可以看到。
解决方案
从最终的调查结果看,造成卡死现象的原因是多方面的。包括音频模式在主线程的切换,解码线程的阻塞和解码器的释放。目前的解决的方案是从三点进行优化解决:
1、音频模式切换放在子线程中进行,以免阻塞主线程;
2、H264解码器进行异步等待解码完成后释放;
3、解码的sampleBuffer判断其CMItemCount是否大于0,否,则返回解码错误。
网友评论