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

📅 2026/8/23 18:49:34
Linux PipeWire深度解析之pw_stream_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_stream_new调用流程与实战。要点概括核心功能创建一个PipeWireStream对象为后续播放、录音、视频采集或视频输出建立客户端侧控制入口。工作机制基于已有pw_core创建pw_stream结构保存Stream名称、属性、Core关联关系、状态管理和事件基础设施。典型用途应用已经连接PipeWire服务端后需要创建一个可连接到Graph的媒体Stream。pw_stream_new的本质是“创建Stream控制对象”不是“开始传输媒体数据”。它只让应用得到一个struct pw_stream*后续还需要通过pw_stream_add_listener注册事件通过pw_stream_connect接入PipeWireGraph才能进入真正的数据处理链路。它和pw_stream_connect的边界很清楚。pw_stream_new负责创建Stream对象pw_stream_connect负责把Stream连接到PipeWireGraph。没有connect之前Stream还没有远端Node、Port、Link和Buffer。它和pw_stream_dequeue_buffer也不同。pw_stream_dequeue_buffer用于process回调中的Buffer取出属于数据路径pw_stream_new属于对象创建路径。前者处理媒体数据后者建立Stream生命周期起点。它和pw_stream_new_simple也不同。pw_stream_new适合应用已经持有pw_core的场景pw_stream_new_simple更适合简单示例或轻量客户端它把部分Core和事件循环处理做了封装。2.应用场景与用法pw_stream_new是PipeWireStream API中用于创建Stream对象的接口。它位于PipeWire客户端接入链路的起点。应用连接到PipeWire服务端并获得pw_core之后就可以调用pw_stream_new创建一个Stream对象。这个Stream对象后续可以配置事件、连接目标、协商格式、接收Buffer事件并进入process回调处理媒体数据。pw_stream_new用于基于已有pw_core创建一个PipeWireStream对象。函数原型structpw_stream*pw_stream_new(structpw_core*core,constchar*name,structpw_properties*props);参数说明structpw_core*core;core表示应用已经连接到PipeWire服务端后得到的Core对象。它是Stream连接PipeWire服务端的基础。pw_stream_new创建出来的Stream会绑定到这个Core后续pw_stream_connect会通过该Core与服务端交互。constchar*name;name表示Stream名称。这个名称通常用于调试、对象标识、日志显示和会话管理策略识别。例如播放器可以设置为music-playback录音程序可以设置为audio-capture。structpw_properties*props;props表示Stream属性集合。常见属性包括媒体类型、媒体分类、应用名称、节点名称、Stream角色等。它会影响PipeWire和WirePlumber对这个Stream的识别、路由和策略处理。工程上通常通过pw_properties_new创建props然后传给pw_stream_new。传入后不要再把同一个props当作普通外部对象随意释放或复用。返回值成功时返回structpw_stream*表示新创建的Stream对象。失败时返回NULL。常见原因包括core无效、内存分配失败或内部初始化失败。返回成功并不表示Stream已经连接成功也不表示已经有Buffer可用。此时只是创建了客户端侧Stream对象。要进入媒体处理链路还需要继续调用pw_stream_connect。应用场景第一类场景是播放器创建播放Stream。播放器先连接PipeWire服务端得到pw_core然后调用pw_stream_new创建播放Stream再设置媒体属性并连接到默认Sink或指定Node。第二类场景是录音程序创建采集Stream。录音程序同样先创建Stream对象再通过pw_stream_connect以输入方向连接到Source或录音设备Node之后在process回调中读取采集数据。第三类场景是复杂客户端统一管理多个Stream。例如一个音视频会议程序可能同时创建麦克风采集Stream、扬声器播放Stream、摄像头采集Stream和屏幕共享Stream。使用pw_stream_new可以让这些Stream共享同一个pw_core和事件循环上下文。第四类场景是需要明确控制Core生命周期的程序。如果应用已经自己管理pw_context、pw_core、pw_loop和权限逻辑就更适合使用pw_stream_new而不是使用封装更高的pw_stream_new_simple。3.调用流程剖析3.1核心步骤1.应用初始化PipeWire运行环境并连接PipeWire服务端。2.应用获得pw_core对象。3.应用准备Stream名称和属性props。4.应用调用pw_stream_new(core,name,props)。5.pw_stream_new检查core参数并为Stream分配客户端侧结构。6.Stream保存Core引用、Stream名称和属性集合。7.Stream初始化内部状态、事件Hook、Buffer列表和监听结构。8.Stream进入未连接状态此时还没有接入PipeWireGraph。9.pw_stream_new返回struct pw_stream*给应用。10.应用调用pw_stream_add_listener注册Stream事件。11.应用调用pw_stream_connect设置方向、目标ID、连接标志和格式参数。12.连接完成后Stream才进入格式协商、Buffer管理和process数据处理阶段。3.2调用流程图3.3生命周期图4.实战应用案例下面以“创建一个播放Stream对象”为例说明pw_stream_new的典型使用方式。这个案例只展示pw_stream_new在主链路中的位置不展示编译命令和程序运行结果。#includepipewire/pipewire.hstructapp_data{structpw_core*core;structpw_stream*stream;structspa_hookstream_listener;};首先定义应用数据结构。core表示已经连接到PipeWire服务端的Core对象。stream表示通过pw_stream_new创建出来的Stream对象。stream_listener用于保存事件监听Hook避免监听器生命周期过早结束。staticvoidon_stream_process(void*userdata){structapp_data*datauserdata;structpw_buffer*b;bpw_stream_dequeue_buffer(data-stream);if(bNULL)return;/* * 播放方向 * 这里通常向Buffer写入PCM数据。 * * 采集方向 * 这里通常从Buffer读取PCM数据。 */pw_stream_queue_buffer(data-stream,b);}process回调不是由pw_stream_new直接触发的。它只有在Stream完成connect、进入Graph调度并且有可用Buffer之后才会被触发。pw_stream_new只创建Stream对象不负责取Buffer也不负责提交Buffer。staticconststructpw_stream_eventsstream_events{PW_VERSION_STREAM_EVENTS,.processon_stream_process,};这里定义Stream事件表。对于播放或录音程序process事件最重要。它代表PipeWireGraph已经调度到该Stream应用需要在这个回调中生产或消费媒体数据。staticstructpw_stream*create_playback_stream(structapp_data*data){structpw_properties*props;propspw_properties_new(PW_KEY_MEDIA_TYPE,Audio,PW_KEY_MEDIA_CATEGORY,Playback,PW_KEY_MEDIA_ROLE,Music,PW_KEY_APP_NAME,pipewire-playback-demo,NULL);data-streampw_stream_new(data-core,playback-stream,props);if(data-streamNULL)returnNULL;pw_stream_add_listener(data-stream,data-stream_listener,stream_events,data);returndata-stream;}这段代码体现了pw_stream_new的核心用法。第一步准备Stream属性。propspw_properties_new(PW_KEY_MEDIA_TYPE,Audio,PW_KEY_MEDIA_CATEGORY,Playback,PW_KEY_MEDIA_ROLE,Music,PW_KEY_APP_NAME,pipewire-playback-demo,NULL);这些属性会告诉PipeWire和会话管理器这是一个音频播放流角色是音乐播放。WirePlumber这类会话管理器可以根据这些属性进行路由、权限和策略处理。第二步创建Stream对象。data-streampw_stream_new(data-core,playback-stream,props);这里的核心点是pw_stream_new只需要已有core、Stream名称和属性集合。调用成功后应用得到一个Stream控制对象。第三步注册Stream事件。pw_stream_add_listener(data-stream,data-stream_listener,stream_events,data);pw_stream_new本身不接收事件表。事件需要通过pw_stream_add_listener单独注册。这样process、state_changed、param_changed、add_buffer、remove_buffer等事件才能通知到应用。接下来Stream还需要connect。staticintconnect_playback_stream(structapp_data*data,conststructspa_pod**params,uint32_tn_params){returnpw_stream_connect(data-stream,PW_DIRECTION_OUTPUT,PW_ID_ANY,PW_STREAM_FLAG_AUTOCONNECT|PW_STREAM_FLAG_MAP_BUFFERS|PW_STREAM_FLAG_RT_PROCESS,params,n_params);}这一步才是Stream进入PipeWireGraph的关键。PW_DIRECTION_OUTPUT表示应用向Graph输出数据也就是播放方向。PW_ID_ANY表示不指定固定目标由会话管理器选择合适的播放设备。PW_STREAM_FLAG_AUTOCONNECT表示允许自动连接目标Node。PW_STREAM_FLAG_MAP_BUFFERS表示希望PipeWire帮应用映射Buffer内存便于直接读写。PW_STREAM_FLAG_RT_PROCESS表示process回调会进入实时处理路径应用必须避免阻塞操作。从工程视角看pw_stream_new和pw_stream_connect要分开理解。pw_stream_new阶段data-streampw_stream_new(data-core,playback-stream,props);此时应用只是拿到了Stream对象。pw_stream_connect阶段pw_stream_connect(data-stream,PW_DIRECTION_OUTPUT,PW_ID_ANY,flags,params,n_params);此时Stream才开始和PipeWire服务端交互进入格式协商、Node创建、Port连接和Buffer准备流程。如果把pw_stream_new误解成“创建播放节点并开始播放”后面分析PipeWire链路就会混乱。更准确的说法是pw_stream_new创建客户端侧Stream对象。pw_stream_connect让Stream进入Graph连接流程。pw_stream_dequeue_buffer和pw_stream_queue_buffer负责process回调中的Buffer流转。5.一句话总结pw_stream_new是PipeWireStream生命周期的创建入口它基于已有pw_core创建客户端侧Stream对象但不连接Graph、不创建Buffer、不处理媒体数据真正的数据链路要从pw_stream_connect之后才开始。