我正在尝试使用Speex编解码器库执行回声消除(AEC)。根据Speex文档,我需要执行两个调用:

 speex_echo_playback(echo_state, echo_frame);

每次播放音频帧时,以及
 speex_echo_capture(echo_state, input_frame, output_frame);

对于捕获的每一帧。

由于我使用的是DirectSound,因此我想我可以在对speex_echo_playback的调用中将主要的DirectSound缓冲区用作echo_frame,例如,
  DWORD offset = 0;
  DWORD length = 0;
  LPVOID block1, block2;
  DWORD length1, length2;
  DWORD flags = DSBLOCK_ENTIREBUFFER;

  HRESULT hr = primary_buffer->Lock(
        offset
      , length
      , &block1
      , &length1
      , &block2
      , &length2
      , flags
      );

  // Would like to convert the buffer into a form that
  // speex_echo_capture() can use.
  // Why does length1 == length2 == 0 always?

  hr = primary_buffer->Unlock( block1, length1, block2, length2 );

该文档确实说这些是只写指针,但是我自己还不能使用缓冲区数据吗?

这基本上就是我创建缓冲区的方式:
  CComPtr< IDirectSoundBuffer > primary_buffer;
  DSBUFFERDESC primarydesc = { sizeof( DSBUFFERDESC ),
      DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D | DSBCAPS_LOCHARDWARE,
      0, 0, NULL, DS3DALG_HRTF_LIGHT };
  HRESULT hr = directsound_->CreateSoundBuffer(
      &primarydesc, &primary_buffer, NULL );

使用DirectSound缓冲区本身的替代方法似乎是使用speex_decode()的输出并进行我自己的软件混合。

有关使Speex和DirectSound协同工作的任何指示或建议?谢谢你的帮助。

最佳答案

我曾经做过一次。但是我的方法如下:

我从未直接使用Primary缓冲区。相反,我只使用一个辅助缓冲区。我有两个线程-回放线程和捕获线程。另外,我使用了另一个speex函数speex_echo_cancellation

因此,在回放线程中,我已将当前回放帧保存在全局缓冲区中,并在名为speex_echo_cancellation函数的捕获线程中保存了正确的捕获帧和先前存储的回放帧。

DMO不适用于我,因为我还必须支持Windows XP。

您还可以浏览-speex mailing lists archive甚至更好的subscribe here以获得更多有趣的信息。

祝你好运,

安东尼

10-06 13:12