c/c++语言开发共享2019 WebRtc AudioMixer混音流程

本文简要说明最新版WebRtc AudioMixer混音流程。 本程序使用4个16KHz 单声道时长均大于10秒的Wav文件作为混音源,只合成前10秒的音频,输出也是16KHz单声道音频。 输入和输出的采样率都是16000,每10ms音频长度采样点数为160,每个采样点为16bit,两字节大小。 使 …

c/c++开发分享2019 WebRtc AudioMixer混音流程简要说明最新版webrtc audiomixer混音流程。

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

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

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

代码如下:

  1 #include "stdafx.h"    2 #include <string>    3 #include <iostream>    4 #include <memory>    5 #include <thread>    6 #include <chrono>    7 #include "webrtcmodulesaudio_mixeraudio_mixer_impl.h"    8 #include "webrtcapiaudioaudio_frame.h"    9 #include "webrtcmodulesaudio_mixeroutput_rate_calculator.h"   10    11 using namespace std::literals::chrono_literals;   12    13 #define wav_header_size 44   14 #define sample_rate 16000   15    16 int16_t s_buf[160] = { 0 };   17    18 class audiosrc : public webrtc::audiomixer::source   19 {   20 public:   21     audiosrc(int ssrc, int sample, const std::string& file)   22         : mssrc(ssrc)   23         , msample(sample)   24         , mfile(nullptr)   25     {   26         fopen_s(&mfile, file.c_str(), "rb");   27            28         if (mfile)   29         {   30             fseek(mfile, 44, seek_set);   31         }   32     }   33    34     virtual ~audiosrc()   35     {   36         if (mfile)   37         {   38             fclose(mfile);   39             mfile = nullptr;   40         }   41     }   42    43     virtual audioframeinfo getaudioframewithinfo(int sample_rate_hz,   44         webrtc::audioframe* audio_frame)   45     {   46         if (mfile)   47         {   48             fread(s_buf, 160 * 2, 1, mfile);//16khz, 10ms buf   49         }   50            51         std::thread::id tid = std::this_thread::get_id();   52         std::cout << "thread id ";   53         tid._to_text(std::cout);   54    55         //copy s_buf to audio_frame inner buf   56         audio_frame->updateframe(0, s_buf, 160, sample_rate, webrtc::audioframe::speechtype::knormalspeech, webrtc::audioframe::vadactivity::kvadunknown, 1);   57         printf(",ssrc %d get audio frame, muted: %d, n %d, s %dn", mssrc, int(audio_frame->muted()), audio_frame->num_channels_, audio_frame->sample_rate_hz_);   58            59         return audioframeinfo::knormal;   60     }   61    62     // a way for a mixer implementation to distinguish participants.   63     virtual int ssrc() const   64     {   65         return mssrc;   66     }   67    68     // a way for this source to say that getaudioframewithinfo called   69     // with this sample rate or higher will not cause quality loss.   70     virtual int preferredsamplerate() const   71     {   72         return msample;   73     }   74    75 private:   76     int mssrc;   77     int msample;   78     file* mfile;   79 };   80    81    82 class audiooutput : public webrtc::outputratecalculator   83 {   84     virtual int calculateoutputrate(   85         const std::vector<int>& preferred_sample_rates)   86     {   87         return sample_rate;   88     }   89    90 };   91    92 int mixtext()   93 {   94     auto mixptr = webrtc::audiomixerimpl::create(std::make_unique<audiooutput>(), true);   95     audiosrc src1(1, sample_rate, "e:\media\audio\16k_1.wav");   96     audiosrc src2(2, sample_rate, "e:\media\audio\16k_2.wav");   97     audiosrc src3(3, sample_rate, "e:\media\audio\16k_3.wav");   98     audiosrc src4(4, sample_rate, "e:\media\audio\16k_4.wav");   99   100     mixptr->addsource(&src1);  101     mixptr->addsource(&src2);  102     mixptr->addsource(&src3);  103     mixptr->addsource(&src4);  104   105     std::thread::id tid = std::this_thread::get_id();  106     std::cout << "main thread id: ";  107     tid._to_text(std::cout);  108     std::cout << std::endl;  109   110     webrtc::audioframe frame;  111   112     file* fout = nullptr;  113     fopen_s(&fout, "f:/download/outmix.pcm", "wb");  114       115     for (int i = 0; i < 100*10; ++i) // only mix first 10 seconds audio  116     {  117         mixptr->mix(1, &frame);  118         if (fout)  119         {  120             fwrite(frame.data(), 160 * 2, 1, fout);  121         }  122         std::this_thread::sleep_for(10ms);  123     }  124       125     fclose(fout);  126     fout = nullptr;  127   128     mixptr->removesource(&src1);  129     mixptr->removesource(&src2);  130     mixptr->removesource(&src3);  131     mixptr->removesource(&src4);  132   133     tid = std::this_thread::get_id();  134     std::cout << "exit main thread id: ";  135     tid._to_text(std::cout);  136     std::cout << std::endl;  137   138     return 0;  139 }  140   141 int main(int argc, char* argv[])  142 {  143     mixtext();  144   145     return 0;  146 }

代码大体介绍:

 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(1, sample_rate, "e:\media\audio\16k_1.wav");  audiosrc src2(2, sample_rate, "e:\media\audio\16k_2.wav");  audiosrc src3(3, sample_rate, "e:\media\audio\16k_3.wav");  audiosrc src4(4, 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 = 0; i < 100*10; ++i) // only mix first 10 seconds audio      {          mixptr->mix(1, &frame);          if (fout)          {              fwrite(frame.data(), 160 * 2, 1, fout);          }          std::this_thread::sleep_for(10ms);      }

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

mixptr->mix(1, &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播放。

 

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/602842.html

(0)
上一篇 2021年5月11日
下一篇 2021年5月11日

精彩推荐