)
简介CSDN博客专家、《Android系统多媒体进阶实战》作者博主新书推荐《Android系统多媒体进阶实战》Android Audio工程师专栏地址Audio工程师进阶系列【原创干货持续更新中……】Android多媒体专栏地址多媒体系统工程师系列【原创干货持续更新中……】专题一 二AAOS车载系统AOSP14系统攻城狮入门视频实战课专题三Android14 Binder之HIDL与AIDL通信实战课专题四Android15快速自定义与集成音效实战课专题五Android15音频策略实战课专题六Android15音频性能实战课(无声/杂音/断音/爆音实战案例)人生格言人生从来没有捷径只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注Android系统攻城狮文章目录1.前言2.应用场景和用法2.1先打开设备再获取缓冲区资源2.2函数原型与状态变化3.调用流程剖析3.1基类检查状态并分派虚函数3.2设备打开后再获取缓冲区资源4.实战案例4.1定义测试RingBuffer子类4.2打开并关闭设备状态4.3完整代码5.总结1.前言本篇目的理解gst_audio_ring_buffer_open_device()如何检查GstAudioRingBuffer状态、分派到具体子类的设备打开方法并通过一个不依赖真实声卡的子类Demo验证这个调用过程。GstAudioRingBuffer是音频源和音频接收端使用的环形缓冲区基类。它把设备访问和环形缓冲区资源管理分成两个阶段先打开设备再获取并配置缓冲区资源。gst_audio_ring_buffer_open_device()负责打开与RingBuffer关联的设备并调用具体子类提供的open_device虚函数。它不会设置音频格式也不会分配环形缓冲区内存。设备参数和缓冲区资源由后续的gst_audio_ring_buffer_acquire()处理。GstAudioRingBuffer对象gst_audio_ring_buffer_open_device检查open状态并分派虚函数具体子类打开设备设备进入open状态2.应用场景和用法2.1先打开设备再获取缓冲区资源设备打开和RingBuffer资源获取解决的是两个不同问题阶段接口主要职责打开设备gst_audio_ring_buffer_open_device()调用具体子类的设备打开方法获取资源gst_audio_ring_buffer_acquire()配置音频格式并准备RingBuffer资源释放资源gst_audio_ring_buffer_release()释放已获取的RingBuffer资源关闭设备gst_audio_ring_buffer_close_device()调用具体子类的设备关闭方法调用顺序是先打开设备再获取缓冲区资源。关闭时顺序相反先释放资源再关闭设备。应用通常通过GstAudioBaseSrc或GstAudioBaseSink间接使用RingBuffer。直接调用该接口的代码通常位于具体音频设备子类或专门的测试程序中。2.2函数原型与状态变化函数原型如下gbooleangst_audio_ring_buffer_open_device(GstAudioRingBuffer*buf);参数或返回值含义buf要打开设备的GstAudioRingBuffer对象必须是有效实例返回值设备打开成功或RingBuffer已经处于打开状态时返回TRUE失败时返回FALSE调用前RingBuffer必须尚未获取资源。调用成功后基类的open状态变为TRUE。调用失败时基类会把open恢复为FALSE。如果设备已经打开函数会发出警告并返回TRUE不会再次调用子类的open_device虚函数。因此返回TRUE也可能表示对象原本就已打开而不是本次执行了设备打开操作。相邻接口的职责边界需要区分清楚open_device()打开设备acquire()准备格式和缓冲区资源release()释放缓冲区资源close_device()关闭设备。gst_audio_ring_buffer_device_is_open()只查询基类记录的设备打开状态。3.调用流程剖析3.1基类检查状态并分派虚函数gst_audio_ring_buffer_open_device()首先通过GST_IS_AUDIO_RING_BUFFER()检查参数类型。参数有效后函数获取对象锁并检查buf-open。若设备已经打开函数直接返回TRUE。若设备尚未打开基类先将buf-open设为TRUE再从对象类型中取得GstAudioRingBufferClass调用其open_device虚函数。GST_OBJECT_LOCK(buf);if(buf-open)gotowas_opened;buf-openTRUE;rclassGST_AUDIO_RING_BUFFER_GET_CLASS(buf);if(rclass-open_device)resrclass-open_device(buf);if(!res){buf-openFALSE;gotodone;}GST_OBJECT_UNLOCK(buf);returnres;基类持有对象锁执行状态检查和虚函数分派。真正如何打开设备由具体子类实现。对于ALSA后端子类可以在虚函数中打开ALSA设备对于其他后端则由对应实现执行其设备操作。基类本身不选择设备后端也不直接配置音频参数。如果子类的打开方法返回FALSE基类会撤销open状态再把失败结果返回给调用者。是否成功失败传入RingBuffer对象检查对象类型并获取对象锁设备是否已经打开返回TRUE并结束设置open并调用子类虚函数子类打开结果保留open状态并返回TRUE恢复open为FALSE并返回FALSE3.2设备打开后再获取缓冲区资源open_device()成功后设备处于已打开状态但RingBuffer的资源还没有获取。gst_audio_ring_buffer_acquire()会检查buf-open如果设备未打开它会返回失败。通过检查后acquire()再调用子类的acquire虚函数并由基类完成时间戳数组、空白音频段等环形缓冲区状态的准备。关闭设备时gst_audio_ring_buffer_close_device()要求RingBuffer已释放。如果buf-acquired仍为TRUE关闭会失败释放资源之后关闭接口才会调用子类的close_device虚函数。设备尚未打开gst_audio_ring_buffer_open_device设备已打开gst_audio_ring_buffer_acquireRingBuffer资源已获取gst_audio_ring_buffer_releasegst_audio_ring_buffer_close_device4.实战案例4.1定义测试RingBuffer子类GstAudioRingBuffer是抽象基类不能直接创建实例。Demo定义一个最小子类并实现open_device和close_device虚函数。虚函数只记录调用次数不访问真实声卡因此案例验证的是基类状态管理和虚函数分派。4.2打开并关闭设备状态测试按以下顺序执行创建自定义RingBuffer子类实例。调用gst_audio_ring_buffer_open_device()并通过gst_audio_ring_buffer_device_is_open()检查打开状态。调用gst_audio_ring_buffer_close_device()验证关闭状态以及两个虚函数各执行一次。该Demo不调用gst_audio_ring_buffer_acquire()因此不会分配RingBuffer资源。真实后端的设备访问和资源获取应由对应子类完成。4.3完整代码#includegst/gst.h#includegst/audio/audio.htypedefstruct_TestRingBuffer{GstAudioRingBuffer parent;}TestRingBuffer;typedefstruct_TestRingBufferClass{GstAudioRingBufferClass parent_class;}TestRingBufferClass;G_DEFINE_TYPE(TestRingBuffer,test_ring_buffer,GST_TYPE_AUDIO_RING_BUFFER);/* 记录基类是否正确分派到设备打开虚函数 */staticguint open_calls;/* 记录基类是否正确分派到设备关闭虚函数 */staticguint close_calls;staticgbooleantest_ring_buffer_open_device(GstAudioRingBuffer*buf){(void)buf;open_calls;returnTRUE;}staticgbooleantest_ring_buffer_close_device(GstAudioRingBuffer*buf){(void)buf;close_calls;returnTRUE;}staticvoidtest_ring_buffer_class_init(TestRingBufferClass*klass){GstAudioRingBufferClass*ringbuffer_classGST_AUDIO_RING_BUFFER_CLASS(klass);/* 注册测试用设备操作避免访问真实声卡 */ringbuffer_class-open_devicetest_ring_buffer_open_device;ringbuffer_class-close_devicetest_ring_buffer_close_device;}staticvoidtest_ring_buffer_init(TestRingBuffer*self){(void)self;}intmain(intargc,char*argv[]){GstAudioRingBuffer*ringbuffer;gboolean okFALSE;gst_init(argc,argv);/* 创建实现了设备操作虚函数的RingBuffer子类 */ringbufferg_object_new(TEST_TYPE_RING_BUFFER,NULL);/* 调用基类接口触发子类的open_device虚函数 */if(!gst_audio_ring_buffer_open_device(ringbuffer))gotodone;/* 确认基类已经记录设备处于打开状态 */if(!gst_audio_ring_buffer_device_is_open(ringbuffer))gotodone;/* 关闭前确保RingBuffer资源已释放 */if(!gst_audio_ring_buffer_close_device(ringbuffer))gotodone;/* 确认基类已清除设备打开状态 */if(gst_audio_ring_buffer_device_is_open(ringbuffer))gotodone;/* 两个虚函数各调用一次证明基类完成了方法分派 */ok(open_calls1close_calls1);done:/* 失败路径也清理可能已经打开的设备 */if(gst_audio_ring_buffer_device_is_open(ringbuffer))gst_audio_ring_buffer_close_device(ringbuffer);gst_object_unref(ringbuffer);returnok?0:1;}5.总结gst_audio_ring_buffer_open_device()负责检查并更新GstAudioRingBuffer的设备打开状态再将实际打开操作分派给具体子类。