WebRtc VoiceEngine代码解析
WebRtc中VoiceEngine可以完成大部分的VOIP相关人物,包括采集、自动增益、噪声消除、回声抑制、编解码、RTP传输。下边我们通过代码来解析Voe中处理流程;
创建VoiceEngine和VoEBase
[cpp]
VoiceEngine* _vePtr = VoiceEngine::Create(); //创建VoiceEngine
VoEBase* _veBasePtr = VoEBase::GetInterface(_vePtr); //创建VoeBase 所有Voe相关操作通过这个共有类
_veBasePtr->Init() //创建整个Voe处理线程
VoiceEngine* _vePtr = VoiceEngine::Create(); //创建VoiceEngine
VoEBase* _veBasePtr = VoEBase::GetInterface(_vePtr); //创建VoeBase 所有Voe相关操作通过这个共有类
_veBasePtr->Init() //创建整个Voe处理线程
重点就在_veBasePtr->Init() 它会创建voe线程,线程负责采集、数字信号处理、编码、rtp传输。
[cpp]
int VoEBaseImpl::Init(AudioDeviceModule* external_adm, AudioProcessing* audioproc)
{
_shared->process_thread(); //创建voe线程
_shared->process_thread()->Start();
_shared->audio_device()->Init();
}
int VoEBaseImpl::Init(AudioDeviceModule* external_adm, AudioProcessing* audioproc)
{
_shared->process_thread(); //创建voe线程
_shared->process_thread()->Start();
_shared->audio_device()->Init();
}audio_device()->Init()重载了int32_t AudioDeviceWindowsWave::Init()(windowns平台),别的平台是别的函数,基本差不多,在这个Init中,创建了ThreadProcess线程,ThreadProcess线程负责所有的音频流程,从设备获取音频数据包。
[cpp]
bool AudioDeviceWindowsWave::ThreadProcess()
{
while ((nRecordedBytes = RecProc(recTime)) > 0);
}
bool AudioDeviceWindowsWave::ThreadProcess()
{
while ((nRecordedBytes = RecProc(recTime)) > 0);
}处理过程在RecProc
[cpp]
int32_t AudioDeviceWindowsWave::RecProc(LONGLONG& consumedTime)
{
_ptrAudioBuffer->DeliverRecordedData(); <SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">}</SPAN>
int32_t AudioDeviceWindowsWave::RecProc(LONGLONG& consumedTime)
{
_ptrAudioBuffer->DeliverRecordedData(); }
[cpp]
int32_t AudioDeviceBuffer::DeliverRecordedData()
{
_ptrCbAudioTransport->RecordedDataIsAvailable();
}
int32_t AudioDeviceBuffer::DeliverRecordedData()
{
_ptrCbAudioTransport->RecordedDataIsAvailable();
}
RecordedDataIsAvailable是虚函数,被VoeBase重载
[cpp]
int32_t VoEBaseImpl::RecordedDataIsAvailable(
const void* audioSamples,
uint32_t nSamples,
uint8_t nBytesPerSample,
uint8_t nChannels,
uint32_t samplesPerSec,
uint32_t totalDelayMS,
int32_t clockDrift,
uint32_t currentMicLevel,
bool keyPressed,
uint32_t& newMicLevel)
{
_shared->transmit_mixer()->DemuxAndMix();
_shared->transmit_mixer()->EncodeAndSend();
}
int32_t VoEBaseImpl::RecordedDataIsAvailable(
const void* audioSamples,
uint32_t nSamples,
uint8_t nBytesPerSample,
uint8_t nChannels,
uint32_t samplesPerSec,
uint32_t totalDelayMS,
int32_t clockDrift,
uint32_t currentMicLevel,
bool keyPressed,
uint32_t& newMicLevel)
{
_shared->transmit_mixer()->DemuxAndMix();
_shared->transmit_mixer()->EncodeAndSend();
}
DemuxAndMix() 从字面意思是分路与混合,这个函数,主要负责AudioProcess的所有过程,包括Aec,Aecm,AGC,DTMF,遍历所有channel;
[cpp]
TransmitMixer::DemuxAndMix()
{
Channel* channelPtr = sc.GetFirstChannel(iterator);
while (channelPtr != NULL)
{
if (channelPtr->InputIsOnHold())
{
channelPtr->UpdateLocalTimeStamp();
} else if (channelPtr->Sending())
{
// Demultiplex makes a copy of its input.
channelPtr->Demultiplex(_audioFrame);
channelPtr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
}
channelPtr = sc.GetNextChannel(iterator);
}
}
TransmitMixer::DemuxAndMix()
{
Channel* channelPtr = sc.GetFirstChannel(iterator);
while (channelPtr != NULL)
{
if (channelPtr->InputIsOnHold())
{
channelPtr->UpdateLocalTimeStamp();
} else if (channelPtr->Sending())
{
// Demultiplex makes a copy of its input.
channelPtr->Demultiplex(_audioFrame);
channelPtr->PrepareEncodeAndSend(_audioFrame.sample_rate_hz_);
}
channelPtr = sc.GetNextChannel(iterator);
}
}
Channel::Demutiplex(),基本上没有什么具体任务,就是把audioFrame里边的数据拷贝到channel自身, webrtc是client解决方案,对于client只认为有一个audio source,但可以有多个channel,每个channel中都有audio process,所以需要把数据copy到每个channel.
只有就是数据处理 PrepareEncodeAndSend()
[cpp]
Channel::PrepareEncodeAndSend(int mixingFrequency)
{
if (_inputFilePlaying)
{
MixOrReplaceAudioWithFile(mixingFrequency); //如果使用了voeFile::PlayFileAsMic();则从文件读取10ms数据,并覆盖audio buffer
}
if (_mute)
{
AudioFrameOperations::Mute(_audioFrame);//当然如果设置mutex,则memset 0
}
if (_inputExternalMedia)
{
_inputExternalMediaCallbackPtr->Process(); //所过设置了ExternalMedia,自己的audio处理过程,就是在这里调用的
}
InsertInbandDtmfTone(); //添加DTMF音频
_rtpAudioProc->ProcessStream(&_audioFrame); // 真正的GIPS牛逼代码,audio process过程: Aec Aecm AGC
}
Channel::PrepareEncodeAndSend(int mixingFrequency)
{
if (_inputFilePlaying)
{
MixOrReplaceAudioWithFile(mixingFrequency); //如果使用了voeFile::PlayFileAsMic();则从文件读取10ms数据,并覆盖audio buffer
}
if (_mute)
{
AudioFrameOperations::Mute(_audioFrame);//当然如果设置mutex,则memset 0
}
if (_inputExternalMedia)
{
_inputExternalMediaCallbackPtr->Process(); //所过设置了ExternalMedia,自己的audio处理过程,就是在这里调用的
}
InsertInbandDtmfTone(); //添加DTMF音频
_rtpAudioProc->ProcessStream(&_audioFrame); // 真正的GIPS牛逼代码,audio process过程: Aec Aecm AGC
}
int AudioProcessingImpl::ProcessStream(AudioFrame* frame) 就是上述调用的_rtpAudioProc->ProcessStream();
以上是DemuxAndMix()过程,之后就是EncodeAndSend()过程,至此整个voe数据处理流程分析结束;
关于Audio Process则是另外一个大话题;
总结一下几点:
1. VoeBase提供大部分的对外接口
2. Channel:继承了大部分的音频功能;
WebRtc VoiceEngine代码解析的更多相关文章
- WebRTC VoiceEngine综合应用示例(一)——基本结构分析(转)
把自己这两天学习VoiceEngine的成果分享出来,供大家参考,有什么问题也欢迎大家指出,一起学习一起进步. 本文将对VoiceEngine的基本结构做一个分析,分析的方法是自底向上的:看一个音频编 ...
- VBA常用代码解析
031 删除工作表中的空行 如果需要删除工作表中所有的空行,可以使用下面的代码. Sub DelBlankRow() DimrRow As Long DimLRow As Long Dimi As L ...
- [nRF51822] 12、基础实验代码解析大全 · 实验19 - PWM
一.PWM概述: PWM(Pulse Width Modulation):脉冲宽度调制技术,通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形. PWM 的几个基本概念: 1) 占空比:占空比是指 ...
- [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写
一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...
- [nRF51822] 10、基础实验代码解析大全 · 实验15 - RTC
一.实验内容: 配置NRF51822 的RTC0 的TICK 频率为8Hz,COMPARE0 匹配事件触发周期为3 秒,并使能了TICK 和COMPARE0 中断. TICK 中断中驱动指示灯D1 翻 ...
- [nRF51822] 9、基础实验代码解析大全 · 实验12 - ADC
一.本实验ADC 配置 分辨率:10 位. 输入通道:5,即使用输入通道AIN5 检测电位器的电压. ADC 基准电压:1.2V. 二.NRF51822 ADC 管脚分布 NRF51822 的ADC ...
- java集合框架之java HashMap代码解析
java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...
- Kakfa揭秘 Day8 DirectKafkaStream代码解析
Kakfa揭秘 Day8 DirectKafkaStream代码解析 今天让我们进入SparkStreaming,看一下其中重要的Kafka模块DirectStream的具体实现. 构造Stream ...
- linux内存管理--slab及其代码解析
Linux内核使用了源自于 Solaris 的一种方法,但是这种方法在嵌入式系统中已经使用了很长时间了,它是将内存作为对象按照大小进行分配,被称为slab高速缓存. 内存管理的目标是提供一种方法,为实 ...
随机推荐
- json和jsonp的使用格式
最近一直在看关于json和jsonp的区别和各自的用法.优缺点! 下面是我看到过解释最清楚的一片文章 说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求 ...
- arranging-coins
https://leetcode.com/problems/arranging-coins/ public class Solution { public int arrangeCoins(int n ...
- Spring+Hibernate配置多数据源
配置说明 在实际应用中,经常会用到读写分离,这里就这种情况进行Spring+Hibernate的多数据源配置.此处的配置只是让读的方法操作一个数据库,写的方法操作另外一个数据库. 注:我这里的配置JD ...
- 【笨嘴拙舌WINDOWS】GDI(1)
GDI:Graphics Device Interface 图形设备接口. 操作系统从命令行界面到图形界面的过度是施乐公司实验室对计算机普及作出的不可估量的贡献,苹果公司乔布斯与微软公司比尔盖茨对其的 ...
- 谷歌的ajax.googleapis.com被墙导致访问很多国外网站很慢的解决方法
比如访问StackOverflow, 更比如flexerasoftware.com(导致Visual Studio的打包程序InstallShield Limited Edition不能注册和下载) ...
- UVa 11210 (DFS) Chinese Mahjong
大白书第一章的例题,当时看起来很吃力,现如今A这道题的话怎么写都无所谓了. 思路很简单,就是枚举胡哪张牌,然后枚举一下将牌,剩下如果能找到4个顺子或者刻子就胡了. 由于粗心,34个字符串初始化写错,各 ...
- 详解Android动画之Frame Animation(转)
在开始实例讲解之前,先引用官方文档中的一段话: Frame动画是一系列图片按照一定的顺序展示的过程,和放电影的机制很相似,我们称为逐帧动画.Frame动画可以被定义在XML文件中,也可以完全编码实现. ...
- 【C#学习笔记】从粘贴板复制文本
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- 安装完eclipse,dbwear后,需要在他们解压文件.ini下加上你liux的jdk的安装路径,才能正常使用
-vm/usr/java/jdk/jdk1.6.0_45/bin/java
- 中小型数据库 RMAN CATALOG 备份恢复方案(二)
中小型数据库呈现的是数据库并发少,数据库容量小,版本功能受限以及N多单实例等特点.尽管如此,数据库的损失程度也会存在零丢失的情形.企业不愿意花太多的钱又要保证数据库的可靠稳定,可是苦煞了我这些搞DB的 ...