windows WASAPI回送捕获的调试模式下持续音频中断

brjng4g3  于 2023-03-19  发布在  Windows
关注(0)|答案(1)|浏览(200)

我正在写一个程序,它使用WASAPI环回捕获来捕获Windows设备上的输出。原则上它工作正常,但每当我试图调试它时,它就会从断点继续后中断。
我可以在Windows自己的示例代码中重现这一点:我使用的是CaptureSharedEventDriven sample
然后我遵循instructions to change this demo to use loopback,它很简单:

  • GetDefaultAudioEndpoint中将eCapture更改为eRender
  • EnumAudioEndpoints中的eCapture更改为eRender
  • AUDCLNT_STREAMFLAGS_LOOPBACK添加到IAudioClient::Initialize调用

这样就可以正确地捕获音频输出。但是,当我在CWASAPICapture::Start(...)的末尾(示例中的第262行)断点,然后继续时,捕获就变成了垃圾。捕获的音频每1056个样本(这也是IAudioClient的缓冲区大小)显示不连续性,并且每次迭代丢失384个样本。
我可以通过添加以下调试代码来证明这一点:

[WASAPICapture.cpp, line 358]

hr = _CaptureClient->GetBuffer(&pData, &framesAvailable, &flags, NULL, NULL);
if (SUCCEEDED(hr))
{
   UINT32 framesToCopy = min(framesAvailable, static_cast<UINT32>((_CaptureBufferSize - _CurrentCaptureIndex) / _FrameSize));
   if (framesToCopy != 0)
   {
      //
      // Adding this in order to trace the output issue:
      //
      if (flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) {
         printf("Discontinuity detected, writing %d samples\n", framesAvailable);
      }
      else {
         printf("Correct render, writing %d samples\n", framesAvailable);
      }

命中断点后,对于捕获的其余部分,输出现在将为:

Discontinuity detected, writing 480 samples
Correct render, writing 480 samples
Discontinuity detected, writing 96 samples
Discontinuity detected, writing 480 samples
Correct render, writing 480 samples
Discontinuity detected, writing 96 samples
Correct render, writing 480 samples
Correct render, writing 480 samples
Discontinuity detected, writing 96 samples
etc...

如何使WASAPI从此错误中恢复?

bvhaajcl

bvhaajcl1#

此MS示例包含一个错误,并且缺少一行基本代码。可以在另一个示例中找到正确的实现版本(尽管用例略有不同):ApplicationLoopback
应在GetBuffer()ReleaseBuffer()代码周围添加while-loop:

while (SUCCEEDED(m_AudioCaptureClient->GetNextPacketSize(&FramesAvailable)) &&
       FramesAvailable > 0)   // <-- THIS LOOP SHOULD BE ADDED
{
   hr = _CaptureClient->GetBuffer(&pData, &framesAvailable, &flags, NULL, NULL);
   if (SUCCEEDED(hr))
   {
      UINT32 framesToCopy = min(framesAvailable, static_cast<UINT32>((_CaptureBufferSize - _CurrentCaptureIndex) / _FrameSize));
       if (framesToCopy != 0)
       {
        .....

实际上,ApplicationLoopback示例中的这一行带有大量注解,并附有解释:

// A word on why we have a loop here;
    // Suppose it has been 10 milliseconds or so since the last time
    // this routine was invoked, and that we're capturing 48000 samples per second.
    //
    // The audio engine can be reasonably expected to have accumulated about that much
    // audio data - that is, about 480 samples.
    //
    // However, the audio engine is free to accumulate this in various ways:
    // a. as a single packet of 480 samples, OR
    // b. as a packet of 80 samples plus a packet of 400 samples, OR
    // c. as 48 packets of 10 samples each.
    //
    // In particular, there is no guarantee that this routine will be
    // run once for each packet.
    //
    // So every time this routine runs, we need to read ALL the packets
    // that are now available;
    //
    // We do this by calling IAudioCaptureClient::GetNextPacketSize
    // over and over again until it indicates there are no more packets remaining.

总之:音频引擎不需要给予你一个很好的数据包,比如480个样本,可以把它们分成不同的块。由于某种原因,调试断点代码会让它处于这样的状态。如果没有这个while-loop来检查GetNextPacketSize,它就无法从中恢复。
将此行添加到CaptureSharedEventDriven示例可修复此问题。

相关问题