WEBRTC 录音与会议录音【转】

    xiaoxiao2025-08-16  5

    来自:http://blog.csdn.net/darkinger/article/details/13627479

    今年4月时,我们一个利用WEBRTC开发的单人及多人语音功能需要新增一个录音功能,由此又开始一段艰苦的WEBRTC研究之旅。

    最开始时,记得WEBRTC中好像提供了录音功能,兴冲冲一试,成了,可以录,还提供了录制文件格式的转换功能(ILBC2PCM等),太好了,立即应用于产品中。 不过好景不长,一经测试,居然没有自己的声音,只有对方或多人语音会议中其它人的声音,原来WEBRTC只能录制麦克风输入或音箱输出的声音,不能同时录制二者的声音。怎么办呢?经过多方查找,网络询问,没有任何人有办法。最后无法,上WEBRTC在google的讨论组,直接问开发人员吧。开发小组的回答如下: =================================================== webrtc@googlecode.com 通过“codesite.bounces.google.com”发送至 我 Updates:         Status: WontFix         Owner: braveyao@webrtc.org Comment #1 on issue 1567 by braveyao@webrtc.org: How to record mixed(speaker+mic) signal to file http://code.google.com/p/webrtc/issues/detail?id=1567 True. We abandoned that functionality in WebRTC. Also File is not our focusing any more. Sorry about that. =================================================== 居然是不支持该功能,以后也不会支持。 这下傻眼了吧。 OK,WEBRTC不支持该功能,我该怎么办呢,有源码在手,我还怕没办法?!!

    经过多日研究:

    a. 发现WEBRTC的语音引擎中关于语音录制功能主要在VoEFile及其实现类(VoEFileImpl)中实现,

    b. 音箱输出的录制主要是通过 OutputMixer* _outputMixerPtr; 这个声明在SharedData类中的成员变量来实现,

    c. 麦克风声音的录制主要是通过 TransmitMixer* _transmitMixerPtr; 这个成员变量来录制。

    d. 这两个变量其实就是一个混淆器,通过监控混淆器中的每一帻,实现将语音数据记录至文件流中。

    研究到这,就有一个想法出现,如果我将这两个混淆器输出的每一帻再合在一起混淆一次,并输出至一个文件流中,不就实现我所需要的录音功能了吗? 1、首先在VoEFile中增加一对public方法,用来开始及结束录音     //for Record speaker+mic     // Starts recording the mixed playout audio and mic.     virtual int StartRecordingPlayoutAndMic(const char* fileNameUTF8,                                       CodecInst* compression = NULL,                                       int maxSizeBytes = -1) = 0;     // Stops recording the mixed playout audio and mic.     virtual int StopRecordingPlayoutAndMic() = 0; 2、在SharedData类中增加一个成员变量     OutputMixer* _outputAllMixerPtr;    //for Record speaker+mic 3、在SharedData的构造函数及析构函数中完成该变量创建及释放 SharedData::SharedData() : ... {     ...     //for Record speaker+mic     if (OutputMixer::Create(_outputAllMixerPtr, _gInstanceCounter) == 0)     {         _outputAllMixerPtr->SetEngineInformation(_engineStatistics);     }     ... } SharedData::~SharedData() {     ...     OutputMixer::Destroy(_outputAllMixerPtr);//for Record speaker+mic     ... } 4、在实现类VoEFileImpl中实现StartRecordingPlayoutAndMic 及 StopRecordingPlayoutAndMic //for Record speaker+mic int VoEFileImpl::StartRecordingPlayoutAndMic(     const char* fileNameUTF8, CodecInst* compression,     int maxSizeBytes) {     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),                  "StartRecordingPlayoutAndMic(fileNameUTF8=%s, "                  "compression, maxSizeBytes=%d)",                  fileNameUTF8, maxSizeBytes);     assert(1024 == FileWrapper::kMaxFileNameSize);     if (!_engineStatistics.Initialized())     {         _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);         return -1;     }     _outputAllMixerPtr->StartRecordingPlayout(fileNameUTF8, compression);     return 0; } int VoEFileImpl::StopRecordingPlayoutAndMic() {     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),                  "StopRecordingPlayoutAndMic");     if (!_engineStatistics.Initialized())     {         _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);         return -1;     }     return _outputAllMixerPtr->StopRecordingPlayout(); } 5、在VoEBaseImpl中增加两个私有成员 //for Record speaker+mic private:     AudioFrameMixerPart _afmTransmitMixer;     AudioFrameMixerPart _afmOutputMixer; 6、增加一个MixerParticipant的实现,用于拦截原有两个混淆器的输出,并合并至我们最终的录音混淆器中 //for Record speaker+mic //record mic or playout signal from OutputMixer output class AudioFrameMixerPart:public MixerParticipant  { public:     AudioFrameMixerPart(){};     void SetAudioFrame(AudioFrame &audioFrame)     {         _audioFrame = audioFrame;     }     WebRtc_UWord16 GetPayloadDataLengthInSamples()     {         return _audioFrame._payloadDataLengthInSamples;     } public:     // From MixerParticipant     WebRtc_Word32 GetAudioFrame(const WebRtc_Word32 id,                                 AudioFrame& audioFrame)     {         if (_audioFrame._payloadDataLengthInSamples <= 0) return -1;         audioFrame = _audioFrame;         return 0;     };     WebRtc_Word32 NeededFrequency(const WebRtc_Word32 id)     {         return _audioFrame._frequencyInHz;     }; private:     AudioFrame _audioFrame; }; 7、在VoEBaseImpl::Init中对_outputAllMixerPtr进行初始化         //for Record speaker+mic         _outputAllMixerPtr->SetAudioProcessingModule(_audioProcessingModulePtr);         _outputAllMixerPtr->SetMixabilityStatus(_afmTransmitMixer, true);         _outputAllMixerPtr->SetMixabilityStatus(_afmOutputMixer, true); 8、修改VoEBaseImpl::RecordedDataIsAvailable,增加麦克风语音数据的拦截功能     //for Record speaker+mic     _afmTransmitMixer.SetAudioFrame(*(_transmitMixerPtr->GetAudioFrame())); 9、修改VoEBaseImpl::NeedMorePlayData,增加播放语音数据的拦截功能     //for Record speaker+mic     _afmOutputMixer.SetAudioFrame(*_outputMixerPtr->GetAudioFrame());          ...     //for Record speaker+mic         if (_afmOutputMixer.GetPayloadDataLengthInSamples() == _afmTransmitMixer.GetPayloadDataLengthInSamples())     {         AudioFrame audioFrameX;         _outputAllMixerPtr->MixActiveChannels();         _outputAllMixerPtr->DoOperationsOnCombinedSignal();         _outputAllMixerPtr->GetMixedAudio(samplesPerSec, nChannels, audioFrameX);     } 10、因为拦截混淆语音帻时,使用了两个混淆器的内部数据,所以对TransmitMixer及OutputMixer作出修改,增加一个public方法 public:  //for Record speaker+mic     AudioFrame* GetAudioFrame(){return &_audioFrame;}     至此,终于完成WEBRTC的录音功能扩展! 在本文的实现方法中,对语音多进行了一次混淆,不知是否有性能影响,不过,在实现应用过程中(PC平台),未发现语音质量有因录音而下降。
    转载请注明原文地址: https://ju.6miu.com/read-1301794.html
    最新回复(0)