☰
Linux Gstreamer深度解析之gst_audio_ring_buffer_activate调用流程与实战(七十九)
2026/10/17 2:38:30 网站建设 项目流程

简介: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执行激活与停用检查
        • 4.3完整代码
      • 🌻5.总结

🌻1.前言

本篇目的:理解gst_audio_ring_buffer_activate()如何切换GstAudioRingBuffer的激活状态,梳理它与子类虚函数及音频基类的关系,并通过内存后端示例验证激活、重复激活和停用行为。

GstAudioRingBuffer的资源采集和激活是两个阶段。采集阶段准备设备及缓冲区资源;激活阶段通知具体后端开始或停止拉取数据。gst_audio_ring_buffer_activate()不负责申请缓冲区,也不等同于启动音频处理状态。

否

是

已采集的GstAudioRingBuffer

gst_audio_ring_buffer_activate

active状态是否变化

保持当前状态并返回成功

调用子类activate虚函数

更新RingBuffer激活状态

🌻2.应用场景和用法

2.1何时激活或停用RingBuffer

gst_audio_ring_buffer_activate()常由音频基类在设备配置或Pad运行模式切换时调用。

场景调用动作作用
播放端完成Caps设置根据Pad模式调用activate(TRUE)允许后端启动数据拉取
播放端切换到READY调用activate(FALSE)停止后端的数据拉取
播放端重配音频格式先停用旧缓冲区,再释放并重新采集避免旧配置仍在处理数据
子类没有实现activate虚函数基类按成功处理适用于采集阶段已经完成激活工作的后端

传入TRUE时,RingBuffer必须已经采集资源,否则调用失败。传入的目标状态与当前状态相同时,函数返回成功,不会重复调用子类的虚函数。

2.2函数原型与状态语义

函数原型如下:

gbooleangst_audio_ring_buffer_activate(GstAudioRingBuffer*buf,gboolean active);
参数或返回值含义
buf要切换激活状态的RingBuffer对象
activeTRUE表示激活,FALSE表示停用
返回值后端成功切换或状态无需变化时返回TRUE,失败时返回FALSE

调用时,基类获取对象锁。如果请求激活但buf->acquired为FALSE,函数返回失败。如果目标状态已经等于buf->active,函数直接返回成功。

状态需要变化时,基类调用GstAudioRingBufferClass.activate虚函数。该虚函数是可选的:子类没有实现时,基类会按成功处理。虚函数返回失败时,基类不会更新buf->active;返回成功后才保存新的激活状态。

gst_audio_ring_buffer_activate()与相邻接口的职责不同:

接口职责
gst_audio_ring_buffer_acquire()申请RingBuffer及设备资源
gst_audio_ring_buffer_activate()切换后端的数据拉取或激活状态
gst_audio_ring_buffer_start()将音频处理状态切换到开始运行
gst_audio_ring_buffer_pause()暂停音频处理状态
gst_audio_ring_buffer_release()停止并释放采集到的资源

🌻3.调用流程剖析

3.1检查采集状态并分派虚函数

gst_audio_ring_buffer_activate()先验证对象类型,然后获取RingBuffer对象锁。active=TRUE且对象未采集时,基类会报告错误并返回FALSE。停用操作没有这个前置检查,因此可以在清理流程中请求activate(FALSE)。

如果buf->active已经等于请求值,函数直接返回TRUE。状态需要变化时,函数取得对象实际类型对应的GstAudioRingBufferClass,再调用可选的activate虚函数。

是

否

是

否

否

是

传入目标active状态

获取RingBuffer对象锁

请求激活且尚未采集

返回失败

目标状态等于当前状态

返回成功且不调用虚函数

查询子类activate虚函数

执行后端状态切换

后端切换成功

保留原active状态并返回失败

保存新的active状态

基类在调用虚函数时仍持有对象锁。具体后端实现需要遵循对应的锁约定;例如通用GstAudioSink环形缓冲区在停用线程时会暂时释放对象锁,等待线程退出后再重新获取。

3.2音频基类如何使用激活接口

播放端的GstAudioBaseSink会在Caps设置流程中先停用并释放旧RingBuffer,再解析新Caps并重新采集资源。采集成功后,如果当前使用Push模式,基类会调用gst_audio_ring_buffer_activate(TRUE)。

Pull模式则在Pad激活与停用流程中设置或清除RingBuffer回调,并调用相同接口切换激活状态。播放端从PAUSED切换到READY以及从READY切换到NULL时,也会调用停用接口并继续释放资源。

通用GstAudioSink子类的activate(TRUE)实现会启动环形缓冲区线程;activate(FALSE)会通知线程退出并等待线程结束。这里的线程行为属于该子类实现,不是基类函数固定创建的行为。

active状态也不等于RingBuffer的处理状态。gst_audio_ring_buffer_start()会检查acquired、flushing和may_start等条件,再调用start或resume虚函数。激活接口负责后端激活,开始接口负责音频处理状态迁移。

🌻4.实战案例

4.1创建内存RingBuffer测试后端

本案例定义一个不连接真实声卡的RingBuffer子类。后端通过分配内存模拟资源采集,通过记录布尔值模拟激活和停用。

示例重点观察三种行为:首次激活会调用子类虚函数;重复请求相同状态会直接返回成功;停用后,基类和测试后端的激活状态都会变为FALSE。

4.2执行激活与停用检查

程序按照以下步骤运行:

  1. 创建测试RingBuffer,设置S16LE、48kHz、双声道及分段规格。
  2. 打开设备并采集缓冲区资源。
  3. 调用gst_audio_ring_buffer_activate(TRUE),检查RingBuffer与模拟后端均已激活。
  4. 再次请求激活,确认虚函数调用次数没有增加。
  5. 调用gst_audio_ring_buffer_activate(FALSE),检查两侧状态已停用。
  6. 释放资源并关闭设备。

测试中的后端只记录状态,不启动线程或访问硬件,因此它验证的是基类分派和状态更新逻辑,不代表具体音频设备的线程行为已经实测。

4.3完整代码
#include<gst/gst.h>#include<gst/audio/audio.h>#include<string.h>typedefstruct_TestRingBuffer{GstAudioRingBuffer parent;gboolean backend_active;guint activate_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;}/* 为测试后端分配环形缓冲区内存 */staticgbooleantest_ring_buffer_acquire(GstAudioRingBuffer*buf,GstAudioRingBufferSpec*spec){buf->size=spec->segsize*spec->segtotal;buf->memory=g_malloc0(buf->size);returnTRUE;}/* 记录后端收到的激活或停用请求 */staticgbooleantest_ring_buffer_activate(GstAudioRingBuffer*buf,gboolean active){TestRingBuffer*test_buffer=(TestRingBuffer*)buf;test_buffer->backend_active=active;test_buffer->activate_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->activate=test_ring_buffer_activate;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;/* 配置测试格式和环形缓冲区分段参数 */memset(spec,0,sizeof(*spec));gst_audio_info_init(&spec->info);gst_audio_info_set_format(&spec->info,GST_AUDIO_FORMAT_S16,48000,2,NULL);spec->type=GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW;spec->segsize=1024;spec->segtotal=4;spec->seglatency=-1;/* 激活前先打开设备并采集缓冲区资源 */if(!gst_audio_ring_buffer_open_device(ring_buffer))gotodone;opened=TRUE;if(!gst_audio_ring_buffer_acquire(ring_buffer,spec))gotodone;acquired=TRUE;/* 首次激活应调用子类虚函数并更新基类状态 */if(!gst_audio_ring_buffer_activate(ring_buffer,TRUE))gotodone;if(!gst_audio_ring_buffer_is_active(ring_buffer)||!test_buffer->backend_active||test_buffer->activate_calls!=1)gotodone;/* 重复请求当前状态应成功,但不再次调用子类虚函数 */if(!gst_audio_ring_buffer_activate(ring_buffer,TRUE))gotodone;if(test_buffer->activate_calls!=1)gotodone;/* 停用后,基类状态和测试后端状态都应清零 */if(!gst_audio_ring_buffer_activate(ring_buffer,FALSE))gotodone;ok=!gst_audio_ring_buffer_is_active(ring_buffer)&&!test_buffer->backend_active&&test_buffer->activate_calls==2;done:/* 清理时先停用,再释放资源并关闭设备 */if(gst_audio_ring_buffer_is_active(ring_buffer))gst_audio_ring_buffer_activate(ring_buffer,FALSE);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_activate()在资源已采集时分派后端激活或停用操作,并在后端成功后更新RingBuffer的激活状态。

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

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

立即咨询