三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Linux PipeWire深度解析之pw_properties_copy调用流程与实战(五十八)

Linux PipeWire深度解析之pw_properties_copy调用流程与实战(五十八)

简介: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_copy调用流程与实战。

要点概括

  • 核心功能:复制一个已有的pw_properties对象,生成一份独立的属性集合。

  • 工作机制:创建新的pw_properties对象,并把原对象中的key/value属性逐项复制到新对象中。

  • 典型用途:保存配置快照、隔离属性修改、给模块或对象传递一份可独立释放的属性副本。

pw_properties_copy的本质是“复制属性集合”,不是“增加引用计数”。调用完成后,原properties和副本properties是两个独立对象,后续修改副本不会影响原对象,释放副本也不会释放原对象。

它主要用于PipeWire内部和客户端代码中的属性隔离场景。例如创建Stream、Node、Context或模块参数时,某些属性可能来自外部配置、SPA字典或临时变量。为了避免后续修改影响原始属性,通常需要复制一份独立副本。

它和pw_properties_new不同。pw_properties_new用于从变参key/value创建新属性对象;pw_properties_copy用于从已有pw_properties对象复制。它和pw_properties_new_dict、pw_properties_copy_dict也不同,后两者面向的是spa_dict,而pw_properties_copy面向的是pw_properties对象。

🌻2.应用场景与用法

pw_properties_copy

是PipeWire Properties API中用于复制属性对象的接口。

它位于PipeWire基础工具层,不直接参与音频Buffer传输,也不直接参与Graph调度,但它会被Stream、Context、Node、Device、Module等对象创建和参数传递过程频繁使用。PipeWire中很多对象都依赖properties描述名称、角色、媒体类型、设备信息、节点属性和策略参数。

pw_properties_copy用于从一个已有pw_properties对象复制出一个新的独立属性对象。

函数原型

structpw_properties*pw_properties_copy(conststructpw_properties*properties);

参数说明

conststructpw_properties*properties;

properties表示待复制的源属性对象。

它是只读输入参数。函数不会修改源对象,只会读取源对象中的属性项,并把这些属性项复制到新的pw_properties对象中。

源对象内部通常保存一个spa_dict结构,spa_dict中每一项都是key/value形式的字符串属性。pw_properties_copy会把这些属性复制到目标对象,而不是简单复用源对象指针。

返回值

成功时返回:

structpw_properties*

表示新创建的属性对象副本。

失败时返回NULL。常见原因包括源对象无效、内存分配失败、属性项复制失败等。

调用者拿到返回值后,需要在不再使用时调用:

pw_properties_free(copy);

释放副本对象。

注意,释放副本不会影响原始properties对象;释放原始properties对象也不会自动释放副本对象。两者生命周期互相独立。

应用场景

第一类场景是保存配置快照。

当一组属性可能在后续流程中继续变化,但当前模块需要保存“此刻状态”时,可以使用pw_properties_copy复制一份快照。

第二类场景是隔离对象参数。

创建Stream、Node或模块时,如果直接复用外部properties,后续外部代码修改这些属性,可能影响对象初始化语义。复制一份属性可以避免共享修改带来的副作用。

第三类场景是模块内部保存私有属性。

模块加载时可能收到一组properties参数。模块内部如果需要长期保存这些参数,通常不应该依赖外部传入对象的生命周期,而应该复制一份归自己管理。

第四类场景是属性转发。

某些代码需要读取一个对象的properties,然后略作修改再传递给另一个对象。此时通常先copy,再set/update,最后传递副本,避免污染原对象。

🌻3.调用流程剖析

🌻3.1核心步骤

1.调用者已经持有一个有效的struct pw_properties对象。

2.调用者执行pw_properties_copy(properties)。

3.函数检查源properties对象是否可用。

4.函数创建一个新的pw_properties对象。

5.函数读取源对象内部的spa_dict属性表。

6.函数遍历源属性表中的每一个key/value条目。

7.函数为key和value创建新的字符串副本。

8.函数把复制后的key/value写入目标properties对象。

9.所有属性复制完成后,函数返回新的pw_properties指针。

10.调用者可以独立修改副本,例如使用pw_properties_set、pw_properties_update或pw_properties_clear。

11.副本使用完成后,调用者必须调用pw_properties_free释放。

12.原properties和副本properties分别管理,不共享释放责任。

🌻3.2调用流程图

🌻3.3生命周期图

🌻4.实战应用案例

下面用一个简化案例说明pw_properties_copy的典型用法。

假设业务侧已经有一组基础属性,用于描述一个音频流:

structpw_properties*base_props;base_props=pw_properties_new(PW_KEY_MEDIA_TYPE,"Audio",PW_KEY_MEDIA_CATEGORY,"Playback",PW_KEY_MEDIA_ROLE,"Music",PW_KEY_NODE_NAME,"demo-player",NULL);

这组属性可以作为公共模板使用。如果后续要基于它创建不同的Stream或模块配置,不建议直接修改base_props。更安全的做法是复制一份,再在副本上做局部修改。

structpw_properties*stream_props;stream_props=pw_properties_copy(base_props);if(stream_props==NULL)return;pw_properties_set(stream_props,PW_KEY_NODE_DESCRIPTION,"Demo Player Stream");pw_properties_set(stream_props,PW_KEY_APP_NAME,"pipewire-demo");

此时stream_props已经是独立副本。修改stream_props不会改变base_props。

如果后续使用stream_props创建Stream,可以把它传给对应的对象创建流程。具体对象是否接管properties所有权,需要看对应API的约定。如果没有被接管,调用者仍然需要自己释放。

pw_properties_free(stream_props);

这个案例体现了pw_properties_copy的核心价值:让一份属性模板可以被安全复用,同时允许每个使用者拥有自己的可变副本。

再看一个更接近模块内部的用法。

模块收到外部传入的properties后,如果需要长期保存,就应该复制一份,而不是只保存外部指针。

structdemo_module{structpw_properties*props;};staticintdemo_module_init(structdemo_module*mod,conststructpw_properties*props){mod->props=pw_properties_copy(props);if(mod->props==NULL)return-1;return0;}staticvoiddemo_module_destroy(structdemo_module*mod){if(mod->props!=NULL)pw_properties_free(mod->props);}

这样做的好处是模块内部属性生命周期清晰。外部传入的props即使后续被释放,也不会影响mod->props。模块销毁时,只需要释放自己复制出来的属性副本。

工程上使用pw_properties_copy时,要重点注意三点。

第一,返回值必须判空。属性复制过程中可能发生内存分配失败,不能默认一定成功。

第二,复制出来的对象需要释放。pw_properties_copy返回的是新对象,不是借用指针。

第三,不要把它当成轻量引用操作。它会复制属性内容,适合用于隔离和快照,不适合在高频实时路径中反复调用。

🌻5.一句话总结

pw_properties_copy是PipeWire属性系统中的复制接口:它从已有pw_properties对象创建一份独立副本,用于配置快照、参数隔离和生命周期解耦,使用完成后必须由调用者或接管方正确释放。

← 返回列表