来自: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平台),未发现语音质量有因录音而下降。

WEBRTC 录音与会议录音【转】相关推荐

  1. WEBRTC 录音与会议录音

    WEBRTC 录音与会议录音 2014年08月09日 ⁄ 综合⁄ 共 5012字 ⁄ 字号 小 中 大 ⁄ 评论关闭 今年4月时,我们一个利用WEBRTC开发的单人及多人语音功能需要新增一个录音功能, ...

  2. 录音文件下载_录音转文字别烦恼,收下这份锦囊,几种方法任你选!

    工作生活中经常会用到手机录音,比如:电话录音.会议录音.采访录音.课程录音等等.录音结束后就是需要将录音内容整理成文本文档.不少人会对这种情况感到头疼,没有良好的工具,就只会默默的边听边写. 今天木酱 ...

  3. 如何恢复录音删除的录音文件_如何管理手机上的录音文件

    经常使用手机录音的朋友,都会遇到一个棘手的问题,手机里的录音文件多且杂乱,自己从众多录音里找到需要的那个都是件困难的事情,众里寻它千百度,暮然回首,仍深藏原处- 如何解决这个问题呢?下面给大家支几招, ...

  4. 智能会议系统(32)---WebRTC学习之三:录音和播放

    WebRTC学习之三:录音和播放 VoiceEngine中与录音和播放相关的头文件有五个,如下表所示: 头文件 包含的类 说明 voe_base.h VoiceEngineObserver Voice ...

  5. 会议录音转文字(PC版)

    如何将会议录音快速转换成文字 录音转文字的方法有很多种,下列分享其中一种: 所需软件: 1.剪映(pc) 2.办公软件wps(office)3.会议录音文件 剪映PC下载地址:https://lv.u ...

  6. 如何将会议录音转文字?你知道如何将会议录音转文字吗?

    会议录音转文字的需求在现代工作和生活中变得越来越重要.随着会议的频繁举行,我们常常需要记录会议内容以便后续查阅和分析.而传统的手动记录方式效率低下且容易出错.幸运的是,现在有许多会议录音转文字的应用程 ...

  7. 想知道会议录音转文字怎么转吗?这篇文章告诉你

    在现代社会中,会议是人们交流和决策的重要场所.然而,会议的过程往往需要记录和整理,传统的方式是由专门的记录员进行实时记录,然而,这种方式却效率低下.随着科技的不断进步,会议录音转文字技术的出现为我们带 ...

  8. 有什么会议录音转文字软件?用这3个录音转文字软件

    不知道大家有没有这样的烦恼,开会的时候东西太多讲得太快了,经常记完上一个漏掉下一个,不能记录全面,还得在会议结束后补上. 有没有什么办法嫩让我们在会议上就能直接记录完整又不用赶时间呢?我们可以用软件记 ...

  9. 会议录音转文字的软件有哪些?这款软件试试看

    在工作和学习中,我们经常参加各种会议,而会议记录是非常重要的一环.为了更好地整理和回顾会议内容,会议录音转文字技术应运而生.这项技术通过语音识别和自然语言处理技术,将会议录音转换为可编辑和搜索的文字文 ...

最新文章

  1. 相似图片检测:感知哈希算法之dHash的Python实现
  2. 实验一基于 的词法分析实验_[源码和文档分享]基于JAVA实现的基于DFA的词法分析程序...
  3. Java、Scala和Go语言多线程并发对比测试
  4. 不显示调用super_让不懂编程的人爱上iPhone开发(2017秋iOS11+Swift4+Xcode9版)-第11篇
  5. 建筑系学生怎么系统地学 Photoshop、CAD 之类软件?
  6. 网易云镜像仓库选择镜像
  7. 易语言解析html实例,易语言解析JSON教程
  8. Nantian PR-2/K10打印机的安装及配置方法
  9. 160603、使用pd4ml.jar和ss_css2.jar转pdf的工具类
  10. 一文带你由浅入深Netty异步非阻塞世界(持续更新~~~)
  11. sam卡和sim卡区别_SAM卡
  12. 预祝大家平安夜圣诞节快乐
  13. SpringBoot redis GEO 实战应用
  14. python 删除pdf页面_使用python从新生成的pdf文件中删除空白页
  15. java计算机毕业设计快滴预约平台源码+mysql数据库+系统+lw文档+部署
  16. 高中数学必修二立体几何中的向量方法(经典案例讲解)
  17. Android AudioFocus机制小结
  18. 高斯曲线拟合推导过程
  19. 洛口山风电场微机保护设计
  20. 牛客IOI周赛22-普及组

热门文章

  1. GPS伪距导航定位原理
  2. 将汉字转换为Unicode编码vb.net源码
  3. 陌生人社交软件如何破冰?
  4. iPayLinks与Ueeshop达成战略合作 助力中国品牌拓业全球
  5. Java中的transient关键字
  6. c++计算正态累积分布函数
  7. 中产阶级毁灭者,详解外汇投资骗局
  8. 浅谈“硝烟中的Scrum and XP”
  9. MyBatis(一)——初识MyBatis
  10. 计算机可以做推理逻辑吗?