☰
Linux Gstreamer深度解析之gst_audio_ring_buffer_stop调用流程与实战(七十一)
2026/10/12 3:51:46 网站建设 项目流程

简介:CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀

人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮


🍉🍉🍉文章目录🍉🍉🍉

      • 🌻1.前言
      • 🌻2.应用场景和用法
        • 2.1停止RingBuffer的场景
        • 2.2函数原型与返回语义
      • 🌻3.调用流程剖析
        • 3.1状态切换与子类停止回调
        • 3.2停止与释放、关闭的边界
      • 🌻4.实战案例
        • 4.1准备带停止回调的测试RingBuffer
        • 4.2启动后调用stop并检查结果
        • 4.3完整代码
      • 🌻5.总结

🌻1.前言

本篇目的:理解gst_audio_ring_buffer_stop()如何停止GstAudioRingBuffer中的音频处理,梳理它与RingBuffer状态及子类停止回调的关系,并通过模拟后端观察停止前后的状态变化。

GstAudioRingBuffer的状态可能是运行、暂停、错误或已停止。gst_audio_ring_buffer_stop()负责把运行、暂停或错误状态切换到已停止,并在状态确实发生切换时调用子类的stop虚函数。

它不释放RingBuffer资源,也不关闭设备。资源释放和设备关闭分别由gst_audio_ring_buffer_release()和gst_audio_ring_buffer_close_device()负责。

已采集的音频RingBuffer

gst_audio_ring_buffer_stop

状态切换为STOPPED

子类停止设备处理

RingBuffer保持已采集但不再运行

🌻2.应用场景和用法

2.1停止RingBuffer的场景

gst_audio_ring_buffer_stop()用于停止当前的样本处理。播放端和录制端都可以通过RingBuffer子类停止对应设备上的处理动作。

场景调用时的状态调用后的结果
停止播放STARTED状态切换为STOPPED,子类停止回调执行
暂停后结束PAUSED状态切换为STOPPED,子类停止回调执行
发生错误后停止ERROR状态切换为STOPPED,子类停止回调执行
重复停止已经是STOPPED返回成功,不重复调用子类回调

调用后RingBuffer仍可能持有已采集的设备资源。需要释放这些资源时,应继续调用gst_audio_ring_buffer_release();设备不再使用时,再调用gst_audio_ring_buffer_close_device()。

2.2函数原型与返回语义

函数原型如下:

gbooleangst_audio_ring_buffer_stop(GstAudioRingBuffer*buf);
参数或返回值含义
buf要停止的GstAudioRingBuffer对象
TRUERingBuffer已经停止,或无需执行状态切换
FALSE对象无效,或子类停止回调报告失败

函数会检查buf对象并获取对象锁。只有状态从STARTED、PAUSED或ERROR切换到STOPPED时,才会调用子类的stop虚函数。如果状态已经是STOPPED,函数直接返回TRUE。

调用者不需要重复调用来确保已停止。调用后若还要释放资源,应使用相邻的生命周期接口:

接口职责
gst_audio_ring_buffer_stop()停止样本处理并更新运行状态
gst_audio_ring_buffer_release()释放已经采集的缓冲区和设备资源
gst_audio_ring_buffer_close_device()关闭已经打开的设备

🌻3.调用流程剖析

3.1状态切换与子类停止回调

函数进入后先获取RingBuffer对象锁,再尝试把状态从STARTED切换为STOPPED。

如果当前不是STARTED,函数会继续尝试PAUSED和ERROR状态。若三种状态都不匹配,说明RingBuffer已经停止或无需改变状态,函数直接返回TRUE。

发生状态切换后,基类会唤醒等待中的线程,再调用当前RingBuffer子类的stop虚函数。播放端的通用GstAudioSinkRingBuffer会调用具体Sink的stop方法;没有该方法时会尝试调用reset。录制端的通用GstAudioSrcRingBuffer则会调用具体Source的reset。

是

否

是

否

是

否

当前RingBuffer状态

是否为STARTED

切换到STOPPED

是否为PAUSED或ERROR

已停止并返回TRUE

唤醒等待者并调用子类stop

子类停止成功

返回TRUE

恢复为STARTED并返回FALSE

如果子类停止回调返回失败,基类会把状态恢复为STARTED,然后返回FALSE。因此,FALSE表示停止动作没有成功完成,不应把它当作普通的“当前状态不是运行中”。

3.2停止与释放、关闭的边界

gst_audio_ring_buffer_stop()只处理运行状态和设备停止动作,不清理RingBuffer已采集的内存,也不关闭设备。

在释放流程中,gst_audio_ring_buffer_release()会先调用gst_audio_ring_buffer_stop(),再进入子类的资源释放回调。设备关闭则要求资源已经释放。这三个动作按职责形成停止、释放、关闭的顺序。

正在处理样本

gst_audio_ring_buffer_stop

停止处理

gst_audio_ring_buffer_release

释放RingBuffer资源

gst_audio_ring_buffer_close_device

设备关闭

🌻4.实战案例

4.1准备带停止回调的测试RingBuffer

下面的例子定义一个内存型GstAudioRingBuffer子类。它提供打开、采集、启动、停止、释放和关闭回调,不连接真实声卡。停止回调只记录调用次数,用来区分“状态确实发生切换”和“重复停止直接返回”的行为。

4.2启动后调用stop并检查结果

程序先打开设备并采集缓冲资源,再清除Flushing状态、允许RingBuffer启动。调用gst_audio_ring_buffer_start()后,gst_audio_ring_buffer_stop()应调用子类停止回调一次。

程序随后再次调用停止接口。因为状态已经是STOPPED,第二次调用应返回成功,但停止回调次数仍保持为一次。

4.3完整代码
#include<gst/gst.h>#include<gst/audio/audio.h>typedefstruct_TestRingBuffer{GstAudioRingBuffer parent;guint start_calls;guint stop_calls;}TestRingBuffer;typedefstruct_TestRingBufferClass{GstAudioRingBufferClass parent_class;}TestRingBufferClass;G_DEFINE_TYPE(TestRingBuffer,test_ring_buffer,GST_TYPE_AUDIO_RING_BUFFER);/* 模拟打开设备 */staticgbooleantest_ring_buffer_open_device(GstAudioRingBuffer*buf){returnTRUE;}/* 为测试RingBuffer申请一段内存 */staticgbooleantest_ring_buffer_acquire(GstAudioRingBuffer*buf,GstAudioRingBufferSpec*spec){if(spec->segsize<=0||spec->segtotal<=0)returnFALSE;buf->size=(gsize)spec->segsize*spec->segtotal;buf->memory=g_malloc0(buf->size);returnTRUE;}/* 记录子类启动回调 */staticgbooleantest_ring_buffer_start(GstAudioRingBuffer*buf){TestRingBuffer*test_buffer=(TestRingBuffer*)buf;test_buffer->start_calls++;returnTRUE;}/* 记录子类停止回调 */staticgbooleantest_ring_buffer_stop(GstAudioRingBuffer*buf){TestRingBuffer*test_buffer=(TestRingBuffer*)buf;test_buffer->stop_calls++;returnTRUE;}/* 释放测试后端申请的内存 */staticgbooleantest_ring_buffer_release(GstAudioRingBuffer*buf){g_free(buf->memory);buf->memory=NULL;buf->size=0;returnTRUE;}/* 模拟关闭设备 */staticgbooleantest_ring_buffer_close_device(GstAudioRingBuffer*buf){returnTRUE;}staticvoidtest_ring_buffer_class_init(TestRingBufferClass*klass){GstAudioRingBufferClass*ring_buffer_class=GST_AUDIO_RING_BUFFER_CLASS(klass);ring_buffer_class->open_device=test_ring_buffer_open_device;ring_buffer_class->acquire=test_ring_buffer_acquire;ring_buffer_class->start=test_ring_buffer_start;ring_buffer_class->stop=test_ring_buffer_stop;ring_buffer_class->release=test_ring_buffer_release;ring_buffer_class->close_device=test_ring_buffer_close_device;}staticvoidtest_ring_buffer_init(TestRingBuffer*test_buffer){}intmain(intargc,char*argv[]){TestRingBuffer*test_buffer;GstAudioRingBuffer*ring_buffer;GstAudioRingBufferSpec*spec;gboolean opened=FALSE;gboolean acquired=FALSE;gboolean ok=FALSE;gst_init(&argc,&argv);test_buffer=g_object_new(test_ring_buffer_get_type(),NULL);ring_buffer=GST_AUDIO_RING_BUFFER(test_buffer);spec=&ring_buffer->spec;/* 准备采集规格,S16双声道每个Frame占4字节 */gst_audio_info_init(&spec->info);if(!gst_audio_info_set_format(&spec->info,GST_AUDIO_FORMAT_S16,48000,2,NULL))gotodone;spec->type=GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW;spec->segsize=1024;spec->segtotal=4;spec->seglatency=-1;/* acquire之前先打开设备 */if(!gst_audio_ring_buffer_open_device(ring_buffer))gotodone;opened=TRUE;/* 采集资源并完成基类的RingBuffer初始化 */if(!gst_audio_ring_buffer_acquire(ring_buffer,spec))gotodone;acquired=TRUE;/* 允许启动,并退出初始化时的Flushing状态 */gst_audio_ring_buffer_may_start(ring_buffer,TRUE);gst_audio_ring_buffer_set_flushing(ring_buffer,FALSE);/* 启动后停止,验证子类stop回调被调用 */if(!gst_audio_ring_buffer_start(ring_buffer))gotodone;if(!gst_audio_ring_buffer_stop(ring_buffer))gotodone;/* 已经停止,再调用一次不会重复触发子类stop回调 */if(!gst_audio_ring_buffer_stop(ring_buffer))gotodone;ok=test_buffer->start_calls==1&&test_buffer->stop_calls==1&&!ring_buffer->acquired;/* 释放阶段会再次确认RingBuffer已停止 */if(acquired){gst_audio_ring_buffer_release(ring_buffer);acquired=FALSE;}done:if(acquired)gst_audio_ring_buffer_release(ring_buffer);if(opened)gst_audio_ring_buffer_close_device(ring_buffer);gst_object_unref(ring_buffer);returnok?0:1;}

🌻5.总结

gst_audio_ring_buffer_stop()负责把RingBuffer从运行、暂停或错误状态切换到停止状态,并调用子类停止动作,但不负责释放采集资源或关闭设备。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询