-
webrtc混音混流
2020-11-28 10:29:13webRTC混音流程 https://blog.csdn.net/u013692429/article/details/100778297 原因:由于目前开始调研混音算法,故在此分析一下webRTC的实现流程,其他实现流程在另外一个博客有记录. 概况:目前调研的混音...webRTC混音流程
https://blog.csdn.net/u013692429/article/details/100778297
原因:由于目前开始调研混音算法,故在此分析一下webRTC的实现流程,其他实现流程在另外一个博客有记录.
概况:目前调研的混音算法在多路混音时只有webRtc的原理符合基本流程。webRtc充分考虑了人耳在同一时间内最多只能感知3路音频的特性,故在多路混音时选择三路能力值最大的作为主要混音,其余参与者判断是否上一帧参与过混音,如果参与过则当前帧进行淡出特性,然后一起进行混音.而最终的混音算法就是简单的线性叠加做饱和运算.
代码分析:
主要实现文件在webrtc/modules/audio_conference_mixer目录.依赖的头文件主要有audio_conference_mixer_defines.h,该文件中主要定义了MixerParticipan和AudioMixerOutputRecevier两个类,该两个类主要定义了混音数据的对象来源和混音后数据的接收.调用逻辑通过TimeUnitNextProcess和Process方法进行调用,所以重点实现在process方法中.主要方法伪代码如下:
-
webRTC混音流程
2019-09-12 17:25:51原因:由于目前开始调研混音算法,故在此分析一下webRTC的实现流程,其他实现流程在另外一个博客有记录. 概况:目前调研的混音算法在多路混音时只有webRtc的原理符合基本流程。webRtc充分考虑了人耳在同一时间内...原因:由于目前开始调研混音算法,故在此分析一下webRTC的实现流程,其他实现流程在另外一个博客有记录.
概况:目前调研的混音算法在多路混音时只有webRtc的原理符合基本流程。webRtc充分考虑了人耳在同一时间内最多只能感知3路音频的特性,故在多路混音时选择三路能力值最大的作为主要混音,其余参与者判断是否上一帧参与过混音,如果参与过则当前帧进行淡出特性,然后一起进行混音.而最终的混音算法就是简单的线性叠加做饱和运算.
代码分析:
主要实现文件在webrtc/modules/audio_conference_mixer目录.依赖的头文件主要有audio_conference_mixer_defines.h,该文件中主要定义了MixerParticipan和AudioMixerOutputRecevier两个类,该两个类主要定义了混音数据的对象来源和混音后数据的接收.调用逻辑通过TimeUnitNextProcess和Process方法进行调用,所以重点实现在process方法中.主要方法伪代码如下:
void AudioConferenceMixerImpl::Process() { UpdateToMix(&mixList, &rampOutList, &mixedParticipantsMap, &remainingParticipantsAllowedToMix); MixFromList(mixedAudio, mixList); MixAnonomouslyFromList(mixedAudio, additionalFramesList); MixAnonomouslyFromList(mixedAudio, rampOutList); }
UpdateToMix是为了将参与会话成员按需求分配到mixList,rampOutList,mixList就是重点需要进行mix的会话成员,而rampOutList是上一帧参与会话,当前帧将该会话进行淡出处理,所以重点分析UpdateToMix方法代码如下:通过代码可以看出首先进行判断当前会话上一帧是否参与了mix,如果没有则将进行RampIn特效处理,然后加入activeList队列,在加入过程前判断队列是否达到了限制的最大值,如果达到则将移除能量值最小的会话成员,而在移除过程中也要判断移除的会话成员上一帧是否参与了mix,如果参与了则将该会话当前帧做RampOut处理.
void AudioConferenceMixerImpl::UpdateToMix( AudioFrameList* mixList, AudioFrameList* rampOutList, std::map<int, MixerParticipant*>* mixParticipantList, size_t* maxAudioFrameCounter) const { for (MixerParticipantList::const_iterator participant = _participantList.begin(); participant != _participantList.end(); ++participant) { if(audioFrame->vad_activity_ == AudioFrame::kVadActive) { if(!wasMixed && !muted) { RampIn(*audioFrame); } if(activeList.size() >= *maxAudioFrameCounter) { if (replaceWasMixed) { if (!replaceFrame.muted) { RampOut(*replaceFrame.frame); } rampOutList->push_back(replaceFrame); } } }
最后将当前两个队列成员进行mix处理.主要代码如下:可以看出进行了简单的合并.
void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) { if (use_limiter) { // This is to avoid saturation in the mixing. It is only // meaningful if the limiter will be used. AudioFrameOperations::ApplyHalfGain(frame); } if (mixed_frame->num_channels_ > frame->num_channels_) { // We only support mono-to-stereo. assert(mixed_frame->num_channels_ == 2 && frame->num_channels_ == 1); AudioFrameOperations::MonoToStereo(frame); } } void AudioFrameOperations::Add(const AudioFrame& frame_to_add, AudioFrame* result_frame) { for (size_t i = 0; i < result_frame->samples_per_channel_ * result_frame->num_channels_; i++) { const int32_t wrap_guard = static_cast<int32_t>(result_frame->data_[i]) + static_cast<int32_t>(frame_to_add.data_[i]); result_frame->data_[i] = rtc::saturated_cast<int16_t>(wrap_guard); }
按照webRTC混音原理通过简单代码实现,4路进行混音最终生成的波形如下
利用FFmpeg命令行生成如下:可以明显看出波形衰减严重。
总结:webRTC混音原理通过代码可以大体分析出,可以根据原理自己实现一个混音算法。
-
WebRTC 混音分析
2018-05-04 21:12:51webrtc网站被和谐, 直接上github查找有没有人fork, 然后找到一个比较新的版本 ...没有下载代码, 直接用手机在网页上查看代码, 虽然不方便,但也找到混音处理代码. 简单写一下大概过程, 详细的在以后有用到...webrtc网站被和谐, 直接上github查找有没有人fork, 然后找到一个比较新的版本
https://github.com/JumpingYang001/webrtc
https://github.com/ibaoger/webrtc (这个好像每天都更新)没有下载代码, 直接用手机在网页上查看代码, 虽然不方便,但也找到混音处理代码.
简单写一下大概过程, 详细的在以后有用到时再研究吧。
因为是在手机上看的代码,可能理解有误,等有空再仔细在电脑上深入研究。混音对象:
media/engie/webrtcvoiceengine.cc void WebRtcVoiceEngine::Init() { ... config.audio_mixer = webrtc::AudioMixerImpl::Create(); ... }
混音类:
modules/audio_mixer/audio_mixer_impl.cc AudioMixerImpl::Mix()
Mix方法调用:
modules/audio_mixer/frame_combiner.cc FrameCombiner::Combine()
Combine方法:
调用MixToFloatFrame进行合并, MixToFloatFrame只是简单的把数据相加, 然后调用RunApmAgcLimiter或RunApmAgc2Limiter对混音结果进行增益处理, 同时应该可以防止溢出.
调用InterleaveToAudioFrame根据音频声道交织处理混音结果.
最后混音的结果在audio_frame_for_mixing中. -
WebRTC中混音流程分析
2019-01-14 10:00:51混音分为服务端混音和客户端混音两种,服务端混音是为了节省带宽。...WebRTC中目前只有客户端混音,混音具体实现在webrtc/modules/audio_conference_mixer目录中 想知道一个C++模块如何使用,我们一...混音分为服务端混音和客户端混音两种,服务端混音是为了节省带宽。哪为什么客户端也要混音呢?哪是国为声卡同一时刻只能播放一路
语音,当你的客户端有多路接收语音时,如果你不先混音,而是每一路都直接住声卡送的话,容易会造成声音越来越延时。WebRTC中目前只有客户端混音,混音具体实现在webrtc/modules/audio_conference_mixer目录中
想知道一个C++模块如何使用,我们一般会先看看这个模块的头文件,在audio_conference_mixer模块的include目录下有两个头文件
audio_conference_mixer.h 和 audio_conference_mixer_defines.h,我们先来看看audio_conference_mixer_defines.h,在这个文件
中定义了两个类
MixerParticipant:被混音方,负责给混音器提供原始语音数据
AudioMixerOutputReceiver:混音后的语音接收方在audio_conference_mixer.h文件中定义了AudioConferenceMixer类,它继承于Module类,说明这个类的对象可以被WebRTC的工作线
程周期性的调用。在这个类定义中,被混音方的添加和删除用SetMixabilityStatus(MixerParticipant* participant,bool mixable)方法来实现,这个方法中
第一个参数是被混音对象指针,第二个参数是是否能被混音。添加接收方使用RegisterMixedStreamCallback(AudioMixerOutputReceiver* receiver),参数代表接收者对象
另外我们还发现这两个方法
// Module functions
int64_t TimeUntilNextProcess() override = 0;
void Process() override = 0;从上面几个方法,我们就可能想象出这个混音模块大概的工作流程,WebRTC工作线程先调用混音模块的TimeUntilNextProcess方法,先确认是否到了处理
这个模块的时间,如果还没有到时间,就直接处理下一个模块 ,如果到了时间,就调用这个模块的Process方法,在Process方法中,会从所有的等待混音对象
中分别取出一个音频帧,再把所有的音频帧叠加起来,合成一个音频帧,再送给混音接收对象。为了验证我们的想法,我们先在模块中搜索TimeUntilNextProcess和Process方法,发现这两个方法的具体实现在AudioConferenceMixerImpl类中
在AudioConferenceMixerImpl.cc 182行AudioConferenceMixerImpl::TimeUntilNextProcess方法中,我们可以知道这这个模块以10ms的周期被
调用,这和WebRTC的音频采样周期刚好符合。我们先来分析一下AudioConferenceMixerImpl::Process:下面我会以中文的方式把Process的流程写出来,大家再对照代码自己再体会一下。
void AudioConferenceMixerImpl:rocess() {
1,更新_timeScheduler,作用是确保以近似10ms的间隔去音频缓冲队列取数据来混音
2,定义了三个AudioFrameList音频帧队列,mixList,rampOutList,additionalFramesList,这三个队列分别是当前需要混音的音频队列,上次已经被混音,
这次需要被移除队列,附加的音频队列(在WebRTC中,主要用于文件播放器)
3,分别取数据填充这三个队列,
UpdateToMix(&mixList, &rampOutList, &mixedParticipantsMap,&remainingParticipantsAllowedToMix);
GetAdditionalAudio(&additionalFramesList);
4,把这三个队列混音
MixFromList(mixedAudio, mixList);
MixAnonomouslyFromList(mixedAudio, additionalFramesList);
MixAnonomouslyFromList(mixedAudio, rampOutList);
5, 调用WebRTC中的AudioProcessing模块处理混音后的音频帧,调整音量 LimitMixedAudio(mixedAudio);
6,通知混音接收方 _mixReceiver->NewMixedAudio
7,清除数据
}Process()方法结构还比较清晰,理解起来不太难。UpdateToMix方法主要作用是从众多候选者中选出声音最大的三个,从这三个候选者中取出音频,再混音。
因为同时混太多路,容易发生重叠,造成语音不清楚。下面我们来分析UpdateToMix方法,UpdateToMix方法代码比较长,第一次看有点费力。void AudioConferenceMixerImpl::UpdateToMix(
AudioFrameList* mixList,
AudioFrameList* rampOutList,
std::map<int, MixerParticipant*>* mixParticipantList,
size_t* maxAudioFrameCounter) const {
const size_t mixListStartSize = mixList->size(); //一直为0,不知道是不是bug
AudioFrameList activeList; //声音最大的用户,最多三个
ParticipantFrameStructList passiveWasNotMixedList; //虽然没有说话,但是因为当前用户少于3,也要被混音
ParticipantFrameStructList passiveWasMixedList; //上一次已经被混音了,这一次没有说话的用户
for{
1,循环从候选用户取出音频帧
2,如果当前总用户数少于3,设置标志位mustAddToPassiveList,即使这个音频帧不是活动的,也可以被混音
3,检测上一次是不是已经被混音,设置标志位wasMixed
if(音频帧是活动的){
下面代码是检测出最大的三个用户出来
}else{
if(上次被混音过){
添加到passiveWasMixedList
}else if(用户总数小于3,必需要被混音){
添加RampIn,类似图片切换淡入淡出效果
添加到passiveWasNotMixedList
}else{
直接释放不处理
}
}
}
}这里需要单独说明的是,WebRTC处理被混音用户进入和退出时加了特效,要不然就会太生硬了,具体实现在audio_frame_manipulator.cc文件中。当用户第一次进入时,会添加RampIn效果,当用户退出时,会加入RampOut效果。为了避免混音后的音量忽大忽小,调用了AudioProcessing模块的AGC功能,这样就可能保证音频的音量保持稳定。
两个音频帧的混音具体实现在
void MixFrames(AudioFrame* mixed_frame, AudioFrame* frame, bool use_limiter) {
assert(mixed_frame->num_channels_ >= frame->num_channels_);
if (use_limiter) {
// Divide by two to avoid saturation in the mixing.
// This is only meaningful if the limiter will be used.
*frame >>= 1;
}
if (mixed_frame->num_channels_ > frame->num_channels_) {
// We only support mono-to-stereo.
assert(mixed_frame->num_channels_ == 2 &&
frame->num_channels_ == 1);
AudioFrameOperations::MonoToStereo(frame);
}*mixed_frame += *frame;
}
从*mixed_frame += *frame;这一行我们可以看出AudioFrame类重定义了+=运算符,我们转到AudioFrame类去看看两个音频帧是如何混合在一起的
在
inline AudioFrame& AudioFrame::operator+=(const AudioFrame& rhs) {
...for (size_t i = 0; i < samples_per_channel_ * num_channels_; i++) {
int32_t wrap_guard =
static_cast<int32_t>(data_) + static_cast<int32_t>(rhs.data_);
data_ = ClampToInt16(wrap_guard);
}
}从上面可以看出,两个音频帧的混合非常简单,只要把对应的音频数据相加就行。
ClampToInt16这个方法是为了防止两个short类型数据相加的结果溢出。我们转到这个方法看看是如何实现的。
inline int16_t ClampToInt16(int32_t input) {
if (input < -0x00008000) {
return -0x8000;
} else if (input > 0x00007FFF) {
return 0x7FFF;
} else {
return static_cast<int16_t>(input);
}
}
这个算法也很简单,一目了然到此,WebRTC中的混音模块算是分析完了,本文是根据WebRTC56版本代码写的,其它版本可能会有不同的地方。
原文:http://www.rtc8.com/forum.php?mod=viewthread&tid=33&extra=page%3D1
---------------------
作者:老衲不出家
来源:CSDN
原文:https://blog.csdn.net/tanningzhong/article/details/77968090
版权声明:本文为博主原创文章,转载请附上博文链接! -
WebRTC中的混音算法
2018-11-28 20:15:02webrtc的混音算法在modules/audio_mixer/frame_combiner.cc文件的FrameCombiner::Combine()函数里 主干程序: void FrameCombiner::Combine(const std::vector<AudioFrame*>& mix_list, ... -
2019 WebRtc AudioMixer混音流程
2019-09-23 23:12:23本文简要说明最新版WebRtc AudioMixer混音流程。 本程序使用4个16KHz 单声道时长均大于10秒的Wav文件作为混音源,只合成前10秒的音频,输出也是16KHz单声道音频。 输入和输出的采样率都是16000,每10ms音频长度... -
WebRTC 学习之 Conference 实现混音混屏
2020-07-24 14:51:18混音 混音的意义就是将多个音频流混成一路音频,在Conference 的实现中有分为终端实现和服务器实现。 1. 终端混音实现: 终端接受到多路(一般是多个用户)的音频流之后,在终端本地将多路音频流混成一路音频送给... -
webrtc封装sdk(六)获取本地pcm语音数据和远端混音后的pcm数据
2019-01-05 16:36:31做录音时首先需要获取本地采集的pcm数据和所有远端用户合成后的pcm数据,也就是播放时投递给扬声器的pcm数据,本文讲解一下如何获取webrtc的原始音频数据。 ##webrtc版本说明 本文使用的webrtc api依赖于webrtc分支... -
AudioMixer,一个跨平台的音频混音器,支持android、ios、macos和windows。由WebRTC、FFMPEG和吉尼提供支持...
2019-09-25 06:41:08一个跨平台的音频混音器,支持android、ios、macos和windows。由WebRTC、FFMPEG和吉尼提供支持。 -
WebRTC系列--录音
2020-11-23 14:12:34文章目录重采样类 该篇文章主要是将WebRTC的远端和本地的音频流录制成mp3;同时也会涉及到WebRTC的重采样算法使用和混音的使用; 重采样类 -
Webrtc音频引擎(一步一步读代码)
2020-05-20 07:54:34WebRTC音频引擎的实现代码主要分布在如下几个源码目录中: ...//接收端混音 webrtc/module/audio_conference_mixer //音频输入输出设备 webrtc/module/audioDevide //音频预处理(消回音、自动增益、降噪等) webrtc/modu -
webrtc_module_audio_conference_mixer
2019-10-31 16:39:38原因:由于需要进行基于webrtc的混音模块封装,故在此进行简单调用。 概述:通过将webrtc_module_audio_conference_mixer模块的摘出,编写测试代码实现conference_mixer模块的调用,内部混音流程与之前博客分析一致... -
WebRTC系列之音频的那些事
2020-06-30 19:29:06WebRTC由语音引擎,视频引擎和网络传输三大模块组成,其中语音引擎是WebRTC中最具价值的技术之一,实现了音频数据的采集、前处理、编码、发送、接受、解码、混音、后处理、播放等一系列处理流程。 音频引擎主要... -
Webrtc Intro - kurento
2016-01-14 17:10:27折腾了一个多星期终于将kurento的环境搭建好(开发阶段的...搞视频会议就会涉及一对多、多对多、广播、转码、混音、合屏、录制,这就需要用到流媒体服务器,而kurento就具有这些功能。 他主要用来作为webrtc的流媒体 -
CentOS下编译webrtc2sip实战
2019-02-13 09:12:14在研究WebRTC服务端画面合成和混音处理,需要实现浏览器端与服务器端的点对点,网上找了好些参考的项目,webrtc2sip项目就是其中之一,该项目基于doubango的框架,需要自行编译搭建环境,根据webrtc2sip中的《技术... -
webrtc mixer源码分析
2021-01-20 10:39:20AudioMixer的入口函数为AudioMixerImpl::Mix,功能分为三步: 计算输出采样率:CalculateOutputFrequency ...混音:FrameCombiner::Combine 下面分别对这三步进行分析 CalculateOutputFrequency, ... -
webrtc arm liunx 海思等嵌入式设备
2021-01-20 22:26:58可以通过设备端摄像头的rtsp/rtmp等流转成webrtc协议在手机app和手机浏览器和各种电脑流行浏览器网页(Chrome,edge,Firefox,safari)和pc电脑端播放,实时性在延时300毫秒左右,实现了回音消除,多路实时语言混音...