https://www.freedesktop.org/wiki/Software/PulseAudio 官网上的介绍是这样的:
pulseaudio 是一个POSIX操作系统上的声音系统。是音频应用的代理。它允许你对音频数据,在从应用传递到硬件的过程中,做更多的操作。像把音频数据传递到另一台机器,更改采样率,声道,多路音频混音等。

车机平台,会包含多种声音的处理。多媒体,语音,导航等。
我要做的是,在平台中声卡驱动及alsalib接口已经就绪的状态下,提供的接口,用于不同音频类型的播放及音量控制,还有录音。
其实直接用alsa也不是不可以,但是感觉pulseaudio功能还是多一些。而且后续可以通过配置属性实现软件的 audio route 控制。

使用alsa的小工具,可以查看当前配置好的playback和record接口。下面是我开发板中的信息:

root@atlas7-arm:~# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: kasaudiocard [kas-audio-card], device 0: Music Playback (*) []Subdevices: 1/1Subdevice #0: subdevice #0
card 0: kasaudiocard [kas-audio-card], device 1: Navigation Playback (*) []Subdevices: 1/1Subdevice #0: subdevice #0
card 0: kasaudiocard [kas-audio-card], device 2: Alarm Playback (*) []Subdevices: 1/1Subdevice #0: subdevice #0
...root@atlas7-arm:~# arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: kasaudiocard [kas-audio-card], device 8: Analog Capture (*) []Subdevices: 1/1Subdevice #0: subdevice #0
...

#不同音频类型的输出方案
pulseaudio 通过alsalib API处理音频输出的是alsa-sink对象。每个alsa-sink对象会对应一个alsa hw的输出设备(hw:0,0 hw:0,1 dmixer这些)。
所以,想法就是为不同的alsa hw设备接口,分别创建不同的alsa-sink,这样在处理不同APP的音频数据时,采用对应的alsa-sink作为输出端。
这样,需要做的就是为pulseaudio生成不同的alsa-sink,然后在处理不同类型的音频数据时,做对应的选择即可。

#Pulseaudio 的配置文件及模块加载
pulseaudio是一个守护进程,参考了官网的一些资料,把pulseaudio运行在了system-wide模式。
In some situations however, such as embedded systems where no real notion of a user exists, it makes sense to use the system-wide mode.
默认的配置文件在 /etc/pulse/daemon.conf
pulseaudio 加载模块,可以通过配置pa文件的方式(普通模式下是default.pa, system-wide模式下是system.pa)来在pulseaudio daemon启动后,自动加载
通过pa文件自动加载的话,要确保/etc/pulse/daemon.conf中的相关配置正确(load-default-script-file 和 default-script-file )
也可以通过pacmd工具来发送命令动态加载。

#创建alsa-sink对象
有几种方式

  1. 加载module-alsa-sink模块,每加载一次module-alsa-sink,会创建一个对应的alsa-sink对象。
  2. 加载module-alsa-card 模块,module-alsa-card模块会根据profile set 来创建一个或者多个alsa-sink对象。
  3. 加载module-udev-detect 模块,这个模块会发现alsa-card设备,然后加载module-alsa-card,然后就和方式2一样

按照前面说的,其实我是希望创建3个alsa-sink,分别对应hw:0,0 (Music Playback),hw:0,1 (Navigation Playback),hw:0,2(Alarm Playback)这几个alsa设备。

先看一下直接加载module-alsa-sink这种方式,从参数说明看,可以通过device和device_id来指定具体要关联打开的alsa设备。
通过阅读代码和实际测试发现:
如果设置了device_id参数的话,device参数就不会生效,而是会先生成一个默认的profile set,然后根据其中每个profile配置里的设备字串模版,把device_id值带入,然后尝试打开设备。
而这个默认的profile set内容来自于 /usr/share/pulseaudio/alsa-mixer/profile-sets/default.conf,其中配置了不同的mapping,比如这种

[General]
auto-profiles = yes
...
[Mapping analog-stereo]
device-strings = front:%f hw:%f
channel-map = left,right
paths-output = analog-output analog-output-lineout ...
paths-input = analog-input-front-mic analog-input-rear-mic ...
priority = 10

auto-profiles 配置为yes的话,就会自动为每个mapping创建一个profile。
然后在创建alsa-sink时,就会循环的对每个profile中的device-strings带入device_id参数。比如device_id设置为1,front:1 hw:1 就会被尝试打开。
其实可以看出来,这个默认的配置并不能和咱们嵌入式开发板上的声卡配置相匹配。
在不自己重新配置的情况下,我怎么能打开hw:0,1 hw:0,2 这样的设备呢…

如果不使用device_id参数,直接配置device参数为hw:0,0或者 hw:0,1 这样,就会直接使用这个字串去打开alsa设备。
像这样 load-module module-alsa-sink device=hw:0,0
当然我们可以设置其他相关的音频参数 load-module module-alsa-sink device=hw:0,0 channels=2 rate=44100,也可以为这个alsa-sink指定名称 sink_name=Muisc-Playback
这样的话,只要在 system.pa 写入如下几行,就可以按需求配置出不同的alsa-sink对象了。

load-module module-alsa-sink device=hw:0,0 sink_name=Muisc-Playback
load-module module-alsa-sink device=hw:0,1 sink_name=Navigation-Playback
load-module module-alsa-sink device=hw:0,2 sink_name=Alarm-Playback

再来看一下加载module-alsa-card 模块这种方式,
从代码里可以发现,这种方式还是会先生成profile set,然后根据一个选中的 profile(active_profile),为其中每个output_mapping创建一个alsa-sink对象。
(input_mapping创建对应的alsa-source对象)
其实本人目前对于profile,mapping,path的概念也是一知半解。
从已知的情况来看,一个profile就是一组mapping的集合,一个mapping对应puseaudio中的一个sink或者source,而path则对应这sink或者source上的port。
path中定义了一些控制元素element,也就是和alsa mixer control element对应的。
从代码看来,alsa-sink创建后,会激活其中的一个port,会probe其中的element,pusleaudio只关注其中可以控制mute和volume的element,如果有这种类型的element,则会记录下来,在之后的volume和mute操作中,会通过这些element来使用硬件接口实现volume和mute。

如果按照默认的配置,因为 hw:0 这个设备字串可以成功打开,analog-stereo这个profile会被选中,module-alsa-card模块会用hw:0创建一个alsa-sink对象。然后probe analog-output path中指定的那些element,当然probe后也都是无效的。
前面也提到了,默认的profile和我们开发板的声卡配置是不能匹配的。而且我是希望创建多个alsa-sink的,所以参考原有的配置,并查找资料写了一个自己的配置
/usr/share/pulseaudio/alsa-mixer/profile-sets/my-default.conf(测试只写了2个mapping)

[General]
auto-profiles = no[Profile output:Music-Playback+output:Navigation-Playback]
description = multiple-sink-profiles
output-mappings = Music-Playback Navigation-Playback
priority = 10[Mapping Music-Playback]
device-strings = hw:%f,0
channel-map = left,right
paths-output = music-analog-output
priority = 9
direction = output[Mapping Navigation-Playback]
device-strings = hw:%f,1
channel-map = left,right
paths-output = navi-analog-output
priority = 9
direction = output

/usr/share/pulseaudio/alsa-mixer/paths/music-analog-output.conf是这样写的,navi-analog-output.conf类似

[Element Music Stream Vol]
switch = ignore
volume = merge[Element Music Stream Mute]
switch =mute
volume = ignore

其中 Music Stream Vol 和 Music Stream Mute 分别是 hw:0,0 这个卡的volume和mute的control element。
声卡0 的alsa mixer的控制元素,可以通过如下命令查看到

amixer -c 0 contents

这个 [Profile output:Music-Playback+output:Navigation-Playback] 是一个profile包含多个mapping的写法方式。
auto-profiles = no 是为了不给mapping在自动生成profile,不然的话,这个文件读出来会有3个profile,而且后两个自动生成的profile优先级会高于第一个。那样就不会选择第一个profile为active_profile了。(当然咱们也可以通过 module-alsa-card 的profile 指定active_profile)
通过指定自己的profile set方式来加载 module-alsa-card 模块:

load-module module-alsa-card device_id=0 profile_set=my-default.conf

会发现module-alsa-card 会根据profile的output-mappings为我们创建了对应的2个alsa-sink(加载多个的alsa-sink和alsa-source的方式都类似)

最后一种通过加载module-udev-detect 模块和第二种类似,只是在默认情况下,module-alsa-card 的参数没有设置profile set,那样就会使用默认的配置了。并且也没有看到有参数可以指定profile set,所以这个方式暂时不使用了。

#Puseaudio使用硬件接口控制volume和mute
pusleaudio最终还是需要通过alsa mixer 接口来控制volume和mute的,这样就需要pulseaudio知道对应的mixer control element。

如果使用直接加载 module-alsa-sink 的方式来创建alsa-sink的话,有一个control参数可以设置,代码中可以发现,通过这个control参数可以设置一个element,pulseaudio会去检测这个element的属性,看是否可以控制volume或者mute的。(代码在alsa-sink.c的find_mixer()函数中),但是如果需要volume和mute两个element,该如何设置呢,这个还不太清楚。

如果使用加载module-alsa-card 模块的方式在创建alsa-sink的话,就可以通过在path的配置中指定element。这样pulseaudio可以同时得到volume和mute的控制element。个人觉得如果需要使用硬件接口来控制volume和mute的话,还是需要这个方式吧。

#控制调试Pulseaudio
启动pulseaudio我用的这个命令,把能打印的log都打印出来。

pulseaudio --log-level=4 --daemonize=no --system --single-user --log-target=file:/skypine/pa.log --log-time &

pacmd可以通过protocal-native模块和pulseaudio交互。可以查询各种信息。用如下命令启动。启动后输入help就会有用法。

PULSE_RUNTIME_PATH=/var/run/pulse pacmd

#alsa-sink的选择
创建alsa-sink的时候,会有名称的。
使用paplay测试可以加 -d 参数,比如想用music那个alsa-sink就这样

paplay -d Muisc-Playback test.wav

如果是用API播放,pa_stream_connect_playback()第二次参数填alsa-sink的名称。

#遇到的一些问题
我的hw:0,1卡驱动里是配置固定48000采样率的。建立alsa-sink之后,如果送入44100采样率的数据发现播放没有声音了。
原因是,由于hw不支持,pulseaudio不能重新用44100参数打开设备,就会使用软件的resampler来重采样,然后默认配置的resample method是 speex-float-0。dump了一下resample的输出,发现全是0数据。后来换了一个resample方式,没问题了。板子上speex的库也是有的,resample数据的API返回值也正确,不知道为啥数据不对。暂时没继续看了。

使用自己配置的profile,创建出来的music alsa-sink,播放没有声音。
原因,从log看并没有什么不正常。仔细查了一下,发现alsa-sink在avtive port之后查询了一下 “Music Stream Mute” 这个element 的mute 状态。得到的结果是0(结果没错),然是接着通过alsa mixer API设置了mute状态为!0,alsa-sink被静音了。手动通过amixer 把这个element值设置回来就好了。但是不清楚代码逻辑为啥是这样的。
因为我这边不是一定需要用硬件控制mute啊,直接把 [Element Music Stream Mute] 中的 switch 设置为 ignore 也就不会有问题了。

alsa-sink播放的时候,经常会underrun,把log关掉或者输出到文件后会好一些,但是偶尔还是会出现。
查了一下log,发现alsa-sink线程在hw buffer数据充足,而且没有其他事件时,sleep了一个固定的时间,然后underrun了,线程又被alsa叫醒。
最简单的办法是加载 alsa-sink 时,tsched设置为0,这个值默认是1的。这样不sleep,就不会underrun,但性能上可能差一些吧。
其实看代码,sleep设置的时间是hw buffer 的数据时长 减去了一个 watermark 值(默认20ms),按道理应该可以在underrun之前结束sleep的啊。后面调整一下这个值,可能会有改善的。

Linux车机平台pulseaudio多alsasink配置相关推荐

  1. wince车机可以连接电脑吗_WINCE车机平台手机互联使用说明

    wince概述 wince是Windows CE的缩写.Windows Embedded Compact(即 Windows CE)是微软公司嵌入式.移动计算平台的基础,它是一个开放的.可升级的32位 ...

  2. linux车机软件市场,车机UI(用户界面)的发展现状

    电视.PC.手机.平板,消费电子市场每一块屏幕都曾创造出一个巨大的市场.屏幕本身当然没有那么大的威力,是内容,是基于同一系统稳定生态下的内容,才粘住了最广大的用户.长期被"忽略"的 ...

  3. 雷凌linux车机升级_绿老师学堂:15万合资车谁更“聪明”?体验思域/福克斯/雷凌车机...

    当汽车新四化成为共识,没有哪一家中国车企不想抓住这个产业变革的时机变道超车.同样是被认定的新趋势,可能还存在新能源的技术路径争论,自动驾驶时间表的争论,但是,对智能网联化的认可是毋庸置疑的. 借助博越 ...

  4. 远程调试在Linux车机中的应用

    导读 在软件开发过程中,调试是必不可少的环节,嵌入式操作系统的调试与桌面操作系统的调试相比有很大差别,嵌入式系统的可视化调试能力比桌面操作系统要弱一点.对于导航这种业务场景比较复杂的程序开发,可视化调 ...

  5. 安卓导航车机root方法_远程调试在Linux车机中的应用

    导读 在软件开发过程中,调试是必不可少的环节,嵌入式操作系统的调试与桌面操作系统的调试相比有很大差别,嵌入式系统的可视化调试能力比桌面操作系统要弱一点.对于导航这种业务场景比较复杂的程序开发,可视化调 ...

  6. linux车机按键学习,linux就该这么学

    前言 学习是一件苦差 我无意回避这个问题--学习本是件痛苦的事情,如果学习Linux真的很简单,那么必是骗子说的谎话,起码这不能给你带来高薪,打开电脑后沉思,是该聊会天那~还是追个美剧那~还是打盘LO ...

  7. linux车机系统怎么进工厂模式,工厂方法模式 - 跟JBPM学习设计模式_Linux编程_Linux公社-Linux系统门户网站...

    模式简介 工厂方法模式,定义一个用于创建对象的接口,让子类决定实例化那个类,其使一个类的实例化延迟到其子类中. 前边我们学习了简单工厂模式,简单工厂模式的最大优势在于工厂类中包含了必要逻辑判断,根据客 ...

  8. 雷凌linux车机ssh,OpenWRT自动挂载支持

    添加USB相关支持Kernel modules -> USB Support -> kmod-usb-core. ##默认已经选了 Kernel modules -> USB Sup ...

  9. 雷凌linux车机升级_丰田雷凌原车高德地图升级方法(附说明)

    丰田雷凌原厂导航的地图用的是高德地图离线版,升级方法是将地图卡插上连网的电脑上手动更新.地图卡插上电脑后,卡的根目录下有两个升级文件:"导航地图升级下载工具Win版.exe"和&q ...

最新文章

  1. 精进不休 .NET 4.0 (4) - C# 4.0 新特性之命名参数和可选参数
  2. Hadoop安装记录(伪分布式)
  3. C语言执行shellcode的五种方法
  4. PHP require和include的区别
  5. Hibernate 基础配置及常用功能(二)
  6. 二叉树第i层中的所有结点_讲透学烂二叉树(二):图中树的定义amp;各类型树的特征分析...
  7. Mybatis为实体类定义别名typeAliases
  8. xshell连不上虚拟机linux的解决办法
  9. [机器学习]推荐系统介绍
  10. Shiro框架(一)-Shiro概述
  11. 虚拟偶像出道,技术「造星」推动下的粉丝经济
  12. java多行注释_Java注释:单行、多行和文档注释
  13. LG-P2342 叠积木
  14. “创意不是想出来的”
  15. 「光驱」先锋 DVR-111XL 刻录
  16. 《Boosting Data-Driven Evolutionary Algorithm With Localized Data Generation》笔记
  17. 项目oms之----阿里巴巴字体图标运用详解 (含:彩色图标svg运用)
  18. KRnano打开黑屏: FATAL ERROR,【解决办法】
  19. java 虚拟机(3)
  20. Java程序员面试题集(131-135)

热门文章

  1. 智能手机降价杀:你方唱罢我登台 搞死一个少一个
  2. 1G→2G→3G→4G→5G:一部波澜壮阔的移动通信史
  3. 【随堂习题1】用Python编写猜拳游戏
  4. 高精度倾角传感器测量原理
  5. 计算机哪些证书可以在网上考?
  6. 拆解VCM音圈马达,原理、结构
  7. web JSP的动态交互 cs与bs结构的区别, bs结构的超详细解释,jsp的表单验证
  8. 传智oracle,传智播客Oracle笔记
  9. MySQL的视图的相关介绍
  10. 2021年低压电工考试资料及低压电工复审模拟考试