
做语音直播开发有些年头了,经常被一个问题困扰:用户反馈说开着直播app手机发烫,电池撑不过半天。说实话,这事儿挺让人头疼的。毕竟现在用户对电量敏感得很,没人愿意为了听个直播就把手机插着充电宝用。
后来我们团队专门花时间研究了下怎么在保证音质和流畅度的情况下,把耗电量尽量压下来。这篇文章就把我踩过的坑和总结的经验分享出来,希望能给正在做类似开发的朋友一些参考。
在想办法省电之前,咱们得先弄清楚手机里的电都是怎么被消耗掉的。就像修房子得先知道地基在哪一样,知道了耗电的大头在哪,才能有的放矢地去优化。
语音直播app的耗电主要来自这几个方面:音频编解码、扬声器或耳机播放、网络数据传输、屏幕显示,还有cpu的后台运算。这里有个有意思的发现,很多人觉得屏幕是耗电大户,但在纯语音直播场景下,屏幕常亮反而不是最费电的那个。真正偷走电量的,往往是那些看不见的后台工作。
我做过一个简单的测试对比,同样条件下播一小时语音直播,屏幕关闭和屏幕亮着的电量差距其实不大。但把codec换成高码率的版本,或者频繁做网络重连,那电量掉得可就快了。这个发现让我们团队后来优化时有了明确的方向——先抓大头,别在细枝末节上花太多精力。
音频编解码绝对是语音直播里最耗性能的环节之一。每次把麦克风采集到的原始音频数据压缩成网络传输的格式,再在接收端解压缩播放,这个过程cpu一直在高强度工作。你可能会说,现在手机cpu性能都过剩了,这点运算不算什么。但问题是,这种运算不是跑一下就完事了,而是一场直播可能要持续好几个小时,积少成多就很可观了。

我们在声网的项目里试过好几种codec,最后发现opus确实是个不错的选择。它的编码效率高,而且可以根据网络状况动态调整码率。在网络好的时候用高码率保证音质,网络差的时候自动降下来,既减少了传输带宽,也降低了编解码的运算量,一举两得。
还有个细节可能很多人会忽略:采样率的选择。很多开发者觉得采样率越高音质越好,这话没错,但高采样率意味着更大的数据量和更多的运算。在语音直播这个场景下,人声的频率范围其实很有限,16kHz到32kHz的采样率已经完全够用了。没必要为了追求”高保真”就用48kHz甚至更高的采样率,白白增加cpu负担。
| 采样率 | 适用场景 | 功耗水平 |
| 8kHz | 普通语音通话,音质要求不高 | 最低 |
| 16kHz | 语音直播日常使用,推荐选用 | 较低 |
| 32kHz | 较高音质需求,接近广播级 | 中等 |
| 48kHz | 专业音频制作,语音场景没必要 | 较高 |
这里有个重点得单独说说。现在的智能手机芯片一般都会自带音频编解码的硬件加速功能,调用硬件加速和纯软件运算的功耗差距有多大呢?我们实测过,大概能省电30%到50%。这个数字相当可观了。
那怎么调用硬件加速呢?不同平台的实现方式不太一样。Android平台可以用MediaCodec,iOS平台可以用Audio Toolbox里的硬件codec接口。写代码的时候注意判断一下设备是否支持对应的硬件codec,如果支持就优先用, fallback到软件实现。这样既保证了兼容性,又能在支持的设备上拿到省电红利。
当然,硬件加速也不是万能的。有些设备上硬件codec的实现会有一些小问题,比如延迟稍大或者某些参数不支持。这时候就得做好错误处理,确保出问题了能平滑切换回软件方案,别让直播中途崩了。
网络这块的耗电主要来自两个方面:数据发送接收的 radio 功耗,还有网络状态变化时的信号搜索和切换。做过移动开发的都知道,蜂窝网络的 radio 在活跃传输数据和待机状态下的功耗能差出好几倍,而且从待机切换到活跃状态的那一瞬间,功耗会飙到很高。
基于这个原理,我们优化网络传输的思路就清晰了:减少网络状态切换的频率,让 radio 尽量维持在稳定的活跃或者休眠状态,别反复横跳。具体怎么做呢?
首先是合理设置心跳间隔。心跳包的作用是告诉服务器”我还活着”,但太频繁的心跳会让 radio 频繁唤醒,浪费电。我们測试下来,30秒到60秒的心跳间隔是比较合适的,既能及时发现网络异常,又不会太耗电。
然后是音频数据的发送策略。有些开发者喜欢每采集到一点音频就立刻发出去,这样确实延迟低,但网络包太小太碎,radio 频繁工作,功耗上去了。更好的做法是凑够一定的数据量再发送。比如每次发送20ms到40ms的音频数据,这样可以显著减少网络包的发送次数,radio 工作时间变短,耗电自然就少了。
前面提到 opus 的时候简单提了一下码率自适应,这里展开说说。码率自适应不仅仅是网络优化的手段,也是省电的重要技巧。因为高码率意味着更大的数据量,传输和编解码都要消耗更多电量。
在实现码率自适应的时候,我们通常会监测网络的rtt、丢包率这些指标。当网络状况变差时,主动降低码率;网络好了再升上来。这个逻辑看起来简单,但实际调优的时候有很多细节要注意。比如降码率的阈值设置得太敏感会导致频繁波动,用户体验不好;设置得太迟钝又起不到及时反应的作用。
我们后来加了平滑过渡的逻辑,不是突然从高码率跳到低码率,而是循序渐进地调整。这样一方面用户体验更平滑,另一方面也给cpu和radio一个适应的过程,整体功耗曲线更稳定。
很多人写代码的时候不太关注cpu调度,觉得手机性能强,cpu跑满也没事。但实际上,cpu在高频状态下的功耗是非常惊人的。如果能让cpu在空闲的时候降频甚至休眠,积少成多能省不少电。
语音直播的场景其实很有规律:在没人说话的时候,除了背景噪音处理,基本上没什么运算量;有人说话的时候,编解码的运算量才会上去。利用好这个特点,就能做很多优化。
具体来说,我们可以实现一种轻量级的语音活动检测算法,区分有人说话和没人说话的时段。检测到没人说话时,可以把编解码的采样率适当降低,或者把处理间隔拉大,让cpu有机会进入低功耗状态。有人说话时再恢复正常工作。这种动态调整需要调好阈值和响应速度,不然会出现说话时反应迟钝的问题。
还有一个思路是任务调度。语音直播的音频处理其实可以拆分成多个小任务,合理安排这些任务的执行时间,尽量让cpu在一个时间窗口内集中处理完,然后进入休眠。而不是断断续续地处理,让cpu一直处于活跃和休眠之间切换。
虽然前面说屏幕不是最大的耗电大户,但在某些场景下,屏幕相关的优化还是能有一些效果的。特别是现在很多语音直播app都有精美的动效和虚拟形象,这些视觉效果背后都是gpu在跑,功耗可不少。
首先是最基础的:自动亮度调节得做好。很多用户喜欢把屏幕亮度调得很高看直播,但实际上在室内环境下,完全没必要那么亮。把自动亮度做好,不仅用户体验好,也能实实在在省电。
然后是动画和渲染。语音直播时,屏幕上的音波跳动、礼物特效这些确实能增加氛围感,但得节制。我见过一些app,音波跳动的刷新率能做到60fps,确实流畅,但gpu一直高负载跑着,功耗上去了。后来我们改成30fps,视觉上差别不大,功耗降了一截。
虚拟形象这块,如果用了复杂的3d模型,gpu的功耗会更高。如果用户设备性能一般或者电量告警,可以建议用户切换到静态头像模式,把3d渲染关掉。这不是功能上的妥协,而是对用户实际使用场景的体谅。
App在前台和后台的运行策略完全不同,这块的优化空间其实很大,但很多开发者重视不够。
先说进入后台的情况。当用户切换到其他app或者锁屏时,语音直播app应该怎么处理?完全切断不行,用户可能还在听;继续保持高质量传输又太耗电。比较好的做法是检测到后台状态后,主动降低码率、降低帧率,甚至暂停视频流(如果是语音加视频的直播)。有些app会提示用户”已进入后台省电模式”,让用户知道发生了什么,这个交互设计值得借鉴。
还有就是来电中断的处理。直播过程中突然有电话打进来,这是很常见的场景。处理不好的话,电话挂了直播也断了,或者电话来了直播还在跑导致漏听。应该在电话进来时暂停直播相关的数据处理和传输,通话结束后恢复。这些边界情况的处理虽然不涉及核心技术,但对用户体验影响很大。
另外,Android和iOS的后台机制不太一样,需要分别处理。Android的后台限制越来越多,很多以前能做的事情现在不让做了。iOS的background modes相对宽松一些,但也要注意不要滥用,不然审核可能过不了。了解并遵守平台规范,是做好后台管理的前提。
除了上面说的几个大头,语音直播app还会用到一些其他硬件,比如麦克风、扬声器、振动马达什么的。这些硬件虽然单个功耗不高,但加在一起也不能忽视。
麦克风的功耗优化主要体现在增益控制上。有些app为了保证音质,把麦克风增益设得很高,结果收录了很多背景噪音,既增加了后期处理的运算量,又影响了音质。其实根据环境噪音动态调整增益更好,没人说话时降低增益,有人说话时再提高。
扬声器这块,主要是音量控制。最大音量播放不仅耗电,也容易产生失真。适当控制音量上限,既能保护用户听力,也能省点电。还有个细节:使用扬声器播放时,可以关闭一些不必要的音效处理,比如虚拟环绕声之类的,这些特效在扬声器模式下效果有限,纯属浪费运算。
说了这么多优化技巧,最后想分享几点在实际开发中的心得。
第一,耗电优化一定要结合真实场景测试。实验室里的数据和用户实际用起来可能差别很大。我们之前在办公室里测得好好的,结果用户反馈在地铁里耗电特别快。后来去地铁里复现才发现,频繁的信号切换和较差的网络环境下,app的功耗策略完全失效了。所以测试场景要尽可能贴近真实使用环境。
第二,做好电量监控和上报。App可以定期获取一下系统电量信息,结合自己的运行状态做关联分析。这样就能知道在用户那真实的使用场景下,哪些情况耗电最严重。这些数据对后续优化方向很有指导意义。
第三,给用户选择权。不同用户对电量和体验的取舍不一样。有些用户不在乎电量,就想要最高画质;有些用户电量告警了,只求能多撑一会儿。app里可以提供几种不同的直播质量模式让用户选择,让用户根据自己的实际情况做决策。
第四,省电不能牺牲核心体验。语音直播的核心是流畅度和音质,如果为了省电把这两个搞砸了,得不偿失。省电优化应该在保证基本体验的前提下做减法,而不是牺牲体验硬省钱。
这些经验也是我们在声网的多个项目里一点点摸索出来的,不一定适用于所有场景,但思路应该是有共通性的。开发过程中多思考多测试,慢慢就能找到适合自己的平衡点。
好了,这就是我关于语音直播app耗电优化的一些总结。技术这东西日新月异,可能过两年又有新的优化方法出来,但底层的一些思路应该是相通的。希望对正在做这方面开发的朋友有点帮助。如果有什么问题或者更好的想法,欢迎交流讨论。
