简介: CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀
专题四:Android15快速自定义与集成音效实战课 🚀
专题五:Android15音频策略实战课 🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉
🌻1.前言
本篇目的:
Linux PipeWire深度解析之pw_factory_create_object调用流程与实战。
要点概括
-
核心功能:通过已经绑定到客户端的Factory对象创建一个新的PipeWire远端对象。
-
工作机制:客户端拿到Factory代理后,调用pw_factory_create_object向服务端Factory发送创建请求,服务端根据type、version和props创建具体对象,并返回一个新的Proxy。
-
典型用途:通过Factory动态创建Node、ClientNode、ClientDevice、Adapter等对象,理解PipeWire对象创建链路。
pw_factory_create_object的本质是"通过Factory创建对象"。它不是音频数据处理接口,也不是Buffer接口,更不是直接访问ALSA、V4L2、BlueZ这类底层设备的接口。
它工作在PipeWire对象模型层。PipeWire内部很多对象并不是应用直接new出来的,而是通过Factory创建。Factory可以理解为对象创建入口,客户端通过Registry发现Factory,再通过Factory创建对应类型的对象。
它和pw_core_create_object很接近,但关注点不同。pw_core_create_object是通过Core指定factory_name创建对象;pw_factory_create_object是已经拿到Factory对象之后,通过这个Factory创建对象。前者更像"按名字找工厂再创建",后者更像"已绑定工厂后直接创建"。
它也不同于pw_stream_new_simple。pw_stream_new_simple是上层Stream封装接口,适合普通播放、录音应用;pw_factory_create_object更靠近PipeWire底层对象创建机制,适合理解Factory、Proxy、Resource、Registry之间的关系。
🌻2.应用场景与用法
pw_factory_create_object
是PipeWireFactory API中用于通过Factory创建远端PipeWire对象的接口。
它位于PipeWire客户端对象创建链路中。客户端先连接Core,通过Registry发现服务端暴露的Factory全局对象,再bind得到本地Factory代理。随后调用pw_factory_create_object,向PipeWire服务端发送对象创建请求。服务端Factory收到请求后,根据目标type、接口version和属性props创建具体对象,并把新对象以Proxy形式返回给客户端。
pw_factory_create_object用于通过已经绑定的Factory创建一个新的PipeWire远端对象。
函数原型
c
struct pw_proxy *pw_factory_create_object(struct pw_factory *factory,
const char *type,
uint32_t version,
const struct spa_dict *props,
size_t user_data_size);
参数说明
c
struct pw_factory *factory;
factory表示已经绑定到客户端的Factory代理对象。
它通常来自Registry bind流程。也就是说,客户端不是凭空构造factory,而是先从PipeWire服务端Registry中发现Factory全局对象,然后根据global id绑定得到pw_factory对象。
c
const char *type;
type表示要创建对象的接口类型。
它用于告诉Factory:客户端希望创建哪一类PipeWire对象。例如某些Factory可以创建Node类型对象,某些Factory可以创建Device类型对象,某些Factory可以创建ClientNode或ClientDevice类型对象。
c
uint32_t version;
version表示客户端希望使用的目标接口版本。
PipeWire对象接口是有版本的。客户端创建对象时需要声明自己期望的接口版本,服务端会根据Factory能力和协议兼容性处理该请求。
c
const struct spa_dict *props;
props表示创建对象时附带的属性字典。
它通常用于传递对象名称、媒体类型、Factory特定参数、节点属性、设备属性或模块需要的初始化配置。不同Factory识别的props不同,不能把所有属性都理解成通用参数。
c
size_t user_data_size;
user_data_size表示为返回的Proxy附加分配的用户数据大小。
如果应用需要在Proxy后面附带私有数据,可以设置该值。如果不需要,通常传0。
返回值
成功时返回:
c
struct pw_proxy *
表示新创建对象对应的本地Proxy。
这个Proxy是客户端访问远端对象的入口。后续可以根据对象类型把它转换成对应的高层封装,或者通过Proxy监听事件、发送方法、管理生命周期。
失败时返回NULL。
失败原因通常包括Factory无效、type不匹配、version不兼容、服务端拒绝创建、权限不足、props缺失或Factory内部创建失败。工程上不能只检查函数返回值,还要结合PipeWire日志、Registry对象、Factory名称、创建参数和服务端错误事件一起定位。
应用场景
第一类场景是理解PipeWireFactory机制。
PipeWire中的很多对象都来自Factory。比如client-node、client-device、adapter、link-factory、spa-node-factory等,本质上都可以从"Factory创建对象"这个角度理解。pw_factory_create_object正好处在这条链路的客户端侧入口。
第二类场景是创建底层PipeWire对象。
普通播放器一般不会直接调用pw_factory_create_object,而是使用pw_stream_new_simple、pw_stream_connect等更高层接口。但调试PipeWire对象模型、写底层客户端、研究Factory创建流程时,需要理解它。
第三类场景是分析pw_core_create_object和Factory绑定流程。
如果代码里使用pw_core_create_object,内部语义可以理解成"通过Core按factory_name请求创建对象"。如果代码里已经拿到了pw_factory对象,就可以通过pw_factory_create_object直接发起创建。
第四类场景是分析PipeWire模块如何导出对象能力。
PipeWire模块加载后会注册Factory。Factory对外暴露"我能创建什么对象"。客户端发现Factory后,再通过创建接口把这个能力转化为真实对象。这个过程是理解PipeWire模块、Factory、Registry、Proxy、Resource关系的关键。
🌻3.调用流程剖析
🌻3.1核心步骤
1.客户端连接PipeWireCore,建立与PipeWire服务端的通信通道。
2.客户端通过pw_core_get_registry获取Registry对象。
3.Registry向客户端同步当前服务端暴露的全局对象。
4.客户端在global事件中识别目标Factory对象。
5.客户端通过pw_registry_bind绑定Factory,得到本地pw_factory代理。
6.客户端准备type、version和props等创建参数。
7.客户端调用pw_factory_create_object向Factory发送创建请求。
8.PipeWire服务端收到Factory create_object请求。
9.服务端Factory检查对象类型、接口版本、客户端权限和属性参数。
10.Factory调用对应实现逻辑创建具体对象实例。
11.服务端为新对象建立Resource或Proxy关联关系。
12.客户端获得返回的pw_proxy,并通过该Proxy继续管理新对象。
13.对象正常运行期间,客户端和服务端通过Proxy/Resource进行方法调用和事件通知。
14.对象销毁时,Proxy、Resource和实现侧对象依次释放。
🌻3.2调用流程图

🌻3.3生命周期图

🌻4.实战应用案例
下面用一个简化案例说明pw_factory_create_object在PipeWire客户端侧的典型使用方式。
这个案例的重点不是播放音频,也不是写PCM数据,而是演示"发现Factory→绑定Factory→通过Factory创建对象"的主链路。
c
#include <pipewire/pipewire.h>
struct app_data {
struct pw_core *core;
struct pw_registry *registry;
struct pw_factory *factory;
struct pw_proxy *created;
struct spa_hook registry_listener;
};
static void on_global(void *data,
uint32_t id,
uint32_t permissions,
const char *type,
uint32_t version,
const struct spa_dict *props)
{
struct app_data *app = data;
const char *name;
if (props == NULL)
return;
name = spa_dict_lookup(props, PW_KEY_FACTORY_NAME);
if (name == NULL)
return;
/*
* 这里只是示例。
* 实际开发中应根据目标Factory名称选择,比如client-node、adapter等。
*/
if (strcmp(name, "adapter") != 0)
return;
app->factory = pw_registry_bind(app->registry,
id,
type,
version,
sizeof(struct pw_factory));
if (app->factory == NULL)
return;
{
struct spa_dict_item items[] = {
{ PW_KEY_OBJECT_LINGER, "false" },
{ PW_KEY_NODE_NAME, "demo.factory.created.object" },
};
struct spa_dict props = SPA_DICT_INIT_ARRAY(items);
app->created = pw_factory_create_object(app->factory,
PW_TYPE_INTERFACE_Node,
PW_VERSION_NODE,
&props,
0);
}
}
static const struct pw_registry_events registry_events = {
PW_VERSION_REGISTRY_EVENTS,
.global = on_global,
};
这段代码的执行重点有三个。
第一,pw_factory_create_object之前必须先拿到Factory。
Factory不是普通C对象,不应该由应用自己malloc。客户端需要先通过Registry发现服务端暴露的Factory,然后调用pw_registry_bind获得本地代理。只有拿到pw_factory之后,才有条件调用pw_factory_create_object。
第二,type和version必须和Factory能力匹配。
不是所有Factory都能创建Node,也不是所有Factory都能创建Device。Factory导出的能力决定了它能创建什么对象。type写错,version不匹配,或者props缺少关键字段,都可能导致创建失败。
第三,返回值是pw_proxy,不是最终实现对象指针。
PipeWire采用客户端/服务端对象模型。客户端拿到的是Proxy,服务端才持有真实实现对象。应用后续对对象的操作,本质上是通过Proxy向服务端对象发送请求,或者接收服务端对象发回的事件。
从工程调试角度看,pw_factory_create_object失败时,建议从四个方向排查。
第一,确认Factory是否真的存在。
可以通过PipeWire对象枚举工具查看当前Registry里有没有目标Factory。没有Factory,后续创建一定失败。
第二,确认Factory名称是否正确。
很多Factory名称看起来像对象类型,但它们不是库名,也不是模块名,而是PipeWire暴露出来的对象创建入口。例如adapter是Factory名称,Node是对象接口类型,两者不是同一层概念。
第三,确认type和version是否匹配。
type描述"创建什么接口类型的对象",version描述"使用哪个接口版本"。它们必须和Factory支持的创建能力一致。
第四,确认props是否完整。
Factory创建对象时通常依赖属性字典。props中缺少媒体类别、节点名称、工厂参数或SPA相关配置时,服务端可能无法完成创建。
下面给出一个更接近真实工程的伪代码主链路:
c
static void create_object_from_factory(struct app_data *app)
{
struct spa_dict_item items[] = {
{ PW_KEY_NODE_NAME, "my-created-node" },
{ PW_KEY_MEDIA_CLASS, "Audio/Sink" },
};
struct spa_dict props = SPA_DICT_INIT_ARRAY(items);
if (app->factory == NULL)
return;
app->created = pw_factory_create_object(app->factory,
PW_TYPE_INTERFACE_Node,
PW_VERSION_NODE,
&props,
0);
if (app->created == NULL)
return;
/*
* 后续可以给created添加listener,
* 或根据实际对象类型继续完成参数配置。
*/
}
这个函数展示的是Factory对象创建的核心形态:调用方不直接创建服务端对象,而是把创建意图交给Factory。Factory内部再根据服务端模块注册的实现逻辑生成真实对象。
在PipeWire架构中,这种设计非常关键。它把"对象如何创建"从客户端代码中抽离出去,由模块和Factory统一管理。客户端只需要知道目标Factory、对象类型、接口版本和创建属性,不需要直接知道底层对象结构如何分配、如何初始化、如何接入PipeWire对象模型。
这也是PipeWire比传统单体音频服务更灵活的地方。播放流、采集流、设备、适配器、协议桥接、底层SPA插件,都可以通过Factory机制接入统一对象体系。理解pw_factory_create_object,就能更清楚地理解PipeWire为什么大量使用Factory、Registry、Proxy和Resource这些概念。
🌻5.一句话总结
pw_factory_create_object是PipeWireFactory对象创建入口:客户端先通过Registry绑定Factory,再通过type、version和props请求Factory创建远端对象,成功后拿到pw_proxy继续管理该对象。