当前位置:首页>Linux>Linux多媒体进阶之旅(十八):多个播放设备,WirePlumber到底选谁?

Linux多媒体进阶之旅(十八):多个播放设备,WirePlumber到底选谁?

  • 2026-10-28 05:38:17
Linux多媒体进阶之旅(十八):多个播放设备,WirePlumber到底选谁?

点击下方👇关注 Android系统攻城狮

第211篇原创文章

持续迭代 | Android+Linux多媒体进阶体系

专栏·课程 知识体系持续更新


学习理念:一次理解一个知识点
所属系列:Linux多媒体进阶实战(第18篇)
框架分类:PipeWire篇
源码环境:PipeWire1.7  vs WirePlumber0.5
硬件平台:RK3588
主题内容:WirePlumber选择设备 + 建立Link
难度等级:★★★★☆
阅读时间:3.5分钟

  上一篇已经知道应用通过pw_stream创建播放流Node,并把Node注册到PipeWire服务端。此时Graph中已经有了Stream/Output/Audio播放流Node,但它还不能真正播放声音。

因为播放流已经进了Graph,但它还不知道声音应该送给谁。

  系统里可能同时存在板载扬声器、HDMI和蓝牙耳机,WirePlumber首先要从这些Audio/Sink设备中选出一个目标,然后再把播放流的输出Port连接到目标Node的输入Port。

  本文只回答两个问题:先决定:声音给谁,再决定:两边怎么连。

1

选择设备过程

  播放流Node和扬声器Node同时存在,只能说明两个对象都已经进入PipeWire对象体系,并不代表它们已经连接。可以把PipeWire Graph想成一个房间:播放流Node是“送声音的人”,Audio/Sink Node是“接声音的人”,两个人都在房间里,不代表已经牵上线。

  PipeWire负责维护Node、Port和Link组成的Graph,WirePlumber负责看播放流想去哪里、默认设备是谁、设备当前能不能用,然后做出目标选择。

  这里最容易混淆三个概念:default.audio.sink解决默认选谁,si-standard-link解决WirePlumber内部怎么组织这次连接,真正的数据通路则是PipeWire Graph里的Link。

2

播放流何时自动连接?

  播放流Node进入Graph后,并不是所有流都会自动寻找设备。WirePlumber先要判断:这个流是否允许系统帮它自动连接。

  WirePlumber会把可以参与连接的Node封装为Linkable Session Item,然后检查播放流的node.autoconnect。如果它为true,意思就是:这个播放流允许WirePlumber帮我自动找一个Sink。

  所以,pw_stream_connect()里的自动连接标志并不会直接选中Speaker。它只是给播放流留下一个“我允许自动连接”的意图,真正选择哪个设备的是WirePlumber。

  普通播放流进入会话后,WirePlumber可以触发select-target。如果后来发生默认设备变化、蓝牙耳机接入、HDMI变化或者新的Linkable对象进入Graph,WirePlumber还会进行Linking rescan,再重新检查是否需要选择目标。

播放流负责允许自动连接,WirePlumber负责帮你找设备。

3

如何选播放设备?

  最关键的问题:如果系统里有多个Sink,WirePlumber到底选谁?最容易理解的方法,是把它看成一个有明确顺序的目标查找过程。

  第一优先级是播放流自己已经指定目标,例如target.object或node.target。

  如果没有指定目标,WirePlumber再检查默认Audio/Sink。默认设备来自Default Nodes策略,其中default.configured.audio.sink更接近用户希望使用哪个设备,default.audio.sink则表示当前条件下实际选中的默认Sink。

  如果默认目标也不可用,find-best-target.lua会遍历候选Linkable对象。候选设备至少要满足:媒体类型一致、数据方向能够对接、canLink()检查通过,如果Node关联了设备Profile和Route,还要确认当前Route确实可用。

  候选设备都通过检查后,再比较priority.session。数值更高的设备更优先,如果相同,则继续比较item.plugged.usec,较晚接入的设备优先。

  不要把priority.session和priority.driver混淆,前者帮助WirePlumber知道:声音送给哪个设备,后者用于Graph Driver相关的优先级选择。

4

如何保存Link状态?

  设备选好以后,WirePlumber只是回答了“连接谁”,还没有真正创建PipeWire Link,接下来需要把这次连接关系组织起来。

  播放场景中,播放流是输出端,目标Audio/Sink是输入端。link-target.lua根据方向确定两边角色,然后创建一个si-standard-linkSession Item。

  可以把si-standard-link理解成一张连接任务单。它保存谁输出、谁输入、媒体类型是什么,以及两边Port应该从什么上下文获取。播放流使用outputPort上下文,Audio/Sink使用inputPort上下文。

si-standard-link不是Graph的音频线,而是WirePlumber内部连接的管理对象。

5

Node的Port如何Link起来?

  真正的数据连接最终发生在Port和Port之间,比如一个立体声播放流可能有FL、FR两个输出Port,Speaker也有FL、FR两个输入Port,那么WirePlumber需要把左声道接左声道,右声道接右声道。

si-standard-link激活后,会先确认输出项和输入项仍然有效,然后取得两端Port列表。Port匹配优先选择相同声道;如果没有完全一致的声道,还会按内部评分规则寻找可连接的Port,并避免重复使用同一个输入Port。

  一旦Port匹配成功,WirePlumber就能得到创建Link所需的四个关键标识:输出Node ID、输出Port ID、输入Node ID和输入Port ID。

  随后WirePlumber调用wp_link_new_from_factory(),并把link-factory作为工厂名称传入。这里先得到WirePlumber侧的WpLink对象,再由它请求远端PipeWire服务端的Link Factory创建真正的PipeWire Link。

  新建的WpLink还需要激活。只有远端Link成功绑定并可以使用,PipeWire Graph中才真正出现播放流Node到Audio/Sink Node之间的连接。

6

总结

  WirePlumber建立播放Link,看起来涉及很多脚本、Session Item和对象,但本质只有两个问题:第一,声音给谁;第二,两边怎么连。

整个过程可以分成四步:

①发现播放流需要连接②按“指定目标→默认目标→最佳候选设备”选择Audio/Sink③创建si-standard-link保存“谁连接谁”④匹配两端Port,通过link-factory创建真实PipeWire Link。

  所以:default.audio.sink解决选谁,si-standard-link解决怎么组织连接,PipeWire Link解决真正传输数据。

一句话总结:WirePlumber先决定声音应该去哪个设备,再把这个决定转换成PipeWire Graph中的真实Link。

  到这里,上一篇创建出来的播放流Node,才真正接到了Audio/Sink Node。

若读者朋友发现有错误、疑问的地方,或者好的建议,欢迎拍砖!!!

★★★★★★★★★< END >★★★★★★★★★

欢迎加入知识星球:Android+Linux多媒体进阶体系2.0
专栏推荐
☞ 【专栏一】 基础原理系列
☞ 【专栏二】 Android车载音频系列
☞ 【专栏三】 Android编解码系列
☞ 【专栏四】 Android相机系列
☞ 【专栏五】 Android图形系列
☞ 【专栏六】 Android系统系列
☞ 【专栏七】 Linux车载多媒体系列
原创不易,谢谢支持~~

最新文章

随机文章