ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Linux PipeWire深度解析之pw_main_loop_new调用流程与实战(七十三)

Linux PipeWire深度解析之pw_main_loop_new调用流程与实战(七十三) 简介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_main_loop_new调用流程与实战。要点概括核心功能创建PipeWire主循环对象为后续Context、Core、Client和事件源提供统一事件驱动环境。工作机制内部创建并封装一个pw_loop对象应用通过pw_main_loop_get_loop()取得底层loop再交给pw_context_new()等接口使用。典型用途PipeWire客户端程序、服务端程序、测试工具、示例程序中创建事件循环并通过pw_main_loop_run()驱动事件分发。pw_main_loop_new的本质是“创建主事件循环容器”。它本身不连接PipeWire服务端不创建Context不创建Node也不处理音频Buffer。它只负责搭建事件循环基础设施。它和pw_loop_new的区别在于pw_loop_new创建的是更底层的事件循环对象而pw_main_loop_new是更上层的主循环封装适合应用直接使用。它和pw_thread_loop_new也不同。pw_thread_loop_new会配合独立线程和锁机制使用常用于需要后台线程驱动PipeWire事件的场景pw_main_loop_new通常用于当前线程中运行主循环。它和pw_main_loop_run是一组配套接口。new负责创建对象run负责进入事件循环quit负责请求退出destroy负责释放资源。2.应用场景与用法pw_main_loop_new是PipeWireMain Loop API中用于创建主事件循环对象的接口。它位于PipeWire程序启动阶段。应用通常先调用pw_init()完成PipeWire库初始化然后调用pw_main_loop_new()创建主循环再通过pw_main_loop_get_loop()取得内部pw_loop并把这个loop传给pw_context_new()或其他需要事件循环的PipeWire对象。pw_main_loop_new用于创建PipeWire主循环对象。函数原型structpw_main_loop*pw_main_loop_new(structpw_properties*props);参数说明structpw_properties*props;props表示创建主循环时传入的属性集合。该参数可以为NULL。多数普通应用和示例程序会直接传NULL表示使用默认主循环配置。只有在需要给底层loop传入特定属性时才需要构造pw_properties对象。参数本身不代表事件源也不代表媒体参数。它不是音频格式参数不是Buffer参数也不是设备路由参数。返回值成功时返回structpw_main_loop*表示创建完成的PipeWire主循环对象。失败时返回NULL。常见原因包括内存分配失败、底层pw_loop创建失败等。返回的pw_main_loop不能直接当作pw_context_new()的第一个参数使用。pw_context_new()需要的是struct pw_loop*因此通常要先调用structpw_loop*looppw_main_loop_get_loop(main_loop);再把loop传给Context或其他依赖事件循环的对象。应用场景第一类场景是PipeWire客户端程序。例如播放、录音、监控、调试工具等程序需要创建主循环接收PipeWire服务端事件、处理Stream状态变化、处理Buffer回调和错误回调。第二类场景是PipeWire服务端或嵌入式服务程序。服务端需要持续监听文件描述符、定时器、信号和内部事件。主循环负责把这些事件统一分发到对应回调中。第三类场景是源码调试和最小Demo。学习PipeWire时经常需要写一个最小程序验证Context、Core、Stream、Registry、Node等对象的生命周期。pw_main_loop_new通常是这些Demo中最早出现的接口之一。第四类场景是和pw_context_new配合。PipeWireContext并不凭空运行它需要一个事件循环作为基础。pw_main_loop_new创建主循环后pw_main_loop_get_loop()取出的pw_loop就可以作为Context运行环境。3.调用流程剖析3.1核心步骤1.应用启动后先调用pw_init()初始化PipeWire库环境。2.应用调用pw_main_loop_new(props)创建主循环对象。3.pw_main_loop_new内部分配pw_main_loop封装对象。4.主循环对象内部创建或持有底层pw_loop。5.pw_loop负责后续文件描述符、定时器、事件源和信号等事件分发。6.pw_main_loop_new完成状态初始化并返回struct pw_main_loop*。7.应用调用pw_main_loop_get_loop(main_loop)取得内部struct pw_loop*。8.应用把pw_loop传给pw_context_new()创建PipeWireContext。9.对象准备完成后应用调用pw_main_loop_run(main_loop)进入事件循环。10.需要退出时调用pw_main_loop_quit(main_loop)请求run返回。11.主循环退出后应用调用pw_main_loop_destroy(main_loop)释放主循环资源。3.2调用流程图3.3生命周期图4.实战应用案例下面用一个最小PipeWire程序骨架说明pw_main_loop_new在真实项目中的位置。这个案例不关注播放、录音和设备枚举只关注PipeWire运行环境的建立。主线是创建主循环取得底层loop创建Context进入事件循环退出后释放资源。#includepipewire/pipewire.hstructapp_data{structpw_main_loop*main_loop;structpw_context*context;};staticvoidapp_destroy(structapp_data*app){if(app-context!NULL)pw_context_destroy(app-context);if(app-main_loop!NULL)pw_main_loop_destroy(app-main_loop);}intmain(intargc,char*argv[]){structapp_dataapp{0};structpw_loop*loop;pw_init(argc,argv);app.main_looppw_main_loop_new(NULL);if(app.main_loopNULL)gotoexit;looppw_main_loop_get_loop(app.main_loop);if(loopNULL)gotoexit;app.contextpw_context_new(loop,NULL,0);if(app.contextNULL)gotoexit;pw_main_loop_run(app.main_loop);exit:app_destroy(app);pw_deinit();return0;}这段代码体现了pw_main_loop_new的几个关键点。第一pw_main_loop_new只创建主循环对象不会自动进入循环。真正开始事件分发的是pw_main_loop_run。第二pw_main_loop_new返回的是pw_main_loop而不是pw_loop。需要通过pw_main_loop_get_loop取得内部loop才能传给pw_context_new。第三pw_context_new依赖的是事件循环环境。Context后续加载配置、创建Core、管理全局对象、处理客户端事件都需要这个loop作为基础。第四pw_main_loop_destroy应在Context等依赖对象释放之后调用。否则可能出现上层对象还持有loop但底层loop已经销毁的生命周期错误。在实际播放程序中主循环通常还会和Stream一起使用。structplayer{structpw_main_loop*main_loop;structpw_stream*stream;};staticvoidon_process(void*userdata){structplayer*puserdata;/* * 播放流中通常会在这里调用 * * pw_stream_dequeue_buffer() * 填充PCM数据 * pw_stream_queue_buffer() * * 这些回调能够被触发前提是外层main_loop正在运行。 */(void)p;}这里要注意pw_stream_dequeue_buffer属于Stream数据路径pw_main_loop_new属于事件循环路径。两者不是同一层接口。pw_main_loop_new负责让程序“能被事件驱动起来”。pw_stream_dequeue_buffer负责在事件驱动后“处理一个媒体Buffer”。如果没有主循环Stream状态变化、Registry事件、Buffer回调、错误通知等都无法稳定分发。对于PipeWire客户端来说主循环是对象生命周期和媒体回调能够运行的基础。工程中常见的错误有三类。第一只调用pw_main_loop_new但忘记调用pw_main_loop_run。这样程序虽然创建了主循环对象但不会真正处理PipeWire事件。第二把pw_main_loop直接传给pw_context_new。pw_context_new需要的是pw_loop不是pw_main_loop因此必须先调用pw_main_loop_get_loop。第三销毁顺序错误。一般应先释放依赖loop的Context、Core、Stream等对象再销毁main_loop。5.一句话总结pw_main_loop_new是PipeWire程序启动阶段的主循环创建接口它创建并封装底层pw_loop为Context、Core、Stream和事件回调提供运行环境但真正进入事件分发要靠pw_main_loop_run。
返回列表