简介:CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀
人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻1.前言
- 要点概括
- 🌻2.应用场景与用法
- 函数原型
- 参数说明
- 返回值
- 应用场景
- 🌻3.调用流程剖析
- 🌻3.1核心步骤
- 🌻3.2调用流程图
- 🌻3.3生命周期图
- 🌻4.实战应用案例
- 🌻5.一句话总结
🌻1.前言
本篇目的:
Linux PipeWire深度解析之pw_main_loop_get_loop调用流程与实战。
要点概括
核心功能:取得pw_main_loop内部持有的pw_loop指针,让Context、事件源和后续任务绑定到同一个事件循环。
工作机制:该函数不创建新的Loop,只返回pw_main_loop对象内部已经创建好的pw_loop。
典型用途:创建pw_context、注册signal/timer/io/defer事件源、统一驱动PipeWire客户端主循环。
pw_main_loop_get_loop的本质是“从主循环封装对象中取出底层事件循环”。它不是运行主循环的接口,也不是创建Loop的接口。
pw_main_loop_new负责创建pw_main_loop对象,并在内部准备pw_loop。pw_main_loop_get_loop只负责暴露这个内部pw_loop指针。pw_main_loop_run才负责进入事件循环并驱动事件分发。
它和pw_main_loop_run不同。pw_main_loop_run会阻塞当前线程并持续处理事件;pw_main_loop_get_loop只返回指针,不会进入事件循环。
它和pw_main_loop_quit也不同。pw_main_loop_quit用于请求主循环退出;pw_main_loop_get_loop不改变运行状态。
它和pw_loop_new也不同。pw_loop_new创建独立的pw_loop对象;pw_main_loop_get_loop返回的是pw_main_loop内部已经拥有的pw_loop,调用方不能销毁这个返回指针。
🌻2.应用场景与用法
pw_main_loop_get_loop
是PipeWire Main Loop API中用于获取底层pw_loop的接口。
它位于PipeWire客户端初始化主链路中。应用先通过pw_main_loop_new创建主循环对象,再通过pw_main_loop_get_loop取得内部pw_loop,然后把该pw_loop传给pw_context_new,保证Context、Core连接、Registry事件、Stream事件和自定义事件源都在同一个事件循环中调度。
pw_main_loop_get_loop用于从pw_main_loop中取得内部pw_loop指针。
函数原型
structpw_loop*pw_main_loop_get_loop(structpw_main_loop*loop);参数说明
structpw_main_loop*loop;loop表示已经通过pw_main_loop_new创建的主循环对象。
该对象负责管理PipeWire客户端常用的主循环封装。它内部持有一个pw_loop,pw_main_loop_get_loop返回的就是这个内部pw_loop。
调用前需要保证loop有效。不能把已经destroy的pw_main_loop继续传给该函数。
返回值
成功时返回:
structpw_loop*表示pw_main_loop内部持有的底层事件循环对象。
该返回值是借用指针,不表示调用方获得所有权。调用方不能直接释放它,也不能在pw_main_loop_destroy之后继续使用它。
返回NULL通常表示传入对象无效,或者主循环对象没有正确创建。实际开发中,应优先保证pw_main_loop_new成功,再调用pw_main_loop_get_loop。
应用场景
第一类场景是创建PipeWire Context。
PipeWire客户端通常先创建pw_main_loop,再通过pw_main_loop_get_loop取得pw_loop,最后把pw_loop传给pw_context_new。这样Context后续产生的事件可以由同一个主循环驱动。
第二类场景是注册事件源。
应用可以基于返回的pw_loop注册signal、timer、io、defer等事件源。这些事件源和PipeWire内部事件运行在同一个事件循环中,方便统一调度。
第三类场景是客户端程序主循环封装。
简单PipeWire客户端不一定直接管理pw_loop,可以使用pw_main_loop作为上层封装。pw_main_loop_get_loop提供了向底层事件系统对接的入口。
第四类场景是Stream事件调度。
应用创建Context并连接PipeWire服务端后,后续Registry事件、Stream状态变化、process回调等都依赖事件循环驱动。pw_main_loop_get_loop虽然不直接处理Stream数据,但它决定了这些事件挂在哪个Loop上运行。
🌻3.调用流程剖析
🌻3.1核心步骤
1.应用调用pw_init初始化PipeWire库环境。
2.应用调用pw_main_loop_new创建pw_main_loop对象。
3.pw_main_loop_new内部创建并保存一个pw_loop对象。
4.应用调用pw_main_loop_get_loop取得pw_main_loop内部的pw_loop指针。
5.应用把该pw_loop传给pw_context_new创建PipeWire Context。
6.Context后续基于同一个pw_loop处理连接、Registry、Proxy和Stream事件。
7.应用也可以基于该pw_loop注册timer、signal、io、defer等事件源。
8.应用调用pw_main_loop_run进入主循环。
9.pw_main_loop_run驱动底层pw_loop进行poll和dispatch。
10.应用调用pw_main_loop_quit请求主循环退出。
11.应用调用pw_main_loop_destroy销毁主循环对象。
12.pw_main_loop_destroy完成后,pw_main_loop_get_loop返回过的pw_loop指针失效。
🌻3.2调用流程图
🌻3.3生命周期图
🌻4.实战应用案例
下面以“创建PipeWire客户端主循环和Context”为例,说明pw_main_loop_get_loop在真实开发中的位置。
这个案例只保留主链路:创建主循环、取得内部pw_loop、创建Context、连接PipeWire服务端、运行主循环。
#include<pipewire/pipewire.h>structapp_data{structpw_main_loop*main_loop;structpw_context*context;structpw_core*core;};staticvoidinit_pipewire_client(structapp_data*data){structpw_loop*loop;pw_init(NULL,NULL);data->main_loop=pw_main_loop_new(NULL);if(data->main_loop==NULL)return;/* * 此API在主链路作用: * 从pw_main_loop中取得内部pw_loop, * 后续Context和事件源都绑定到这个loop。 */loop=pw_main_loop_get_loop(data->main_loop);if(loop==NULL)return;/* * 此API在主链路作用: * 创建PipeWire Context,并使用上面取得的pw_loop驱动Context事件。 */data->context=pw_context_new(loop,NULL,0);if(data->context==NULL)return;/* * 此API在主链路作用: * 通过Context连接PipeWire服务端,得到Core代理对象。 */data->core=pw_context_connect(data->context,NULL,0);if(data->core==NULL)return;/* * 此API在主链路作用: * 进入主循环,驱动Core、Registry、Stream等事件回调执行。 */pw_main_loop_run(data->main_loop);}staticvoiddestroy_pipewire_client(structapp_data*data){if(data->core!=NULL)pw_core_disconnect(data->core);if(data->context!=NULL)pw_context_destroy(data->context);if(data->main_loop!=NULL)pw_main_loop_destroy(data->main_loop);pw_deinit();}这个案例中,pw_main_loop_get_loop不负责连接PipeWire服务端,也不负责运行事件循环。它只是把pw_main_loop内部的pw_loop取出来,交给pw_context_new使用。
实际开发中,最容易出现的问题是把pw_main_loop和pw_loop的所有权搞混。
pw_main_loop_get_loop返回的pw_loop不需要手动destroy。它由pw_main_loop管理。应用只需要在最后调用pw_main_loop_destroy,内部资源会跟随主循环对象一起释放。
另一个常见问题是创建了多个Loop。比如Context使用一个Loop,自定义timer使用另一个Loop,最后只有一个Loop被run。这样部分事件永远不会被调度。工程上建议简单客户端优先使用同一个pw_main_loop,并通过pw_main_loop_get_loop取得同一个pw_loop。
如果只是创建普通Stream客户端,典型结构通常是:
data.main_loop=pw_main_loop_new(NULL);loop=pw_main_loop_get_loop(data.main_loop);data.context=pw_context_new(loop,NULL,0);data.core=pw_context_connect(data.context,NULL,0);data.stream=pw_stream_new(data.core,"playback",props);pw_stream_connect(data.stream,PW_DIRECTION_OUTPUT,PW_ID_ANY,flags,params,n_params);pw_main_loop_run(data.main_loop);在这条链路中,pw_main_loop_get_loop处在主循环创建之后、Context创建之前。它是PipeWire客户端从“主循环封装层”进入“底层事件循环层”的连接点。
🌻5.一句话总结
pw_main_loop_get_loop是PipeWire主循环链路中的取Loop接口:它从pw_main_loop中返回内部pw_loop指针,用于创建Context和注册事件源,但不创建Loop、不运行Loop,也不转移Loop所有权。