本文简要说明最新版WebRtc AudioMixer混音流程。

本程序使用4个16KHz 单声道时长均大于10秒的Wav文件作为混音源,只合成前10秒的音频,输出也是16KHz单声道音频。

输入和输出的采样率都是16000,每10ms音频长度采样点数为160,每个采样点为16bit,两字节大小。

使用的WebRTC代码日期为2019-05-08。

代码如下:

 #include "stdafx.h"
#include <string>
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include "webrtc\modules\audio_mixer\audio_mixer_impl.h"
#include "webrtc\api\audio\audio_frame.h"
#include "webrtc\modules\audio_mixer\output_rate_calculator.h" using namespace std::literals::chrono_literals; #define WAV_HEADER_SIZE 44
#define SAMPLE_RATE 16000 int16_t s_buf[] = { }; class AudioSrc : public webrtc::AudioMixer::Source
{
public:
AudioSrc(int ssrc, int sample, const std::string& file)
: mSsrc(ssrc)
, mSample(sample)
, mFile(nullptr)
{
fopen_s(&mFile, file.c_str(), "rb"); if (mFile)
{
fseek(mFile, , SEEK_SET);
}
} virtual ~AudioSrc()
{
if (mFile)
{
fclose(mFile);
mFile = nullptr;
}
} virtual AudioFrameInfo GetAudioFrameWithInfo(int sample_rate_hz,
webrtc::AudioFrame* audio_frame)
{
if (mFile)
{
fread(s_buf, * , , mFile);//16KHz, 10ms buf
} std::thread::id tid = std::this_thread::get_id();
std::cout << "thread id ";
tid._To_text(std::cout); //copy s_buf to audio_frame inner buf
audio_frame->UpdateFrame(, s_buf, , SAMPLE_RATE, webrtc::AudioFrame::SpeechType::kNormalSpeech, webrtc::AudioFrame::VADActivity::kVadUnknown, );
printf(",ssrc %d get audio frame, muted: %d, n %d, s %d\n", mSsrc, int(audio_frame->muted()), audio_frame->num_channels_, audio_frame->sample_rate_hz_); return AudioFrameInfo::kNormal;
} // A way for a mixer implementation to distinguish participants.
virtual int Ssrc() const
{
return mSsrc;
} // A way for this source to say that GetAudioFrameWithInfo called
// with this sample rate or higher will not cause quality loss.
virtual int PreferredSampleRate() const
{
return mSample;
} private:
int mSsrc;
int mSample;
FILE* mFile;
}; class AudioOutput : public webrtc::OutputRateCalculator
{
virtual int CalculateOutputRate(
const std::vector<int>& preferred_sample_rates)
{
return SAMPLE_RATE;
} }; int MixText()
{
auto mixptr = webrtc::AudioMixerImpl::Create(std::make_unique<AudioOutput>(), true);
AudioSrc src1(, SAMPLE_RATE, "e:\\Media\\Audio\\16k_1.wav");
AudioSrc src2(, SAMPLE_RATE, "e:\\Media\\Audio\\16k_2.wav");
AudioSrc src3(, SAMPLE_RATE, "e:\\Media\\Audio\\16k_3.wav");
AudioSrc src4(, SAMPLE_RATE, "e:\\Media\\Audio\\16k_4.wav"); mixptr->AddSource(&src1);
mixptr->AddSource(&src2);
mixptr->AddSource(&src3);
mixptr->AddSource(&src4); std::thread::id tid = std::this_thread::get_id();
std::cout << "main thread id: ";
tid._To_text(std::cout);
std::cout << std::endl; webrtc::AudioFrame frame; FILE* fOut = nullptr;
fopen_s(&fOut, "f:/download/outmix.pcm", "wb"); for (int i = ; i < *; ++i) // only mix first 10 seconds audio
{
mixptr->Mix(, &frame);
if (fOut)
{
fwrite(frame.data(), * , , fOut);
}
std::this_thread::sleep_for(10ms);
} fclose(fOut);
fOut = nullptr; mixptr->RemoveSource(&src1);
mixptr->RemoveSource(&src2);
mixptr->RemoveSource(&src3);
mixptr->RemoveSource(&src4); tid = std::this_thread::get_id();
std::cout << "exit main thread id: ";
tid._To_text(std::cout);
std::cout << std::endl; return ;
} int main(int argc, char* argv[])
{
MixText(); return ;
}

代码大体介绍:

class AudioSrc : public webrtc::AudioMixer::Source 定义了混音音频源的类,

AudioSrc必须实现基类的三个virtual函数,

virtual int Ssrc() const;  返回混音源的ID, AudioMixer调用此函数用于区分每个音频源,每个音频源的Ssrc必须返回不同的值。

virtual int PreferredSampleRate() const; 返回混音源的音频采样率,这里都是16000,AudioMixer调用此函数得到每个音频源的音频采样率。

virtual AudioFrameInfo GetAudioFrameWithInfo(int sample_rate_hz, webrtc::AudioFrame* audio_frame) 获取混音源的10ms长度音频,混音时AudioMixer依次对混音源调用此函数,

AudioSrc先从wav文件读取10ms音频到s_buf中,用AudioFrame的UpdateFrame函数把刚获取的s_buf中内容更新到AudioFrame中,AudioMixer内部完成混音。

class AudioOutput : public webrtc::OutputRateCalculator  是用于计算混音输出音频采样率的类,必须实现虚函数CalculateOutputRate,

参数const std::vector<int>& preferred_sample_rates中元素为每个混音源的音频采样率,返回值为输出音频采样率,这里输出和输入的采样率一样,返回16000。

函数MixText是调用的代码

auto mixptr = webrtc::AudioMixerImpl::Create(std::make_unique<AudioOutput>(), true);

创建了一个AudioMixer智能指针对象mixptr ,

AudioSrc src1(, SAMPLE_RATE, "e:\\Media\\Audio\\16k_1.wav");
AudioSrc src2(, SAMPLE_RATE, "e:\\Media\\Audio\\16k_2.wav");
AudioSrc src3(, SAMPLE_RATE, "e:\\Media\\Audio\\16k_3.wav");
AudioSrc src4(, SAMPLE_RATE, "e:\\Media\\Audio\\16k_4.wav");

创建了4个混音源。

mixptr->AddSource(&src1);
mixptr->AddSource(&src2);
mixptr->AddSource(&src3);
mixptr->AddSource(&src4);

把4个混音源添加到AudioMixer中,

webrtc::AudioFrame frame;

创建一个AudioFrame 对象,用于接收混音输出。

FILE* fOut = nullptr;
fopen_s(&fOut, "f:/download/outmix.pcm", "wb");

打开一个文件,用于写入混音输出。

    for (int i = ; i < *; ++i) // only mix first 10 seconds audio
{
mixptr->Mix(, &frame);
if (fOut)
{
fwrite(frame.data(), * , , fOut);
}
std::this_thread::sleep_for(10ms);
}

此循环调用1000次,每次混音10毫秒长度音频,总共混音10秒钟长度的音频,

mixptr->Mix(, &frame);

Mix是实际执行混音的函数,
它内部再依次调用AudioSrc::GetAudioFrameWithInfo再完成混音,把混音输出到frame中。

然后用fwrite再把frame.data()中的混音输出写入到输出文件。

std::this_thread::sleep_for(10ms);

sleep等待10毫秒。

混音完成再调用

    mixptr->RemoveSource(&src1);
mixptr->RemoveSource(&src2);
mixptr->RemoveSource(&src3);
mixptr->RemoveSource(&src4);

移除混音源。

以上就是混音流程。

注意:由于混音输出写的是PCM文件,没有文件头,一般播放器不能播放,必须用 CoolEdit 或 Audacity 打开PCM播放。

2019 WebRtc AudioMixer混音流程的更多相关文章

  1. [Android] 混音线程MixerThread

    MixerThread是Android音频输出的核心部分,所有Android的音频都需要经过MixerThread进行混音后再输出到音频设备. MixerThread的继承关系如下: MixerThr ...

  2. WebRTC 学习之 Conference 实现混音混屏

    混音 混音的意义就是将多个音频流混成一路音频,在Conference 的实现中有分为终端实现和服务器实现. 1. 终端混音实现: 终端接受到多路(一般是多个用户)的音频流之后,在终端本地将多路音频流混 ...

  3. (二) ffmpeg filter学习--混音实现

    Audio 混音实现 从FFMPEG原生代码doc/examples/filtering_audio.c修改而来. ffmpeg版本信息 ffmpeg version N-82997-g557c0df ...

  4. XAudio2学习之混音

    XAudio2不仅能够进行採样率转换.还能够进行混音.所谓混音就是将多路音频混合成一路进行输出.混音主要是IXAudio2SubmixVoice进行此项功能. 数据由IXAudio2SourceVoi ...

  5. ffmpeg混音(将多个声音合成一个)命令

    ffmpeg命令中可以使用filter amix实现这个功能. 官方文档 http://ffmpeg.org/ffmpeg-filters.html 6.8 amix Mixes multiple a ...

  6. pcm混音的一种方式

    转载 混音: Mix的意思是混音,无论在自然界,还是在音频处理领域这都是非常普遍的现象.自然界里你能同时听到鸟鸣和水声,这是因为鸟鸣和水声的波形在空气中形成了叠加,耳朵听到后能区分鸟鸣和水声这两种波形 ...

  7. C#混音同时录制采集声卡和麦克风话筒

    在项目中,我们可能需要同时录制声卡的声音和麦克风的声音,比如直播间,在线教学.那么如何实现呢?当然是采用SharpCapture!下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第一步: ...

  8. FL Studio带你走进混音的世界

    混音,是把多种音源整合到一个立体音轨或单音音轨中,通俗讲就是对多种声音进行调整后叠加在一起,这样可以让音乐听起来非常有层次感,尤其是在电音制作过程中,混音的质量更是起到了决定性的作用.音乐制作软件FL ...

  9. FL Studio音频混音教程

    FL Studio是一款音乐制作.编曲.混音软件,其内置众多电子合成音色,还支持第三方VST等格式插件.软件操作界面简洁易上手,即使你是零音乐基础小白,通过它也能轻松实现自己音乐梦想,很多人给他起了个 ...

随机推荐

  1. 两个ESP8266一个作为服务器一个作为客户端实现互相通讯

    两个ESP8266一个作为服务器一个作为客户端实现互相通讯

  2. PropertyValuesHolder学习

    package com.loaderman.customviewdemo; import android.animation.ObjectAnimator; import android.animat ...

  3. 005-多线程-集合-Map-ConcurrentSkipListMap

    一.概述 ConcurrentSkipListMap是线程安全的有序的哈希表,适用于高并发的场景. ConcurrentSkipListMap和TreeMap,它们虽然都是有序的哈希表.但是,第一,它 ...

  4. TensorFlow Object Detection API —— 测试自己的模型

    (flappbird) luo@luo-All-Series:~/MyFile/TensorflowProject/Mask_RCNN/mask_rcnn_20190518/Mask_RCNN/mod ...

  5. 阶段5 3.微服务项目【学成在线】_day17 用户认证 Zuul_01-用户认证-用户认证流程分析

    1 用户认证 1.1 用户认证流程分析 用户认证流程如下: 访问下面的资源需要携带身份令牌和jwt令牌,客户端可以通过身份认证的令牌从服务端拿到长令牌, 一会要实现认证服务请求用户中心从数据库内来查询 ...

  6. 阶段5 3.微服务项目【学成在线】_day07 课程管理实战_02-我的课程-前端页面与Api说明

    我的课程列表使用element 的card组件,如下: 前端页面代码 点击新增到了一个新增课程的页面 新增课程的界面 下面的card是循环遍历的代码 写死的card的静态数据 请求服务端的接口拿到数据 ...

  7. $().attr() 和 $().css的区别

    使用jquery的.attr( )方法去给div隐藏,这样写的 $("#div_id").attr("display","none"),发现 ...

  8. ubuntu18.04开机提示welcome to emergency mode! after logging in type...的解决办法

    开机就是报错,进不了系统. 原因是我的ubuntu电脑绑定了之前的移动硬盘,而我开机的时候并没有插着移动硬盘. 所以解决办法是,在此命令行下,以root用户的身份(我这里默认是root用户),vim ...

  9. 网页布局(html+css基础)

    一.如何用CSS进行网页布局 二.网页布局基础 三.网页简单布局之结构和表现原则 四.CSS Sprite雪碧图应用 什么叫布局? 网页的特点: 网页自适应宽度: 网页长度无限延长: (分栏也叫分列, ...

  10. 携程Apollo统一配置中心的搭建和使用

    原文链接:https://blog.csdn.net/luhong327/article/details/81453001 一.Apollo配置中心介绍 1.What is Apollo 1.1 Ap ...