简介:CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀
人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻1. 前言
- 要点概括
- 🌻2. 应用场景与用法
- 函数原型
- 参数说明
- 返回值
- 应用场景
- 🌻3. 调用流程剖析
- 🌻3.1 核心步骤
- 1. process 回调触发
- 2. 取出 Buffer
- 3. 获取底层 spa_buffer
- 4. 处理 Buffer 数据
- 5. 重新入队 Buffer
- 6. PipeWire 接管 Buffer
- 7. 等待下一轮 process
- 8. Buffer 循环复用
- 🌻3.2 调用流程图
- 🌻3.3 Stream Buffer 入队生命周期图
- 🌻4. 实战应用案例
- 🌻5. 一句话总结
🌻1. 前言
本篇目的:
Linux PipeWire 深度解析之pw_stream_queue_buffer调用流程与实战。
要点概括
- 核心功能:把已经处理完成的
pw_buffer重新提交回pw_stream。 - 工作机制:应用在
process回调中通过pw_stream_dequeue_buffer()取出 Buffer,完成音频/视频数据填充或消费后,再调用pw_stream_queue_buffer()把 Buffer 归还给 PipeWire。 - 典型用途:音频播放、音频采集、Camera 视频帧处理、低延迟媒体流 Buffer 循环复用。
🌻2. 应用场景与用法
pw_stream_queue_buffer()是 PipeWire Stream Buffer 管理体系中的核心接口。
在 PipeWire 中,音频播放、录音采集、摄像头视频流、屏幕采集这类实时媒体数据,最终都会通过pw_stream和pw_buffer完成数据交换。
而该接口用于:
把已经处理完成的
pw_buffer重新入队,交还给 PipeWire Stream 继续调度。
函数原型
intpw_stream_queue_buffer(structpw_stream*stream,structpw_buffer*buffer);参数说明
stream:目标 pw_stream buffer:需要重新入队的 pw_buffer返回值
返回int通常用于判断 Buffer 是否成功重新提交给 Stream。
0 -> 成功 <0 -> 失败应用场景
pw_stream_queue_buffer()常见应用场景主要有三类。
第一类是音频播放。在播放场景中,PipeWire 通过process回调通知应用准备写入音频数据,应用调用pw_stream_dequeue_buffer()取出可写 Buffer,把 PCM 数据写入spa_buffer->datas[]后,再调用pw_stream_queue_buffer()把 Buffer 交还给 PipeWire,后续由 PipeWire 调度到音频设备输出。
第二类是音频采集。在录音场景中,PipeWire 把已经采集到的音频帧放入 Buffer,应用在process回调中取出 Buffer,读取其中的 PCM 数据并完成编码、保存或网络发送,处理完成后仍然需要调用pw_stream_queue_buffer()归还 Buffer,否则 Buffer 队列会被耗尽,录音流会出现停顿或异常。
第三类是 Camera 与视频帧处理。在摄像头、屏幕采集或视频处理场景中,每一帧图像也通过 Buffer 流转。应用从 Stream 中取出 Buffer,完成图像读取、格式转换、编码或渲染后,再调用pw_stream_queue_buffer()重新入队,使 PipeWire 可以继续复用该 Buffer,维持实时视频流的持续运行。
🌻3. 调用流程剖析
🌻3.1 核心步骤
1. process 回调触发
staticvoidon_process(void*userdata){}PipeWire 通知应用:
当前 Stream 需要处理一轮 Buffer2. 取出 Buffer
应用调用:
pw_stream_dequeue_buffer(stream);从pw_stream中取出一个可处理的:
structpw_buffer3. 获取底层 spa_buffer
每个pw_buffer内部会关联:
structspa_buffer应用通过:
buffer->buffer访问底层数据区。
4. 处理 Buffer 数据
播放场景通常是:
写入 PCM / 视频帧数据采集场景通常是:
读取 PCM / 视频帧数据5. 重新入队 Buffer
处理完成后调用:
pw_stream_queue_buffer(stream,buffer);6. PipeWire 接管 Buffer
Buffer 重新交还给 PipeWire Stream。
PipeWire 后续根据 Stream 方向完成:
播放输出 采集复用 视频帧继续调度7. 等待下一轮 process
当前 Buffer 处理完成后,应用返回process回调。
后续 PipeWire 会继续触发下一轮:
process callback8. Buffer 循环复用
整个过程形成:
dequeue -> process -> queue -> dequeue的循环。
🌻3.2 调用流程图
🌻3.3 Stream Buffer 入队生命周期图
🌻4. 实战应用案例
#include<pipewire/pipewire.h>#include<spa/param/audio/format-utils.h>#include<stdio.h>#include<string.h>structdata{structpw_stream*stream;structspa_hookstream_listener;};staticvoidon_process(void*userdata){structdata*data=userdata;structpw_buffer*buffer;structspa_buffer*spa_buf;void*dst;uint32_tsize;buffer=pw_stream_dequeue_buffer(data->stream);if(!buffer){printf("dequeue buffer failed\n");return;}spa_buf=buffer->buffer;if(!spa_buf||spa_buf->n_datas==0||!spa_buf->datas[0].data){pw_stream_queue_buffer(data->stream,buffer);return;}dst=spa_buf->datas[0].data;size=spa_buf->datas[0].maxsize;/* * 示例:播放场景中填充静音数据 */memset(dst,0,size);spa_buf->datas[0].chunk->offset=0;spa_buf->datas[0].chunk->size=size;spa_buf->datas[0].chunk->stride=4;/* * 处理完成后,必须把 buffer 重新交还给 PipeWire */pw_stream_queue_buffer(data->stream,buffer);}staticconststructpw_stream_eventsstream_events={PW_VERSION_STREAM_EVENTS,.process=on_process,};voidsetup_stream_callback(structdata*data){pw_stream_add_listener(data->stream,&data->stream_listener,&stream_events,data);}intmain(){structdatadata;/* * 假设 PipeWire 已初始化 * 假设 pw_stream 已创建并 connect 成功 */setup_stream_callback(&data);return0;}🌻5. 一句话总结
pw_stream_queue_buffer()本质上是:
“把已经处理完成的 pw_buffer 重新提交回 pw_stream”。
它负责完成 Buffer 从应用侧到 PipeWire Stream 侧的归还动作,是 PipeWire 音频播放、录音采集、Camera 视频帧处理和实时媒体流 Buffer 循环复用中非常关键的基础接口之一。