)
简介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_properties_update调用流程与实战。要点概括核心功能将一个spa_dict中的属性批量合并到已有pw_properties对象中。工作机制遍历dict中的key/value条目value非NULL时新增或覆盖属性value为NULL时删除对应属性并返回实际变化的属性数量。典型用途对象创建前合并默认属性、运行期更新对象属性、配置规则覆盖属性、模块内部同步属性集合。pw_properties_update的本质是“属性集合合并函数”。它不创建PipeWire对象不连接Core不提交Param也不直接改变Graph运行状态。它只处理pw_properties内部的key/value数据。在PipeWire中很多对象都会携带properties例如Core、Client、Node、Device、Stream、Filter、Module等。properties用于描述对象名称、媒体类型、角色、设备属性、节点属性、应用属性以及策略匹配信息。pw_properties_update就是这些属性集合在创建、修改和规则覆盖过程中的基础工具函数。它和pw_properties_set的区别是pw_properties_set一次只设置一个key而pw_properties_update一次合并整个spa_dict。它和pw_properties_add的区别是pw_properties_add只添加目标中不存在的key不覆盖已有keypw_properties_update会覆盖已有key。它和pw_properties_update_keys的区别是pw_properties_update_keys只复制指定keypw_properties_update会处理dict中的全部key。它和pw_properties_update_string的区别是pw_properties_update_string从字符串解析属性pw_properties_update直接使用已经构造好的spa_dict。2.应用场景与用法pw_properties_update是PipeWireProperties API中用于批量更新属性集合的接口。它位于PipeWire对象属性管理的基础层。上层模块、客户端、上下文、Stream、Filter或对象创建逻辑通常会先构造一个pw_properties对象再从配置、规则、参数或外部字典中合并属性最终把这些属性交给PipeWire对象使用。pw_properties_update用于把spa_dict中的key/value批量更新到pw_properties中。函数原型intpw_properties_update(structpw_properties*props,conststructspa_dict*dict);参数说明structpw_properties*props;props表示要被更新的目标属性集合。它是一个可修改的pw_properties对象。函数会直接修改该对象内部保存的key/value数据。conststructspa_dict*dict;dict表示新的属性来源。它是一个spa_dict字典内部包含若干spa_dict_item。每个item包含一个key和一个value。pw_properties_update会遍历这些条目并根据value是否为NULL决定是设置属性还是删除属性。返回值返回值类型为int返回值表示本次调用中实际发生变化的属性数量。如果返回0表示没有属性发生变化。可能是dict为空也可能是传入的key/value与props中已有内容一致。如果某个key的value非NULL该key会被新增或覆盖。如果某个key的value为NULL该key会从props中删除。应用场景第一类场景是对象创建前合并属性。例如创建Stream、Filter、Node或Module之前先准备默认properties再把用户指定属性、配置文件属性或业务侧属性合并进去最终得到完整的对象属性。第二类场景是配置规则覆盖属性。PipeWire配置和WirePlumber策略中经常会根据对象匹配结果修改属性。底层实现上这类逻辑通常都离不开“把一组key/value合并到已有属性集合”这个动作。第三类场景是模块内部同步属性。模块内部可能先维护一份基础属性再根据设备发现结果、媒体类型、角色、节点名称、优先级等信息继续更新属性。pw_properties_update适合做这种批量属性修正。第四类场景是属性删除。当dict中某个key的value为NULL时pw_properties_update不是把字符串NULL写进去而是删除该key。这一点在工程调试中很重要。3.调用流程剖析3.1核心步骤1.上层代码准备一个目标pw_properties对象。2.上层代码准备一个来源spa_dict。3.spa_dict中保存一组key/value条目。4.调用pw_properties_update(props,dict)。5.函数遍历dict中的每一个spa_dict_item。6.如果当前item的value非NULL则把该key/value写入props。7.如果props中不存在该key则新增属性。8.如果props中已经存在该key则覆盖旧value。9.如果当前item的value为NULL则从props中删除该key。10.每发生一次有效新增、覆盖或删除变更计数增加。11.dict遍历结束后函数返回本次实际变化的属性数量。12.上层对象继续使用更新后的props完成创建、导出、发布或策略匹配。3.2调用流程图3.3生命周期图4.实战应用案例下面用一个简化案例说明pw_properties_update的典型用法。假设我们要创建一个播放类Stream。基础属性中已经有应用名称和媒体类型业务侧又提供了一组新的属性用于设置节点名称、媒体角色和节点描述。此时就可以使用pw_properties_update把业务侧属性一次性合并到基础属性中。#includepipewire/pipewire.hstaticvoidupdate_stream_properties(void){structpw_properties*props;structspa_dict_itemitems[3];structspa_dictdict;intchanged;propspw_properties_new(PW_KEY_APP_NAME,pipewire-demo,PW_KEY_MEDIA_TYPE,Audio,NULL);items[0]SPA_DICT_ITEM_INIT(PW_KEY_NODE_NAME,demo.playback);items[1]SPA_DICT_ITEM_INIT(PW_KEY_MEDIA_ROLE,Music);items[2]SPA_DICT_ITEM_INIT(PW_KEY_NODE_DESCRIPTION,Demo Playback Stream);dictSPA_DICT_INIT_ARRAY(items);changedpw_properties_update(props,dict);(void)changed;/* * 更新后的props可以继续传给pw_stream_new_simple、 * pw_stream_new或其他需要properties的对象创建接口。 */pw_properties_free(props);}这个案例中props是目标属性集合dict是新的属性来源。调用pw_properties_update之后props中会保留原来的app.name和media.type同时新增node.name、media.role和node.description。如果业务侧希望删除某个属性可以把对应value设置为NULL。staticvoidremove_property_with_update(structpw_properties*props){structspa_dict_itemitems[1];structspa_dictdict;intchanged;items[0]SPA_DICT_ITEM_INIT(PW_KEY_NODE_DESCRIPTION,NULL);dictSPA_DICT_INIT_ARRAY(items);changedpw_properties_update(props,dict);(void)changed;}这里的NULL表示删除PW_KEY_NODE_DESCRIPTION而不是把该属性设置成字符串NULL。在真实PipeWire开发中这一点非常关键。很多属性不是简单追加而是可能被规则覆盖、被策略清理、被模块重写。pw_properties_update通过“value非NULL表示设置value为NULL表示删除”的方式把新增、覆盖和删除统一到一个接口中。再看一个更接近工程实践的封装方式。假设模块内部有默认属性同时允许外部传入一组额外属性staticstructpw_properties*build_node_properties(conststructspa_dict*extra){structpw_properties*props;propspw_properties_new(PW_KEY_MEDIA_TYPE,Audio,PW_KEY_MEDIA_CATEGORY,Playback,PW_KEY_MEDIA_ROLE,Music,NULL);if(extra!NULL)pw_properties_update(props,extra);returnprops;}这种写法的好处是默认属性和外部属性职责清晰。默认属性负责保证对象可以被正确识别例如media.type、media.category、media.role。外部属性负责覆盖业务侧需要定制的部分例如node.name、node.description、priority.session、application.name等。工程上使用pw_properties_update时需要注意四点。第一props是被直接修改的目标对象。调用后不需要再额外复制结果。第二dict只作为输入来源。函数不会把dict本身变成pw_properties也不会接管dict的生命周期。第三返回值是变化数量不是最终属性总数。不能把返回值理解成props中key的数量。第四属性更新不等于对象参数更新。properties主要用于对象描述、匹配和策略判断音频格式、采样率、通道布局、Buffer参数等通常属于Param路径不能用pw_properties_update替代。5.一句话总结pw_properties_update是PipeWire属性系统中的批量合并接口它把spa_dict中的key/value更新到pw_properties中value非NULL表示新增或覆盖value为NULL表示删除返回值表示本次实际变化的属性数量。