zoukankan      html  css  js  c++  java
  • 实践windows下 speex 1.2rc1 中的回声消除功能(转)

    看到网上很多希望使用speex aec的, 似乎找不到win32下的例子, 我这里尝试做了一个, 效果还行, 使用

    上面是三路实时音频录下后, 在audacity中显示, 第一路为本地mic采集, 第二路为本地回放, 第三路为经过speex_echo_cancellation() 处理后的, 这个测试中, 为间断的读"1, 2, 3...", 图中选中的是 "2". capture到playback之间,大约差了1百多毫秒.

    下面开始叙述实现过程, 并附上源码.

    其实aec中最困难的问题是如何同步capture和playback, 一开始我也尝试用 speex_echo_playback()/speex_echo_capture() 但最后还是放弃了, 因为真正的问题在于win32下的实时性太差了, 两个及时最高优先级的工作线程, 也很难对齐.

    这个例子中使用dsound进行capture/playback(开始用waveIn/waveOut, 简直无法忍受, 感兴趣的, 关闭代码中的 USING_DSOUND试试), capture和playback使用 event, 通知独立的工作线程, 进行aec.

    speex aec中, 希望20ms一个frames, 但是win32下似乎设置20ms一个通知点时, 就乱套了, 至少在我的x61(win2003)是不行的, 所以设置40ms.

    通知点:

        static HANDLE _evt_notify[2] = { CreateEvent(0, 0, 0, 0), CreateEvent(0, 0, 0, 0), };

        创建两个event对象, 分别对应 capture和playback中使用的 notify point

    fifo缓冲 :

        实现为环形缓冲, 分别用于 _cbuf_recv: 接收网络数据, _cbuf_input:  保存capture数据, _cbuf_output: 保存 playback数据

    工作线程: 实施aec

        while true {

             WaitForMultipleObjects(_evt_notify);

             if (capture notify) {

                  save data info _cbuf_input;     // _cbuf_input 包含回声需要消除的声音

             }

             else {

                  get data from _cbuf_recv;  // _cbuf_recv 保存来自网络的数据

                  save data info _cbuf_output // _cbuf_output 作为参考

                  playback data

             }

             while (_cbuf_input.data > FRAMESIZE, _cbuf_output.data > FRAMESIZE) {

                  speex_echo_cancellation();

                  send_pcm();

             }

        }

    PCM格式

            WAVEFORMATEX:

                    .wFormatTag = WAVE_FORMAT_PCM;

                    .nChannels = 1;

                    .nSamplesPerSec = 8000;

                    .wBitsPerSample = 16;

                    .nBlockAlign = 2;

                    .nAvgBytesPerSec = 16000;

    打开playback设备

            DirectSoundCreate8();

            SetCooperativeLevel( DSSCL_EXCLUSIVE)

            CreateSoundBuffer()

            QueryInterface (IID_IDirectSoundNotify8 ..)

                 SetNotificationPositions( _evt_notify[1]);

            Play(0, 0, DSBPLAY_LOOPING);


    打开capature设备

            DirectSoundCaptureCreate8();

            CreateCaptureBuffer();

            QueryInterface (IID_IDirectSoundNotify8 ..)

                 SetNotificationPositions( _evt_notify[0]);

            Start(DSCBBSTART_LOOPING);

    其实xp开始有个 DirectSoundFullDuplexCreate8() 的函数, 可以一次调用同时创建 capture buffer和playback buffer, 源码中有.

    这里下载 http://download.csdn.net/source/3290182

  • 相关阅读:
    使用八爪鱼采集所需信息
    一些小疑问&解答
    第一页的简单爬取
    【不解决了】对Spark源码进行编译
    python学习中的序列函数
    关于python中的小知识总结
    python学习13之数据泄密
    python学习12之梯度推进
    python学习11之交叉验证
    python学习10之管道清理建模
  • 原文地址:https://www.cnblogs.com/myitm/p/2112843.html
Copyright © 2011-2022 走看看