LWN:PipeWire,新一代的Linux audio/video bus_pipewire和pulseaudio区别-程序员宅基地

技术标签: linux  pulseaudio  audio  

关注了就能看到更多这么棒的文章哦~

PipeWire: The Linux audio/video bus

March 2, 2021

This article was contributed by Ahmed S. Darwish
DeepL assisted translation
https://lwn.net/Articles/847412/

十多年来,PulseAudio 一直凭借其主流的音频混音(audio mixing)和路由守护进程(routing daemon)以及其音频 API 来服务于 Linux 桌面。遗憾的是,PulseAudio 的内部架构并不适合日益增长的沙盒应用场景(sandboxed-applications use case),尽管人们一直在努力改善。PipeWire 部分来源于这些尝试,作为一个新的 daemon(守护进程),将在即将到来的 Fedora 34 版本中取代 PulseAudio。这个改变值得介绍一下。

过去,Fedora 8 在 2007 年底切换到 PulseAudio 的过程并不顺利。Linux 的长期用户仍然记得,当时人们对这个 daemon 的印象就是会导致系统音频无法工作。在经历了那么一个坎坷的开端之后,PulseAudio 最终成为了 Linux 声音服务器(sound-server)斗争中的赢家。它提供了一个原生的客户端音频(native client audio) API,同时也能支持那些正在使用当时常见的音频 API 的应用程序–包括 raw Linux ALSA sound API,这种 API 通常只允许有一个应用程序访问声卡。PulseAudio 会将多个应用程序的音频流混合起来(mix),作为音频管理的中心节点,提供了细粒度的设置功能,支持无缝路由(seamless routing)到蓝牙、USB 或 HDMI。它对自己在 Linux Desktop 中的定位是相当于 Windows Vista 的用户模式音频引擎(user-mode audio engine)和 macOS CoreAudio daemon。

Cracks at PulseAudio

到了 2015 年,PulseAudio 事实上仍是 Linux 的缺省音频守护进程,但危机也开始产生了。逐渐转向沙盒化的桌面应用,对其原始设计来说是致命的。因为通过 PulseAudio,一个应用程序就可以窥探到其他应用程序的音频、对麦克风进行无中介的(unmediated)访问、或者加载 server modules 来干扰其他应用程序。人们试图对 PulseAudio 进行修复,也就是修改 access-control layer 和 per-client memfd-backed transport。这都是必要改动,但仍然还不足以隔离各个客户端的音频。

大约在那个时候,PulseAudio 的核心开发人员之一 David Henningson 退出了此项目。他对于 PulseAudio 守护进程对沙盒应用场景的不适应、以及它对音频路由的决策的策略以及混合音频的机制感到沮丧。在他发言的末尾,他提出,这些问题是否应该让我们承担创建一个新的、必需的 Linux audio daemon 的阵痛了:

在软件中没有什么是不可能的,但如果要对 PulseAudio 的架构设计进行大改动,从而用正确的方式来支持所有这些要求(而不是 "在上面再加一个 layer"[…])将是非常困难的,所以我的判断是,从头开始写新的东西会更容易。

而且我确实认为可以写出一些从 PulseAudio、JACK 和 AudioFlinger 中吸取了精华的东西,从而得到一个既适用于移动设备又适用于桌面设备的东西;并且适用于专业音频(pro-audio)、游戏、低功率音乐播放(low-power music playback)等。[…]我认为,作为一个开源社区,开发出这样的声音服务器会更有价值。

PulseVideo to Pinos

与此同时,GStreamer 的联合创始人 Wim Taymans 被安排开发一个 Linux service,用来协调网络浏览器对摄像设备的访问权。最初,他把这个项目称为 PulseVideo。这个名字背后的想法很简单:类似于 PulseAudio (为了协调对 ALSA 声音设备的访问),PulseVideo 则是为了协调和复用 Video4Linux2 摄像头设备节点。

不久之后,Taymans 发现了 William Manley 创建的一个名称类似的 PulseVideo 原型程序[视频],并帮助其将其中必须的 GStreamer 功能加了进来。为了避免与 PulseAudio 的名称冲突,并且由于它的功能已经扩展过,不再是针对 camera access 的了,所以 Taymans 后来将项目改名为 Pinos(来自于他在西班牙所居住的城市)

Pinos 是建立在 GStreamer pipeline 之上的,使用了早期对 Manley 的原型程序增加的一些基础设施代码。使用了 D-Bus 加上传递文件描述符来用于进程间通信。在 GStreamer 2015 会议上,Taymans 向与会者描述了 Pinos 架构,并进行了多个应用程序同时访问系统 camera 输入数据的演示。

由于其灵活的、基于 pipeline 的、文件描述符传递的架构,Pinos 还可以支持反向的应用,也就是多媒体广播:应用程序可以通过传递 memfd 或 dma-buf 文件描述符来 "upload" 多媒体流(media stream)。然后,多媒体流可以被进一步处理并分发到其他应用程序和系统多媒体 sink 设备,如 ALSA 声音设备。

虽然只是顺便提了一下,不过这个双向发送的能力,以及跨应用程序发送 stream 的能力使得 Pinos 可以作为一个通用的音频/视频总线(generic audio/video bus),用来在相互隔离的、可能是 sandbox 的用户进程之间有效地传递多媒体内容。因此,只要适当扩展一下的话,Pinos 就可能替代 PulseAudio 了。Taymans 被与会者明确地问到了这个问题[视频,31:35],他回答道:"取代 PulseAudio 不是一件容易的事,它不在目前的考虑之中[…],但[Pinos]可以有广泛用法,所以它以后可以做更多的事情"。

随着前文所讨论的 PulseAudio 的不足之处越来越多,这里说的"以后可以做更多" 就很快变成有需要的了。

PipeWire

到了 2016 年,Taymans 开始重新思考 Pinos 的基础设计,将它的目标扩展为标准的 Linux 音频/视频守护进程。这包括需要用到 "大量小 buffer" 的低延迟音频用例(low-latency audio use case),这些以前通常是由 JACK 支持的。这里就有两个主要问题需要解决了。

首先,核心守护进程(core daemon)和客户端库(client libraries)对 GStreamer 元素和流水线(elements and pipelines)的依赖性变成了一个麻烦。GStreamer 中有大量的底层逻辑来确保实现中的灵活性。处理 GStreamer pipeline 的过程,这都是在 Pinos 的实时线程的上下文中完成的,那么这些底层逻辑就可能会引入一些隐含的内存分配(implicit memory allocation)、线程创建和等待 lock 的行为。众所周知,这些都是会对硬实时代码(hard realtime code)所必须具有的可预测性而产生负面影响的。

为了在满足硬实时要求的同时,也实现 GStreamer pipeline 的部分灵活性,Taymans 创建了一个更简单的多媒体流水线框架,并将其称为 SPA——简单插件 API(Simple Plugin API)[PDF]。该框架的设计中为了确保能在实时线程(如 Pinos media processing threads)中可靠地运行,设置了一个永远不应该超过的时间预算(time budget)。SPA 不加快任何内存分配,相应的,内存分配等就变成了 SPA 框架应用程序(framework application)的唯一责任。

每个 node 都有一组定义明确的状态。其中一个状态就是用来配置这个 node 的所有 port、format 和 buffer 的,这是由 main thread(non-realtime)来完成的;还有一个状态用来供 host 分配这个 node 在完成配置之后所需的所有 buffer;另外还有一个状态,就是实际在实时线程中完成处理工作。在 streaming 的过程中,如果任何一个 media pipeline node 的状态发生了变化(比如发生了某个 event),就可以通知到实时线程(realtime threads),从而将控制权切换回 main thread 来进行重新配置(reconfiguration)。

其次,不再使用 D-Bus 作为 IPC protocol。取而代之的是一个受 Wayland 启发,通过 Unix 域套接字实现的原生完全异步协议(native fully asynchronous protocol)——但是不会使用 XML serialization。Taymans 需要的是一个简单且能保证硬实时的协议。

当集成了 SPA framework、开发了 native IPC protocol 之后,这个项目已经超出了它最初的目的,它从一个用来共享 camera access 的 D-Bus daemon 变成了一个完全实时的音频/视频总线(full realtime-capable audio/video bus)。因此,它被重新命名为 PipeWire,这个名字反映了它作为基于 pipeline 的多媒体共享和处理引擎的新地位。

Lessons learned

从一开始,PipeWire 的开发者就利用了一套来自当前音频守护进程的经验,包括了 JACK、PulseAudio 和 Chromium OS 音频服务器(CRAS)。与 PulseAudio 的有意将 Linux 音频环境分为消费级与专业实时音频不同,PipeWire 从一开始就被设计成可以同时处理两种音频。为了避免 PulseAudio sandbox 的限制,它天生就关注了安全性:每个 PipeWire node(其中包含若干个 SPA nodes)里面都有一个 per-client permission bitfield(每个客户端都有相应的 bit 来配置权限)。这种具有安全意识的设计就可以简单而安全地与 Flatpak portals 集成起来了。沙箱应用权限接口(sandboxed-application permissions interface)现在也升级成为了一个 freedesktop XDG 标准。

同 CRAS 和 PulseAudio 一样(但与 JACK 不同),PipeWire 使用了基于定时器的音频调度(time-based audio scheduling)。一个可以在运行时重新动态配置的定时器被用来安排唤醒(scheduling wake-ups)来填写 audio buffer(音频缓冲区),而不是依赖固定间隔时间的声卡中断。除了省电的好处外,这样一来 audio daemon 就可以提供动态延迟(dynamic latency)了:对于需要省电的场景和消费级音频(如音乐播放),可以设置较高延迟;对于延迟敏感的工作场景(如专业音频,即 professional audio),可以设置低延迟。

与 CRAS 类似、但与 PulseAudio 不同的是,PipeWire 不是基于 audio-buffer rewinding(音频缓冲区重写)机制的。当基于定时器的音频调度在使用非常大的 buffer 时(就像 PulseAudio 一样),就需要能支持重写声卡中的 buffer,以便对意料之外的事件(如新加入的音频流或者音频流的音量发生了变化)能够提供低延迟响应(low-latency response)。这是必须撤销(revoke)已经发送到音频设备的那个大 buffer,并提交一个新的 buffer。这导致代码复杂性显著增加,也会有更多的corner case需要处理。PipeWire 和 CRAS 都将 latency/buffering 的最大值设置得很小,从而完全没有必要进行 buffer rewinding 了。

与 JACK 一样,PipeWire 选择了外部会话管理器(external-session-manager)。专业音频用户通常会在会话管理程序(如 Catia 或 QjackCtl)中构建自己的音频流水线(audio pipeline),然后让音频守护进程来根据最终设置来执行。这样做的好处是将 policy(也就是如何构建媒体流水线)与 mechanism(音频守护进程如何执行流水线)两者分开了。在 GUADEC 2018 上,开发者明确请求 Taymans[视频,23:15]让 GNOME 以及其他可能的外部守护进程来控制 audio stack 中的相关部分。一些系统集成方已经遇到了问题,因为 PulseAudio 的音频路由策略决策是深深藏在其内部模块代码中的。这也是 Henningson 的退出邮件中提到的痛点之一。

最后,顺应过去十年出现的多个有影响力的系统守护进程的趋势,PipeWire 大量使用了 Linux 内核专用的 API。这包括 memfd、eventfd、timerfd、signalfd、epoll 和 dma-buf——所有这些都将 "文件描述符,file-descriptor" 作为系统中 event 和 shared buffer 的主要标识符。PipeWire 可以 import dma-buf 文件描述符,这是其能高效实现 Wayland 抓屏和录屏的关键。对于 4K 和 8K 这些大屏幕,CPU 不需要碰那些非常大的 GPU buffer。GNOME mutter(或其他类似的应用程序) 会传递一个 dma-buf 描述符供 PipeWire 的 SPA pipeline,用来进行进一步的处理和采集。

Adoption

native PipeWire API 从这个项目的 0.3 版本就被定为 stable 了。通过 PipeWire ALSA 插件就可以支持原有的 raw ALSA 应用程序。如果同时安装了 native PipeWire 和 PipeWire JACK library,则通过重新实现的 JACK 客户端函数库和 pw-jack 工具就能支持使用了 JACK 的应用程序。使用了 PulseAudio 的应用程序则通过 pipewire-pulse 守护进程来支持,该守护进程会监听 PulseAudio 自己的 socket 并转为 native communication protocol。这样,那些使用了自带的 native PulseAudio client libraries 的容器化桌面应用程序仍可以得到支持。WebRTC 是所有主流浏览器使用的通信框架(代码),支持了 native PipeWire support for Wayland screen sharing, 并通过 Flatpak portal 进行协调(mediate)。

下图显示了在 Arch Linux 系统上使用 pw-dot 工具 生成的 PipeWire 多媒体流水线,经过了一些美化。图中可以看到组合了 PipeWire-native 和 PulseAudio-native 的应用程序。

左边,GNOME Cheese 和用 gst-launch-1.0 创建的 GStreamer pipeline instance 都在并行访问同一个摄像头录制的数据。中间,Firefox 正在使用 WebRTC 和 Flatpak portal 共享屏幕内容(用于 Jitsi 会议)。右边的 Spotify 音乐播放器(是一个 PulseAudio 应用程序)正在播放音频,这些音频被路由传送到系统默认的 ALSA sink,并且 GNOME Settings(是另一个 PulseAudio 应用程序)正在实时监控该 sink 的左/右声道状态。

在各大 Linux 发行版中,Fedora 从 Fedora 27 版本开始就提供了 PipeWire 守护程序(仅用于 Wayland 抓屏)。Debian 提供了 PipeWire 包,但不支持替代 PulseAudio 或 JACK。Arch Linux 在其仓库中提供了 PipeWire,并且如果用户需要的话,可以使用官方提供的其他包来帮助实现替换 PulseAudio 和 JACK。同样,Gentoo 也为替换这两个守护进程提供了大量的文档。即将发布的 Fedora 34 版本将是第一个默认用 PipeWire 完全替换(开箱即用) PulseAudio 的 Linux 发行版。

总的来说,这是 Linux 多媒体领域的一个关键时刻。虽然开源是一个关于技术的故事,但它同时也是一个关于努力创造技术的人的故事。值得指出的是,PulseAudio 和 JACK 的开发者都有一个共识,那就是 PipeWire 和它的作者在做正确的事情。即将发布的 Fedora 34 应该就是一个试金石,关乎 PipeWire 今后 Linux 各大发行版中能否得到采用。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Linux_Everything/article/details/114909053

智能推荐

Sparkstreaming获取Kafka数据源的两个报错_spark kafka java.lang.nosuchmethoderror: scala.pro-程序员宅基地

文章浏览阅读648次。Sparkstreaming获取Kafka数据源的两个报错:java.lang.NoSuch MethodError: scala.Product. $ init $(Lscala/Product;)V 和 wrong number of type parameters for overloaded method value createDirectStream with alternatives:1.报错1:java.lang.NoSuch MethodError: scala.Product. $ i_spark kafka java.lang.nosuchmethoderror: scala.product.$init$(lscala/product

Markdown编辑较实用的总结进阶版技巧_markdown 进阶-程序员宅基地

文章浏览阅读86次。基本操作的传送门 Golddsaasd # 关于标题# 这是一级## 这是二级### 这是三级# 列表常用```*空格```or```1.空格```* 这是应用* 这又是* 这还是1. 这是2. 这也是3. 这还是**双击回车2次取消**# 加粗和斜体等快捷键 - 加粗 `Ctrl + B` - 斜体 `Ctrl + I` - 引用 `Ctrl + Q` - 插入链接 `Ctrl + L` - 插入代码 `Ctrl + K` _markdown 进阶

基于Freertos与lwip移植FreeModbusTcp协议_freertos+modbustcp-程序员宅基地

文章浏览阅读982次,点赞21次,收藏26次。基于FreeRTOS的N32G457VEL7之LWIP网络协议栈移植-程序员宅基地。_freertos+modbustcp

uCGUI 5.22 在stm32 上的移植_寄存器版本的lcdconf_lin_template-程序员宅基地

文章浏览阅读2.3k次。时间匆匆呀,yaoxiang_寄存器版本的lcdconf_lin_template

AttributeError: 'DistributedDataParallel' object has no attribute 'blahblah'_attributeerror: 'lightningdistributeddataparallel'-程序员宅基地

文章浏览阅读3.7k次。Pytorch DDP would fail when using the parameters directly to calculate the loss.These are my scripts:# train.py:class Model(nn.Module): def __init__(self, params): ... self.xnli_proj = nn.Linear(dim, 3)...model = Model(params)output = model.x_attributeerror: 'lightningdistributeddataparallel' object has no attribute

解决RequestParam.value() was empty on parameter 0-程序员宅基地

文章浏览阅读2.4k次,点赞4次,收藏6次。解决RequestParam.value() was empty on parameter 0_requestparam.value() was empty on parameter 0

随便推点

element--el-input限制输入为数字且必须大于0_el-input只能输入大于0的数字-程序员宅基地

文章浏览阅读1.9k次。【代码】element--el-input限制输入为数字且必须大于0。_el-input只能输入大于0的数字

HDU - 6430 TeaTree-程序员宅基地

文章浏览阅读236次。题目链接:HDU - 6430水题。显然一个数字的因子不会太多。暴力求出每个数字的因子,然后从子树线段树合并即可。每次合并的时候更新答案。AC代码:#pragma GCC optimize("-Ofast","-funroll-all-loops")#include<bits/stdc++.h>//#define int long longusing namespac..._hdu - 6430

python 使用dce/rpc-程序员宅基地

文章浏览阅读636次。资料下载这里在线看其中的PDF转载于:https://www.cnblogs.com/kkindof/archive/2012/06/11/2545274.html_dcerpc python执行命令

玩转ECS云盘 — 按量付费升级到包年包月云盘-程序员宅基地

文章浏览阅读486次。云服务器ECS当前支持两种计费方式的数据盘:云盘与按量付费云盘。云盘(包年包月云盘,预付费)随包年包月的实例购买时直接生成,不能卸载,生命周期与实例绑定,实例释放会一起释放。按量付费云盘(后付费)可以单独购买并且挂载到实例上,挂载后和云盘没有区别,挂载时可以选择是否随实例释放。当前云服务器ECS支持按量付费云盘升级为包年包月云盘,节省您的时间成本和...

DW手表如何更换电池?_dw手表怎么换电池-程序员宅基地

文章浏览阅读558次,点赞17次,收藏7次。更换石英表电池只需要简单的三步。_dw手表怎么换电池

Node+Vue毕设宠物商店管理系统(程序+mysql+Express)-程序员宅基地

文章浏览阅读349次,点赞7次,收藏9次。该系统将采用HTML、CSS、JavaScript和Vue.js作为前端技术实现动态用户界面设计,Node.js和Express框架作为后端技术支持商品管理、销售跟踪、客户服务等功能,并使用MySQL 5.7作为数据库存储产品信息、销售数据和客户资料。首先,该系统能够为宠物商店提供一个集成化的管理平台,通过电子化的操作方式,使商品入库、销售记录、库存管理等环节更加规范和高效,减少了人为错误和工作重复性,提升了工作效率。最后,该平台的建立还将推动宠物零售行业向数字化和信息化转型,探索新的管理模式和服务创新。

推荐文章

热门文章

相关标签