WebRTC中的scoped_refptr解析

 众所周知,C++中在堆中申请的内存都需要程序员自己手动删除,这是C++容易造成内存泄漏的根本原因。使用过Java的朋友都清楚,Java有完善的内存回收机制,无需程序员调用释放内存的操作。C++里是否能够实现类似Java的自动回收内存的机制呢?答案是肯定的,而Webrtc中的scoped_refptr就是实现类似的功能。

首先我们从这个类的名字入手去理解它的含义。名字由三个单词组成,分别为scope,ref,ptr。

先看ptr,C++程序员都知道这是pointer指针的意思,但是类名中包含指针的语义,这个该如何理解呢?笔者不才,说实话,这个我也是想了好久才弄明白是怎么回事。先说结论吧,在webrtc中,凡是以ptr结尾的类,若以此类创建的非指针对象,均可以当指针对象的语法使用。估计读者有点蒙,下面以实际例子说明。

一般来说,C++中有两种创建对象的方法,一种是创建指针对象

A *a = new A();
a->func();

 另一种是创建非指针对象


A a;
a.func()

    这两种方法创建的对象,对象调用方法的语法是不一样的。一个是以->方式调用,一个是以.方式调用。但是请看:

scoped_refptr<A> temp;
temp->func();

    注意到了吗?temp是以非指针对象的方式创建的,但是它可以使用指针对象的语法调用函数方法。这个是如何实现的呢?这个其实一点也不难,scoped_refptr的代码中实现了operator->的操作符。

T* operator->() const { return ptr_; }

      因此,像这种以ptr结尾的类,最好都以非指针的方式来创建对象。以非指针方式创建对象还有另一个好处,就是当对象离开它所属的作用域时,会自动调用对象的析构函数进行自行销毁。这个也跟接下来要讲的scope单词相关。

     要想弄明白scope的含义,我们要学一个概念,叫RAII。这个概念如果单纯去看这个英文的全名(Resouce Acquisition Is Initialization),会让人莫名其妙,一头雾水。其实就是把一个指向堆内存空间的指针,存放在一个栈空间对象中,通过栈空间对象自动回收的功能,同时回收此指针指向的堆内存的方法。看个简单的例子吧,如果我们在一段作用域代码中创建了一个指针对象,当离开此作用域时,如果该指针没有传递给别的方法时,此时应该显式调用delete对指针进行释放。

A* a = new A();
delete a;
a = NULL;

     虽然对于经验丰富的C++程序员来说,忘记写最后两句的概率并不大,但是这些大量的释放内存的代码嵌在业务代码中也不能忽视。因此就有些人想了个高级的办法把指针的释放封装了起来。做法如下:

首先定义一个类:

class scoped_A{
private:
    A* a;
public:
    scoped_A(A* a){
        this.a = a;
    }
    ~scoped_A(){
        delete a;
        a = NULL;
    }
}

具体用法:


A* a = new A();
scoped_A(a) sa;

或者

scoped_A sa(new A());

    看到了吗?你可以理解为使用一个scoped_A的对象sa把指针对象a包住,当sa离开作用域自动调用scoped_A的析构函数,以达到自动释放a指针的目的。不得不说,这个是很妙的做法。这也是scope的含义,是指这个ptr对象是有范围的,离开了作用域,会自动回收。

    最后来说说ref,ref是引用的意思。在JAVA中,我们经常说一块内存会被多个变量引用,当这块内存没有被任何变量引用的时候,内存将会被垃圾回收机制所回收。在C++中,堆中的一块内存也会被多个指针变量同时引用(指向),有没有办法也像JAVA一样,在这块堆内存没有被任何指针引用时,自动回收呢?这个就要说到Webrtc中的RefCountedObject类了,关于这个类的解释可以看另一篇文章。要想彻底弄懂scoped_refptr,需要两篇文章放在一起看。

    总结:scoped_refptr是一个实现了在C++上自动回收对象内存的功能类。它能够在对象离开作用域时,通过引用计数器来判断是否回收堆中内存,实现了类似Java的垃圾回收的机制。

### WebRTC VAD 使用示例代码 WebRTC VAD (Voice Activity Detection) 是一种用于区分语音和非语音音频片段的技术。下面展示如何使用 C++ 和 Python 实现基于 WebRTC 的 VAD 功能。 #### C++ 示例代码 对于C++环境下的VAD应用,可以参考如下简化版的实现方式[^1]: ```cpp #include "webrtc/modules/audio_processing/include/audio_processing.h" #include "api/array_view.h" // 初始化AudioProcessing模块并设置参数 rtc::scoped_refptr<AudioProcessing> apm(AudioProcessing::Create()); apm->voice_detection()->Enable(true); apm->set_stream_delay_ms(0); // 假设有一个输入音频帧data_in, 需要进行VAD处理 std::vector<int16_t> data_in; bool is_speech; // 调用ProcessStream方法来获取当前音频帧是否为语音的结果 if (!apm->ProcessReverseStream(rtc::ArrayView<const int16_t>(data_in))) { // 处理错误情况... } is_speech = apm->voice_detection()->stream_has_voice(); ``` 此段代码展示了创建 `AudioProcessing` 对象以及配置其属性的过程,并通过调用 `ProcessReverseStream()` 方法完成实际的数据流分析工作。最后利用 `stream_has_voice()` 函数判断该数据包内是否存在有效的人声信号。 #### Python 示例代码 如果倾向于采用更便捷的语言如Python,则可借助第三方库py-webrtcvad快速搭建原型系统[^3]: ```python import webrtcvad import collections def read_wave(path): """读取wav文件""" import wave with wave.open(path,'rb') as wf: num_channels = wf.getnchannels() assert num_channels == 1 sample_width = wf.getsampwidth() assert sample_width == 2 sample_rate = wf.getframerate() frames = wf.readframes(wf.getnframes()) return frames,sample_rate def frame_generator(frame_duration_ms,audio,batch_size=8000): n = int(batch_size * (frame_duration_ms / 1000.0)) offset = 0 while offset + n < len(audio): yield audio[offset : offset+n] offset += n def vad_collector(sample_rate,frame_duration_ms,padding_duration_ms,vad,frames): num_padding_frames = int(padding_duration_ms/frame_duration_ms) ring_buffer = collections.deque(maxlen=num_padding_frames) triggered=False voiced_frames=[] for frame in frames: is_speech=vad.is_speech(frame,sample_rate) if not triggered: ring_buffer.append((frame,is_speech)) if sum([vf[1]for vf in list(ring_buffer)])>=ring_buffer.maxlen*0.9: triggered=True for f,_ in ring_buffer: voiced_frames.append(f) ring_buffer.clear() elif triggered: voiced_frames.append(frame) ring_buffer.append((frame,is_speech)) if sum([vf[1]for vf in list(ring_buffer)])<=ring_buffer.maxlen*0.1: triggered=False ring_buffer.clear() return b''.join(voiced_frames) # 创建一个新的VAD实例,默认模式为aggressive level 3 vad = webrtcvad.Vad(3) audio_data, sr=read_wave('test.wav') frames=list(frame_generator(30,audio_data)) # 将音频分割成每30ms一帧 voiced_audio=vad_collector(sr,30,300,vad,frames) # 获取仅含有人声部分的新音频序列 ``` 上述脚本实现了从WAV文件加载原始音频样本到执行VAD算法过滤静音区间的全过程。其中定义了一些辅助函数帮助解析波形文件结构、按固定时间间隔切分音频流以及累积连续多帧内的状态变化趋势以便做出更加精准的声音事件判定逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值