播放器声卡设备绑定问题
背景: TTS引擎合成的PCM音频流,送给播放器,到指定声卡完成音频播放;
原本使用GStreamer + alsasink插件,输出到alsa的指定声卡设备中
const std::string pipeline_desc =
"appsrc name=mysrc ! " // 从应用层推送音频数据的源
"audioconvert ! " // 转换音频格式(采样位宽、通道数等)
"audioresample ! " // 重采样(调整采样率)
"alsasink device=my_audio_device "; // 用 ALSA 输出到指定设备
最开始,这里指定的device是default,导致输出到了hw:0,0,0号声卡的第0个设备,对应UI上多媒体的音量控制。
问题: 绑定的音频设备有问题,导致多媒体播放 + 唤醒卡顿,唤醒&交互音量忽大忽小,还有在连接蓝牙的情况下,TTS播报会非常卡顿
推测是由于多路音频输入同一个设备,造成的音频竞争。
解决过程: 查看设备->研究GStreamer问题->转换到直接调ALSA API 重构播放器
检查设备绑定问题
- 使用命令行测试,UI上的语音服务音量调节按钮,具体控制的是哪个声卡设备,以此确定了到底应该将音频流输出到哪个声卡设备。
# hw0,5 或者 my_audio_device 这个自定义的音频设备
aplay -D hw:0,5 test.wav
# 以及检测Mixer空间状态变化
alsactl monitor
同时,并没有发现自定义声卡名字的配置,可能客户给出的设备名,是定义在系统底层硬件上的。
/etc/asound.conf
or
~/.asoundrc
并且检查混音器 TTS_MIXER 的相关信息。
sh-4.4# amixer -c 0 scontents | grep -A 5 TTS_MIXER Simple mixer control 'TTS_MIXER',0 Capabilities: volume volume-joined Playback channels: Mono Capture channels: Mono Limits: 0 - 131072 Mono: 58894 [45%]
- Mixer(混音器)是 ALSA 中负责 音量控制 和 信号路由管理 的一部分。
简单来说,ALSA Mixer 就是管理和控制音频设备音量、静音、声道平衡等参数的组件。
检查音频设备的权限
# p->playback播放
# c->capture捕获
xuan@xuan:~$ ls -l /proc/asound/card0/
发现权限是够得,并没有问题。
检查SDS服务,在尝试播音频的时候,操作的声卡设备文件
lsof -p <pid> | grep pcm
发现,打开的是pcm0p,并不是pcm5p,所以还是得看,为什么代码中GStreamer打开的不对。
提高GStreamer日志等级,命令行启动服务,检查初始化日志
LOG alsa gstalsasink.c:1326:gst_alsasink_open:<alsasink0> Opened device plughw:0,5
DEBUG alsa gstalsa.c:470:gst_alsa_open_iec958_pcm:<alsasink0> Generated device string "plughw:0,5:{AES0 0x02 AES1 0x82 AES2 0x00 AES3 0x02}"
WARN alsa conf.c:5453:parse_args: alsalib error: Parameter DEV must be an integer
WARN alsa conf.c:5560:snd_config_expand: alsalib error: Parse arguments error: Invalid argument
WARN alsa pcm.c:2660:snd_pcm_open_noupdate: alsalib error: Unknown PCM plughw:0,5{xxx}
DEBUG alsa gstalsa.c:476:gst_alsa_open_iec958_pcm:<alsasink0> failed opening IEC958 device: Invalid argument
LOG alsa gstalsasink.c:1326:gst_alsasink_open:<alsasink0> Opened device multimedia_device
发现它尝试打开我们所指定的0,5设备了,然后尝试使用iec958解析,但是失败了,不过这里似乎并不影响后续流程,接着尝试打开multimedia_device设备,成功了,所以走了多媒体设备输出音频。
检查GStreamer1.12.4源码发现
gst_alsasink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
{
GstAlsaSink *alsa;
gint err;
alsa = GST_ALSA_SINK (asink);
if (alsa->iec958) {
snd_pcm_close (alsa->handle);
alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa), alsa->device);
if (G_UNLIKELY (!alsa->handle)) {
goto no_iec958;
}
}
if (!alsasink_parse_spec (alsa, spec))
goto spec_parse;
------
if(alsa->channels > 2) {
gst_alsasink_set_device(MULTIMEDIA2_DEVICE, alsa);
}else {
gst_alsasink_set_device(MULTIMEDIA_DEVICE, alsa);
}
------
像是尝试IEC958打开失败后,走了fallback,一定会走到 gst_alsasink_set_device(MULTIMEDIA_DEVICE, alsa); ,打开multimedia设备。
解决方案
- 尝试自定义设备名称——不可以,系统中不好添加新配置文件,而且这个方案似乎也会走到上述逻辑;
- 修改GStreamer源码——不可以,同样改动很大;
- 使用原生ALSA API重构播放器——可以,可控。
评论区