点击下方👇关注 Android系统攻城狮
第200篇原创文章
持续迭代|Android+Linux多媒体进阶体系专栏·课程 知识体系持续更新

1


播放音乐时,如果导航提示音突然出现,背景音乐通常不会完全停止,而是暂时降低音量。导航播报结束后,音乐音量又会自动恢复。
这种行为通常称为降音,也就是duck。
在PulseAudio中,降音、静音和Cork是三个容易混淆的概念。它们看起来都在“压制背景音乐”,但内部执行的动作并不相同。
先用一句话概括:
本文以导航提示音和背景音乐为例,说明PulseAudio如何完成降音,以及降音、静音和Cork之间的区别。

2


假设车机正在播放音乐,此时导航应用需要播报“前方路口右转”。
如果导航提示音和背景音乐保持相同音量,提示内容可能会被音乐掩盖。最直接的处理方式,就是在导航播报期间临时降低背景音乐音量。
整体过程如下:
背景音乐正在播放 ↓导航提示音出现 ↓PulseAudio识别两条流的media.role ↓找到需要降低音量的背景音乐 ↓给背景音乐添加内部衰减因子 ↓导航提示音结束 ↓删除内部衰减因子 ↓背景音乐恢复原有音量整个过程中,背景音乐没有停止播放,应用程序也不需要重新设置音量。PulseAudio只是在Server内部临时改变背景音乐的实际输出音量。

3


PulseAudio需要先知道每条播放流承担什么用途。
应用程序可以通过media.role属性描述播放流角色。例如:
导航提示音:media.role=event背景音乐:media.role=music其中:
event表示提示音、通知音或者界面反馈音;music表示背景音乐或者媒体播放流。module-role-ducking读取播放流的media.role。当模块发现高优先级触发流出现时,会根据配置查找需要降低音量的目标播放流。
例如:
触发角色:event目标角色:music衰减幅度:-20dB 这表示当event角色的播放流出现时,music角色的播放流需要临时降低约20dB。

4


PulseAudio不会直接改写用户看到的普通播放音量,而是给目标Sink Input增加一个内部音量因子。
实际软件音量可以简化为:
实际软件音量 = 原有音量比例 × 内部音量因子对应到内部关系,可以表示为:
soft_volume = real_ratio × volume_factor假设背景音乐原有音量比例为:
real_ratio=0.8导航播报期间增加的内部音量因子为:
volume_factor=0.1那么实际输出比例约为:
soft_volume = 0.8×0.1 = 0.08此时背景音乐仍然持续播放,但PCM数据经过软件音量处理后,输出幅度明显降低。
因此,降音并不是:
它只是给目标播放流临时叠加一个衰减系数。

5


导航提示音退出后,module-role-ducking会删除此前添加的音量因子。
恢复过程可以表示为:
导航提示音退出 ↓重新检查当前触发流 ↓确认不再需要降音 ↓删除module-role-ducking添加的volume_factor ↓重新计算实际软件音量 ↓背景音乐恢复模块不需要提前保存一份“降音前音量”。
原因在于,它没有直接覆盖背景音乐原来的音量,只是临时增加了一项独立的内部因子。删除该因子后,剩余音量项重新参与计算,原有音量自然恢复。

6


静音和降音的目的相似,都是为了避免不同播放流之间相互干扰,但它们执行的动作不同。
用户、应用程序或者策略模块可以直接设置Sink Input的muted状态。
静音之后:
因此:
静音只保证听不到声音,并不等于应用已经暂停播放。
module-role-cork也会根据media.role判断触发流和目标流。
触发流出现后,它会对目标播放流执行两个动作:
设置Sink Input为静音 + 向客户端发送REQUEST_CORK具体含义是:
1.调用Sink Input静音接口,使Server端没有声音输出;2.发送PA_STREAM_EVENT_REQUEST_CORK事件,请求客户端暂停播放。
这里必须注意,PulseAudio发送的是暂停请求,而不是直接强制应用停止发送数据。
只有客户端接收到该事件并正确处理后,播放流才会真正进入CORKED状态。
如果客户端不处理Cork请求:
Server端:目标流已经静音客户端:可能仍然继续发送音频数据因此,module-role-cork同时包含:

7


当触发流退出后,module-role-cork首先解除目标Sink Input的静音状态。
如果目标播放流已经进入CORKED状态,模块还会向客户端发送:
PA_STREAM_EVENT_REQUEST_UNCORK请求客户端恢复播放。
完整过程如下:
高优先级播放流出现 ↓目标Sink Input静音 ↓发送REQUEST_CORK ↓客户端处理请求并暂停 ↓高优先级播放流退出 ↓解除目标Sink Input静音 ↓发送REQUEST_UNCORK ↓客户端恢复播放
8


muted状态 | |||
module-role-ducking | module-role-cork |
一句话区分:
降音:改变声音大小。
静音:是否有声音。
Cork:请求应用暂停播放。
专栏推荐