linux的声音管理
前言
在使用arch与i3时,
发现不能在插入耳机后自动调用耳机输出声音,
而是需要使用 pavucontrol
工具来手动调整输出的硬件,
非常不方便,于是看一看linux的声音到底是怎么管理的.
音频系统本身没有像OSI模型一样每层之间有明确的界限,而是各自为政,互相有影响
名词解释
OSS
Open Sound System
开放声音系统.
- 直接和内核通信,驱动硬件.
- 提供单纯可移植的API给程序.
一开始的声卡支持硬件混音功能,后来由于制造商看法的改变,混音功能交给了软件而OSS没有跟进,
因此OSS本身不具有混音功能.但可以调用声卡的硬件混音功能.
ALSA
Advanced Linux Sound Architecture
高级linux声音体系
由于OSS闭源的原因,打算代替OSS.
过程中加入了OSS自身不支持的软件混音(尽管评价并不好)
并且顺便带了audio server的功能.
由于软件推广的原因,推出了OSS的模拟器
(结果模拟器比本尊还好,但抛弃了调用声卡硬件混音的功能,导致在模拟OSS的API时没有优势可言).
作用如下:
- 提供声卡驱动
- 提供用户操作的函数库
- 负责混音
- 两个程序同时发声时,另声卡发出混和了两种声音的一个声音
- 原则上如果声卡支持硬件混音则声卡自己来(然alsa并不支持)
- 最多支持8路音频硬件
- ALSA的混音饱受诟病,因此混音的部分常常放在pulseaudio中
- alsa API ->alsa混音->alsa底层
- alsa API ->pulseaudio混音->alsa底层
- 硬件资源调用
- 多声道支持
ALSA工具
用于和alsa进行交互
- amixer 命令行中简单的工具
- alsamixer 命令行中使用字符模拟GUI的工具
- alsactl alsamixer的字符版工具,兼具保存配置的功能
配置文件放在 /var/lib/alsa/asound.state
封装器
oss,alsa等的后端太多,就需要有一个封装器包装一下.
- OpenAL
- SDL
- libao2
可能引起额外的延迟
PulseAudio
桌面环境中常用的音频服务(守护进程),
处于alsa与应用程序之间,
充当代理的角色(有时alsa将pulseaudio视为一个虚拟的设备).
- 用户–pulseaudio–虚拟设备–alsa–虚拟设备–pulseaudio–用户
同时有更强的软件能力,可以将远程的音频在本地播放.
但正常来说应该在网络层完成该功能而不是在应用里
pulseaudio的前端(配置该服务行为的软件)有:
- paprefs(用于配置插口用途,比如将麦克风口改为耳机口)
- pavucontrol(用于配置目前使用的播放设备)
- kmix
- plasma-pa等
配置文件放在 /etc/pulse/
也可以有用户的配置文件 ~/.config/pulse/
声卡
早期是将数字信号转换为模拟信号,
一般独显中也自带一个.
PCM
Pulse Code Modulation
脉冲编码调制
模拟信号经过采样,量化,编码转换后的数据流
回放
问题
自己的台式机在使用HDMI连接的带音响显示器时,无法在耳机插入后自动切换为耳机播放,
在windows下甚至也不行.
原因在于:
HDMI使用的是显卡自带的声卡且直接使用数字信号,
耳机如果插在主机上则使用的是主板自带的声卡,使用的是模拟信号.
系统可以在同一个声卡连接的不同端口(比如耳机和主机音响)之间自动切换,
却不能在两个声卡之间自动切换.
目前已知的信息
module-switch-on-connect
pacmd的module中有一个module-switch-on-connect
描述是当有新的sink连接时使用新的sink,
但自己电脑上无论是否插入耳机,都有两个sink,一个内置声卡,一个HDMI声卡
pulseaudio配置的结构
目前pulseaudio的结构并不很清楚,都是猜的
card – (sink)
profile |
port (sink可以使用哪些端口则受到profile的影响)
如果没有声音,原因可能是
- profile由于未知的原因不可用
- profile不可用导致该声卡不能关联合适的port,端口是最接近输出声音的地方,即使选择正确的输出设备,没有正确的端口也听不到声音.
pavucontrol中有三个tab比较关键,
分别是
- playback
- output-device
- settings
settings
在此处为声卡(card)选择配置文件(profile)
等效的命令为
1 | pacmd set-card-profile <card-idx> <profile-nm> |
- 有哪些声卡以及profile需要使用
pacmd list-cards
查看 - BIOS设置音频为新版的HD(旧版为AC97),profile的状态大多是不可用的,
- 目前除了更换为旧版以外还没有其他办法将profile设置为可用
- profile不可用的原因也不清楚
- 一说是因为该profile使用的port全部不可用
- 但又来了问题, port不可用的原因是什么
output-device
在此处为输出设备(sink)选择端口(port).
等效的命令为
1 | pacmd set-sink-port <sink-idx> <port-name> |
- 可以使用的sink和port使用
pacmd list-sinks
查看
playback
此处为应用(input)选择播放设备(sink)
等效的命令为
1 | pacmd move-sink-input <input-idx> <sink-idx> |
- 以上众多命令大致都可以使用index或name来代替
- 查看有那些input可以使用
pacmd list-sink-inputs
解决思想
在profile和port都设置好的情况下
- 设置默认的sink为外置声卡
- 检测耳机插入的事件
- 为事件加入钩子
- 如果有input则切换所有input的sink为内置声卡
- 如果没input则设置默认sink为内置声卡
- 检测耳机拔出事件
- 有input则切换input的sink
- 没有则设置默认sink
网上有,但用于检测hdmi状态的代码在自己的机器上不合适
https://gist.github.com/3v1n0/ad3ad73e0bdd466d7f4a95b3aa376285