Linux车机平台pulseaudio多alsasink配置

2023-11-11

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/1
  Subdevice #0: subdevice #0
card 0: kasaudiocard [kas-audio-card], device 1: Navigation Playback (*) []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: kasaudiocard [kas-audio-card], device 2: Alarm Playback (*) []
  Subdevices: 1/1
  Subdevice #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/1
  Subdevice #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的啊。后面调整一下这个值,可能会有改善的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux车机平台pulseaudio多alsasink配置 的相关文章

  • 命令行参数中的“-”(破折号)有什么魔力?

    例子 创建 ISO 映像并将其直接刻录到 CD mkisofs V Photos r home vivek photos cdrecord v dev dev dvdrw 更改到上一个目录 cd 侦听端口 12345 并解压发送到该端口的数
  • 类似 wget 的 BitTorrent 客户端或库? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 是否有任何
  • 代码::块 - 警告:GDB:无法设置控制终端:不允许操作

    我已经通过官方存储库在 Ubuntu 14 04 中安装了 Code Blocks 13 12 当我编译时 一切正常 但是当我调试时 shell 中会显示以下消息 警告 GDB 无法设置控制终端 操作不正确 允许的 程序执行到断点 但当我执
  • 访问 Linux 线程(pthreads)的本地堆栈

    我目前正在实现一个使用多线程但对总内存消耗有要求的应用程序 我希望有一个主线程执行 I O 并有几个工作线程执行计算 目前 我在主堆栈上有几个可供工作人员访问的数据结构 我使用 OpenMP 进行工作分配 由于主 工作者模式不能很好地与 O
  • 在 C 中使用 sqrtf():“未定义对‘sqrtf’的引用”

    我正在使用Linux Ubuntu 12 04 https en wikipedia org wiki Ubuntu version history Ubuntu 12 04 LTS 28Precise Pangolin 29 Precis
  • 如何从脚本向 sudo 提供密码?

    请注意 这是在我的本地计算机上运行的来宾虚拟机 VBox 我不担心安全性 我正在编写一个将在 Linux Ubuntu VM 上执行的脚本myuser用户 该脚本将在下面创建一个非常大的目录树 etc myapp 目前我必须手动完成所有这些
  • 操作系统崩溃的常见原因[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有兴趣了解 操作系统崩溃 不限于Windows崩溃 最常见的技术原因 从操作系统编程的角度 有哪些 我正在寻找一个不像 打开太多应用
  • Linux下的C#,Process.Start()异常“没有这样的文件或目录”

    我在使用 Process 类调用程序来启动程序时遇到问题 可执行文件的层次结构位于 bin 目录下 而当前工作目录需要位于 lib 目录下 project bin a out this is what I need to call lib
  • Bash 中 $() 和 () 之间的区别

    当我打字时ls l echo file 支架的输出 这只是简单的回显 被获取并传递到外部ls l命令 就等于简单的ls l file 当我打字时ls l echo file 我们有错误 因为不能嵌套 内部外部命令 有人可以帮助我理解之间的区
  • 从 Linux 命令行发送 SNMP 陷阱消息

    Folks 我需要从 Linux 命令行使用此命令 snmptrap 将自定义消息发送到陷阱侦听器 我需要根据用户设置在 v1 和 v2c 中发送相同的消息 这是我发现的 For v1 snmptrap v 1 c Tas hostname
  • Alsa 带有来自调制解调器的 PCM 接口

    我有一个基于 imx28 CPU 的定制板 CPU 的串行端口连接到调制解调器的 PCM 输出 我必须为调制解调器的 PCM 接口开发一个驱动程序 使其成为 ALSA SoC 的一部分 您能指出内核树 中与我的设置重新组合的一些驱动程序吗
  • 如何使用libaudit?

    我试图了解如何使用 libaudit 我想接收有关使用 C C 的用户操作的事件 我不明白如何设置规则 以及如何获取有关用户操作的信息 例如 我想获取用户创建目录时的信息 int audit fd audit open struct aud
  • 测试linux下磁盘空间不足

    我有一个程序 当写入某个文件的磁盘空间不足时 该程序可能会死掉 我不确定是否是这种情况 我想运行它并查看 但我的测试服务器不会很快耗尽空间 有什么办法可以嘲笑这种行为吗 看起来没有任何方法可以在 Ubuntu 中设置文件夹 文件大小限制 并
  • 使用 sed 将 old-link-url 替换为 new-link-url

    我正在 bash 中编写一个脚本 将 old link url 替换为 new link url 我的问题是 sed 由于斜杠而无法替换 url 如果我只输入一些文字就可以了 my code sed e s old link new lin
  • 在 Ubuntu 上纯粹通过 bash 脚本安装 mysql 5.7

    我想要一个无需任何手动输入即可安装 MySQL 5 7 实例的 bash 脚本 我正在关注数字海洋教程 https www digitalocean com community tutorials how to install mysql
  • 在中断时获取 current->pid

    我正在Linux调度程序上写一些东西 我需要知道在我的中断到来之前哪个进程正在运行 当前的结构可用吗 如果我在中断处理程序中执行 current gt pid 我是否可以获得我中断的进程的 pid 你可以 current gt pid存在并
  • Xenomai 中的周期性线程实时失败

    我正在创建一个周期性线程 它在模拟输出上输出方波信号 我正在使用 Xenomai API 中的 Posix Skin 和 Analogy 我使用示波器测试了代码的实时性能 并查看了方波信号 频率为 1kHz 的延迟 我应该实现 250us
  • 如何仅将整个嵌套目录中的头文件复制到另一个目录,在复制到新文件夹后保持相同的层次结构

    我有一个目录 其中有很多头文件 h 和其他 o 和 c 文件以及其他文件 这个目录里面有很多嵌套的目录 我只想将头文件复制到一个单独的目录 并在新目录中保留相同的结构 cp rf oldDirectory newDirectory将复制所有
  • Linux 文本文件操作

    我有一个格式的文件 a href a href a href a href 我需要选择 之后但 之前的文本 并将其打印在行尾 添加后 例如 a href http www wowhead com search Su a a a a a
  • 使用命令行将 MediaWiki 维基文本格式转换为 HTML

    我倾向于编写大量文档 因此 MediaWiki 格式对我来说很容易理解 而且比编写传统 HTML 节省了我很多时间 然而 我也写了一篇博客 发现一直从键盘切换到鼠标来输入正确的 HTML 标签会增加很多时间 我希望能够使用 Mediawik

随机推荐

  • .Net WebAPI JWT身份验证

    一 开发环境 VS2017 enterprise win10 Pro 64 net 4 6 2 二 开发过程 1 使用VS2017 创建 netframework项目 选择WebApi 2 从Nuget包中搜索并安装JWT 3 在Model
  • 动态路由-BGP的基础配置

    一 给每个路由器配置ip地址 AR6 1 1 添加ip地址 interface GigabitEthernet0 0 0 ip address 1 1 1 1 255 255 255 0 2 配置BGP对等体 bgp 100 配置bgp的A
  • 使用PyQt(Python+Qt)+moviepy开发的视频截取、音视频分离、MP4转GIF动图工具免费下载分享

    专栏 Python基础教程目录 专栏 使用PyQt开发图形界面Python应用 专栏 PyQt入门学习 老猿Python博文目录 在因博文素材需要将软件操作制作成动画时 发现网上相关绿色使用工具都需要注册 否则动态上就会打上各种LOGO 无
  • C++ 类成员指针

    1 成员指针简介 成员指针是C 引入的一种新机制 它的申明方式和使用方式都与一般的指针有所不同 成员指针分为成员函数指针和数据成员指针 2 成员函数指针 在事件驱动和多线程应用中被广泛用于调用回调函数 在多线程应用中 每个线程都通过指向成员
  • IIS错误页面隐藏版本信息 - Web.Config customErrors配置

    目录 背景 分析暴露原因 解决办法 扩展学习customErrors使用方法 customErrors元素配置结构 元素属性 Mod 属性选项 示例 参考文章 背景 项目现按照国网的要求 测试后发现系统错误页面存在服务器版本号泄露 不允许部
  • Java Servlet的主要功能和作用是什么?

    Servlet 通过创建一个框架来扩展服务器的能力 以提供在 Web 上进行请求和响应服务 当客户机发送请求至服务器时 服务器可以将请求信息发送给 Servlet 并让 Servlet 建立起服务器返回给客户机的响应 当启动 Web 服务器
  • Kali Linux 2020.1修改Root用户密码

    背景信息 多年以来 Kali从BackTrack继承了默认的root用户策略 作为对Kali工具和策略的评估的一部分 因此Kali 决定对此进行更改 并将Kali移至 传统默认非根用户 模型 那如果我们因某些情况想开启Root用户这应该如何
  • facebook stetho Android调试工具

    什么是Stetho 官网简介 Stetho is a debug bridge for Android applications enabling the powerful Chrome Developer Tools and much m
  • 如何利用matlab神经网络进行水量预测

    数据收集 百度搜索EPS数据库登陆 我们选择进入城市数据库 我们的目的是要进行某年水量预测 我们的目的是知道了某一年的土地 人口等信息 就可以预测出该年的用水量 因此我们需要搜集一些信息用来训练 可以多选几年如2003 2017 然后点击下
  • 13 集成测试之自顶向下集成测试方法

    自顶向下集成测试方法 前言 深度优先集成方法 宽度优先集成方法 总结 前言 自顶向下集成方法可以采取深度优先或者宽度优先策略 深度优先集成方法 深度优先从最左边分支自上而下开始测试并向上结合 测试完一个分支后再测试下一个分支 如图测试顺序为
  • 渗压计工作原理及选型

    渗压计适合埋设在水工建筑物和基岩内 或安装在测压管 钻孔 堤坝 管道或压力容器中 以测量孔隙水压力或液位 主要部件均采用特殊钢材制造 适合在各种恶劣环境中使用 一般型号后缀为标准型 可以为低量程型和为通气 差压 型 另可根据客户要求提供高压
  • Hypertable 简介 一个 C++ 的Bigtable开源实现

    1 Introduction 随着互联网技术的发展 尤其是云计算平台的出现 分布式应用程序需要处理大量的数据 PB级 在一个或多个云计算平台中 成千上万的计算主机 如何保证数据的有效存储和组织 为应用提供高效和可靠的访问接口 并且保持良好的
  • scss中的样式复用:继承;占位符;混合宏

    文章目录 一 使用 extend实现样式复用 继承 二 使用占位符实现样式复用 占位 三 使用混合宏实现样式复用 混合宏 四 参数运算符 待更新 类名复用 未验证 待更新 react中使用sass 了解css in js解决方案 在reac
  • 【Pandas 数据查找函数 详解】

    本文介绍了Pandas数据查找常用函数 掌握了这些函数的应用 让你在数据处理时 手到擒来 游刃有余 目录 一 查找数据位置 s str find 和s str index 函数 二 数据的查找判断 1 判断开头或结尾是否是指定字符串s st
  • 保姆级Obsidian学习教程【超完整,小白必备】

    前言 本篇文章学习视频来源 沙牛obsidian优质课程 学 习 软 件 obsidian 课 程 对 应 资 源 云盘资源 说 明 Obsidian是基于Markdown文件的本地知识管理软件 并且开发者承诺Obsidian对于个人使用者
  • java integer long 转换_long(Long)与int(Integer)之间的转换

    1 将long型转化为int型 这里的long型是基础类型 long a 10 int b int a 2 将Long型转换为int 型的 这里的Long型是包装类型 Long a 10 int b a intValue 3 将Long型转
  • 编译GDB --enable-targets=all --enable-64-bit-bfd

    这次尝试才用一种新的BLOG发帖 大家都可以把要发到BLOG的文章投递到MAILLIST 然后大家REVIEW 等REVIEW的差不离了 再发到BLOG上 欢迎大家帮忙review 编译GDB teawater hellogcc 1 取得源
  • 2.1python中的赋值运算符和比较运算符

    在程序中 使用赋值运算符可以帮助我们更加高效的完成一些需要多行程序完成的工作 使用比较运算符可以让程序员通过比较更加明白所编程序是否与自己的所思考的相同 1 首先 我们先看一下赋值运算符的具体内容 如下 赋值运算符符号 含义 a b b a
  • 微信H5(公众号)跳转微信小程序实现及其传参

    1 使用微信开放标签 wx open launch weapp 跳转
  • Linux车机平台pulseaudio多alsasink配置

    https www freedesktop org wiki Software PulseAudio 官网上的介绍是这样的 pulseaudio 是一个POSIX操作系统上的声音系统 是音频应用的代理 它允许你对音频数据 在从应用传递到硬件