Linux Gstreamer深度解析之gst_audio_ring_buffer_activate调用流程与实战(七十九)

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

博主新书推荐:《Android系统多媒体进阶实战》🚀

Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀

Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀

专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀

专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀

专题四:Android15快速自定义与集成音效实战课 🚀

专题五:Android15音频策略实战课 🚀

专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

🌻1.前言

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

GstAudioRingBuffer的资源采集和激活是两个阶段。采集阶段准备设备及缓冲区资源;激活阶段通知具体后端开始或停止拉取数据。gst_audio_ring_buffer_activate()不负责申请缓冲区,也不等同于启动音频处理状态。
#mermaid-svg-KmFU5PMdBNk13f5h{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KmFU5PMdBNk13f5h .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KmFU5PMdBNk13f5h .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KmFU5PMdBNk13f5h .error-icon{fill:#552222;}#mermaid-svg-KmFU5PMdBNk13f5h .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KmFU5PMdBNk13f5h .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KmFU5PMdBNk13f5h .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KmFU5PMdBNk13f5h .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KmFU5PMdBNk13f5h .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KmFU5PMdBNk13f5h .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KmFU5PMdBNk13f5h .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KmFU5PMdBNk13f5h .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KmFU5PMdBNk13f5h .marker.cross{stroke:#333333;}#mermaid-svg-KmFU5PMdBNk13f5h svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KmFU5PMdBNk13f5h p{margin:0;}#mermaid-svg-KmFU5PMdBNk13f5h .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KmFU5PMdBNk13f5h .cluster-label text{fill:#333;}#mermaid-svg-KmFU5PMdBNk13f5h .cluster-label span{color:#333;}#mermaid-svg-KmFU5PMdBNk13f5h .cluster-label span p{background-color:transparent;}#mermaid-svg-KmFU5PMdBNk13f5h .label text,#mermaid-svg-KmFU5PMdBNk13f5h span{fill:#333;color:#333;}#mermaid-svg-KmFU5PMdBNk13f5h .node rect,#mermaid-svg-KmFU5PMdBNk13f5h .node circle,#mermaid-svg-KmFU5PMdBNk13f5h .node ellipse,#mermaid-svg-KmFU5PMdBNk13f5h .node polygon,#mermaid-svg-KmFU5PMdBNk13f5h .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KmFU5PMdBNk13f5h .rough-node .label text,#mermaid-svg-KmFU5PMdBNk13f5h .node .label text,#mermaid-svg-KmFU5PMdBNk13f5h .image-shape .label,#mermaid-svg-KmFU5PMdBNk13f5h .icon-shape .label{text-anchor:middle;}#mermaid-svg-KmFU5PMdBNk13f5h .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KmFU5PMdBNk13f5h .rough-node .label,#mermaid-svg-KmFU5PMdBNk13f5h .node .label,#mermaid-svg-KmFU5PMdBNk13f5h .image-shape .label,#mermaid-svg-KmFU5PMdBNk13f5h .icon-shape .label{text-align:center;}#mermaid-svg-KmFU5PMdBNk13f5h .node.clickable{cursor:pointer;}#mermaid-svg-KmFU5PMdBNk13f5h .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KmFU5PMdBNk13f5h .arrowheadPath{fill:#333333;}#mermaid-svg-KmFU5PMdBNk13f5h .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KmFU5PMdBNk13f5h .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KmFU5PMdBNk13f5h .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KmFU5PMdBNk13f5h .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KmFU5PMdBNk13f5h .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KmFU5PMdBNk13f5h .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KmFU5PMdBNk13f5h .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KmFU5PMdBNk13f5h .cluster text{fill:#333;}#mermaid-svg-KmFU5PMdBNk13f5h .cluster span{color:#333;}#mermaid-svg-KmFU5PMdBNk13f5h div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KmFU5PMdBNk13f5h .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KmFU5PMdBNk13f5h rect.text{fill:none;stroke-width:0;}#mermaid-svg-KmFU5PMdBNk13f5h .icon-shape,#mermaid-svg-KmFU5PMdBNk13f5h .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KmFU5PMdBNk13f5h .icon-shape p,#mermaid-svg-KmFU5PMdBNk13f5h .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KmFU5PMdBNk13f5h .icon-shape .label rect,#mermaid-svg-KmFU5PMdBNk13f5h .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KmFU5PMdBNk13f5h .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KmFU5PMdBNk13f5h .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KmFU5PMdBNk13f5h :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
已采集的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函数原型与状态语义

函数原型如下:

c 复制代码
gboolean
gst_audio_ring_buffer_activate (GstAudioRingBuffer *buf,
                               gboolean active);
参数或返回值 含义
buf 要切换激活状态的RingBuffer对象
active TRUE表示激活,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虚函数。
#mermaid-svg-JgdiPWUWVUG2kbfc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JgdiPWUWVUG2kbfc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JgdiPWUWVUG2kbfc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JgdiPWUWVUG2kbfc .error-icon{fill:#552222;}#mermaid-svg-JgdiPWUWVUG2kbfc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JgdiPWUWVUG2kbfc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JgdiPWUWVUG2kbfc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JgdiPWUWVUG2kbfc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JgdiPWUWVUG2kbfc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JgdiPWUWVUG2kbfc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JgdiPWUWVUG2kbfc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JgdiPWUWVUG2kbfc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JgdiPWUWVUG2kbfc .marker.cross{stroke:#333333;}#mermaid-svg-JgdiPWUWVUG2kbfc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JgdiPWUWVUG2kbfc p{margin:0;}#mermaid-svg-JgdiPWUWVUG2kbfc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JgdiPWUWVUG2kbfc .cluster-label text{fill:#333;}#mermaid-svg-JgdiPWUWVUG2kbfc .cluster-label span{color:#333;}#mermaid-svg-JgdiPWUWVUG2kbfc .cluster-label span p{background-color:transparent;}#mermaid-svg-JgdiPWUWVUG2kbfc .label text,#mermaid-svg-JgdiPWUWVUG2kbfc span{fill:#333;color:#333;}#mermaid-svg-JgdiPWUWVUG2kbfc .node rect,#mermaid-svg-JgdiPWUWVUG2kbfc .node circle,#mermaid-svg-JgdiPWUWVUG2kbfc .node ellipse,#mermaid-svg-JgdiPWUWVUG2kbfc .node polygon,#mermaid-svg-JgdiPWUWVUG2kbfc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JgdiPWUWVUG2kbfc .rough-node .label text,#mermaid-svg-JgdiPWUWVUG2kbfc .node .label text,#mermaid-svg-JgdiPWUWVUG2kbfc .image-shape .label,#mermaid-svg-JgdiPWUWVUG2kbfc .icon-shape .label{text-anchor:middle;}#mermaid-svg-JgdiPWUWVUG2kbfc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JgdiPWUWVUG2kbfc .rough-node .label,#mermaid-svg-JgdiPWUWVUG2kbfc .node .label,#mermaid-svg-JgdiPWUWVUG2kbfc .image-shape .label,#mermaid-svg-JgdiPWUWVUG2kbfc .icon-shape .label{text-align:center;}#mermaid-svg-JgdiPWUWVUG2kbfc .node.clickable{cursor:pointer;}#mermaid-svg-JgdiPWUWVUG2kbfc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JgdiPWUWVUG2kbfc .arrowheadPath{fill:#333333;}#mermaid-svg-JgdiPWUWVUG2kbfc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JgdiPWUWVUG2kbfc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JgdiPWUWVUG2kbfc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JgdiPWUWVUG2kbfc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JgdiPWUWVUG2kbfc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JgdiPWUWVUG2kbfc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JgdiPWUWVUG2kbfc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JgdiPWUWVUG2kbfc .cluster text{fill:#333;}#mermaid-svg-JgdiPWUWVUG2kbfc .cluster span{color:#333;}#mermaid-svg-JgdiPWUWVUG2kbfc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JgdiPWUWVUG2kbfc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JgdiPWUWVUG2kbfc rect.text{fill:none;stroke-width:0;}#mermaid-svg-JgdiPWUWVUG2kbfc .icon-shape,#mermaid-svg-JgdiPWUWVUG2kbfc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JgdiPWUWVUG2kbfc .icon-shape p,#mermaid-svg-JgdiPWUWVUG2kbfc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JgdiPWUWVUG2kbfc .icon-shape .label rect,#mermaid-svg-JgdiPWUWVUG2kbfc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JgdiPWUWVUG2kbfc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JgdiPWUWVUG2kbfc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JgdiPWUWVUG2kbfc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
否
是
传入目标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完整代码
c 复制代码
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include <string.h>

typedef struct _TestRingBuffer
{
  GstAudioRingBuffer parent;
  gboolean backend_active;
  guint activate_calls;
} TestRingBuffer;

typedef struct _TestRingBufferClass
{
  GstAudioRingBufferClass parent_class;
} TestRingBufferClass;

G_DEFINE_TYPE (TestRingBuffer, test_ring_buffer,
    GST_TYPE_AUDIO_RING_BUFFER);

/* 模拟设备打开 */
static gboolean
test_ring_buffer_open_device (GstAudioRingBuffer *buf)
{
  return TRUE;
}

/* 为测试后端分配环形缓冲区内存 */
static gboolean
test_ring_buffer_acquire (GstAudioRingBuffer *buf,
    GstAudioRingBufferSpec *spec)
{
  buf->size = spec->segsize * spec->segtotal;
  buf->memory = g_malloc0 (buf->size);

  return TRUE;
}

/* 记录后端收到的激活或停用请求 */
static gboolean
test_ring_buffer_activate (GstAudioRingBuffer *buf,
    gboolean active)
{
  TestRingBuffer *test_buffer = (TestRingBuffer *) buf;

  test_buffer->backend_active = active;
  test_buffer->activate_calls++;

  return TRUE;
}

/* 释放测试后端申请的内存 */
static gboolean
test_ring_buffer_release (GstAudioRingBuffer *buf)
{
  g_free (buf->memory);
  buf->memory = NULL;
  buf->size = 0;

  return TRUE;
}

/* 模拟设备关闭 */
static gboolean
test_ring_buffer_close_device (GstAudioRingBuffer *buf)
{
  return TRUE;
}

static void
test_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;
}

static void
test_ring_buffer_init (TestRingBuffer *test_buffer)
{
}

int
main (int argc, 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))
    goto done;
  opened = TRUE;

  if (!gst_audio_ring_buffer_acquire (ring_buffer, spec))
    goto done;
  acquired = TRUE;

  /* 首次激活应调用子类虚函数并更新基类状态 */
  if (!gst_audio_ring_buffer_activate (ring_buffer, TRUE))
    goto done;

  if (!gst_audio_ring_buffer_is_active (ring_buffer)
      || !test_buffer->backend_active
      || test_buffer->activate_calls != 1)
    goto done;

  /* 重复请求当前状态应成功,但不再次调用子类虚函数 */
  if (!gst_audio_ring_buffer_activate (ring_buffer, TRUE))
    goto done;

  if (test_buffer->activate_calls != 1)
    goto done;

  /* 停用后,基类状态和测试后端状态都应清零 */
  if (!gst_audio_ring_buffer_activate (ring_buffer, FALSE))
    goto done;

  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);

  return ok ? 0 : 1;
}

🌻5.总结

gst_audio_ring_buffer_activate()在资源已采集时分派后端激活或停用操作,并在后端成功后更新RingBuffer的激活状态。

相关推荐
小天源1 小时前
智叟云集政策监测技术方案——原文解析、证据提取与可核验摘要
java·服务器·数据库
阿乔外贸日记1 小时前
美国买家资产包装套路与应收款尽调框架,580万应收账款案例解析
大数据·服务器·人工智能·microsoft·云计算
小羊没烦恼!1 小时前
在.net中读写config文件的各种方法
java·大数据·运维·服务器·前端·数据库·oracle
Escalating_xu1 小时前
【Linux 网络编程】网络命令加餐:用 ping、netstat、watch 和 pidof 排查服务问题
linux·运维·网络
mounter6251 小时前
现代 Linux 内核在异构内存与硬件演进下的架构变革:压缩 RAM、CXL 与分布式内存
linux·linux kernel·kernel
YH行业报告分析1 小时前
2026两轴Delta并联机器人深度分析:高速分拣场景下的轻量化自动化升级路径
运维·机器人·自动化
nece0011 小时前
vbox 为虚拟机配置网络
运维·服务器·网络
racerun2 小时前
用于图片上传到服务器
运维·服务器
迅猛龙办公室2 小时前
Python实现PM空气质量提醒
服务器·前端·python