Linux PipeWire深度解析之pw_factory_create_object调用流程与实战(七十二)
简介CSDN博客专家、《Android系统多媒体进阶实战》作者博主新书推荐《Android系统多媒体进阶实战》Android Audio工程师专栏地址Audio工程师进阶系列【原创干货持续更新中……】Android多媒体专栏地址多媒体系统工程师系列【原创干货持续更新中……】专题一 二AAOS车载系统AOSP14系统攻城狮入门视频实战课专题三Android14 Binder之HIDL与AIDL通信实战课专题四Android15快速自定义与集成音效实战课专题五Android15音频策略实战课专题六Android15音频性能实战课(无声/杂音/断音/爆音实战案例)人生格言人生从来没有捷径只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注Android系统攻城狮文章目录1.前言要点概括2.应用场景与用法函数原型参数说明返回值应用场景3.调用流程剖析3.1核心步骤3.2调用流程图3.3生命周期图4.实战应用案例5.一句话总结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远端对象。函数原型structpw_proxy*pw_factory_create_object(structpw_factory*factory,constchar*type,uint32_tversion,conststructspa_dict*props,size_tuser_data_size);参数说明structpw_factory*factory;factory表示已经绑定到客户端的Factory代理对象。它通常来自Registry bind流程。也就是说客户端不是凭空构造factory而是先从PipeWire服务端Registry中发现Factory全局对象然后根据global id绑定得到pw_factory对象。constchar*type;type表示要创建对象的接口类型。它用于告诉Factory客户端希望创建哪一类PipeWire对象。例如某些Factory可以创建Node类型对象某些Factory可以创建Device类型对象某些Factory可以创建ClientNode或ClientDevice类型对象。uint32_tversion;version表示客户端希望使用的目标接口版本。PipeWire对象接口是有版本的。客户端创建对象时需要声明自己期望的接口版本服务端会根据Factory能力和协议兼容性处理该请求。conststructspa_dict*props;props表示创建对象时附带的属性字典。它通常用于传递对象名称、媒体类型、Factory特定参数、节点属性、设备属性或模块需要的初始化配置。不同Factory识别的props不同不能把所有属性都理解成通用参数。size_tuser_data_size;user_data_size表示为返回的Proxy附加分配的用户数据大小。如果应用需要在Proxy后面附带私有数据可以设置该值。如果不需要通常传0。返回值成功时返回structpw_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创建对象”的主链路。#includepipewire/pipewire.hstructapp_data{structpw_core*core;structpw_registry*registry;structpw_factory*factory;structpw_proxy*created;structspa_hookregistry_listener;};staticvoidon_global(void*data,uint32_tid,uint32_tpermissions,constchar*type,uint32_tversion,conststructspa_dict*props){structapp_data*appdata;constchar*name;if(propsNULL)return;namespa_dict_lookup(props,PW_KEY_FACTORY_NAME);if(nameNULL)return;/* * 这里只是示例。 * 实际开发中应根据目标Factory名称选择比如client-node、adapter等。 */if(strcmp(name,adapter)!0)return;app-factorypw_registry_bind(app-registry,id,type,version,sizeof(structpw_factory));if(app-factoryNULL)return;{structspa_dict_itemitems[]{{PW_KEY_OBJECT_LINGER,false},{PW_KEY_NODE_NAME,demo.factory.created.object},};structspa_dictpropsSPA_DICT_INIT_ARRAY(items);app-createdpw_factory_create_object(app-factory,PW_TYPE_INTERFACE_Node,PW_VERSION_NODE,props,0);}}staticconststructpw_registry_eventsregistry_events{PW_VERSION_REGISTRY_EVENTS,.globalon_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相关配置时服务端可能无法完成创建。下面给出一个更接近真实工程的伪代码主链路staticvoidcreate_object_from_factory(structapp_data*app){structspa_dict_itemitems[]{{PW_KEY_NODE_NAME,my-created-node},{PW_KEY_MEDIA_CLASS,Audio/Sink},};structspa_dictpropsSPA_DICT_INIT_ARRAY(items);if(app-factoryNULL)return;app-createdpw_factory_create_object(app-factory,PW_TYPE_INTERFACE_Node,PW_VERSION_NODE,props,0);if(app-createdNULL)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继续管理该对象。