如何使用 WASAPI 共享模式获得低于 10 毫秒的延迟?

Posted

技术标签:

【中文标题】如何使用 WASAPI 共享模式获得低于 10 毫秒的延迟?【英文标题】:How to get below 10ms latency using WASAPI shared mode? 【发布时间】:2016-09-24 21:30:51 【问题描述】:

根据 Microsoft 的说法,从 Windows 10 开始,使用共享模式 WASAPI 的应用程序可以请求小于 10 毫秒的缓冲区大小(请参阅 https://msdn.microsoft.com/en-us/library/windows/hardware/mt298187%28v=vs.85%29.aspx)。

根据文章,实现如此低的延迟需要一些驱动程序更新,我做到了。使用独占模式渲染和捕获流,我测量了大约 13 毫秒的总往返延迟(使用硬件环回电缆)。这向我表明,至少有一个端点成功地实现了

文章提到应用程序可以使用新的IAudioClient3 接口来查询使用IAudioClient3::GetSharedModeEnginePeriod() 的Windows 音频引擎支持的最小缓冲区大小。但是,此函数在我的系统上总是返回 10 毫秒,任何尝试使用 IAudioClient::Initialize()IAudioClient3::InitializeSharedAudiostream() 初始化音频流且周期低于 1​​0 毫秒的尝试总是导致 AUDCLNT_E_INVALID_DEVICE_PERIOD

为了确定,我还禁用了音频驱动程序中的任何效果处理。 我错过了什么?甚至有可能从共享模式中获得低延迟吗? 请参阅下面的一些示例代码。

#include <windows.h>
#include <atlbase.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <iostream>

#define VERIFY(hr) do                                     \
  auto temp = (hr);                                        \
  if(FAILED(temp))                                        \
    std::cout << "Error: " << #hr << ": " << temp << "\n"; \
    goto error;                                            \
                                                          \
 while(0)


int main(int argc, char** argv) 

  HRESULT hr;
  CComPtr<IMMDevice> device;
  AudioClientProperties props;
  CComPtr<IAudioClient> client;
  CComPtr<IAudioClient2> client2;
  CComPtr<IAudioClient3> client3;
  CComHeapPtr<WAVEFORMATEX> format;
  CComPtr<IMMDeviceEnumerator> enumerator; 

  REFERENCE_TIME minTime, maxTime, engineTime;
  UINT32 min, max, fundamental, default_, current;

  VERIFY(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED));
  VERIFY(enumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)));
  VERIFY(enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &device));
  VERIFY(device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, reinterpret_cast<void**>(&client)));
  VERIFY(client->QueryInterface(&client2));
  VERIFY(client->QueryInterface(&client3));

  VERIFY(client3->GetCurrentSharedModeEnginePeriod(&format, &current));

  // Always fails with AUDCLNT_E_OFFLOAD_MODE_ONLY.
  hr = client2->GetBufferSizeLimits(format, TRUE, &minTime, &maxTime);
  if(hr == AUDCLNT_E_OFFLOAD_MODE_ONLY)
    std::cout << "GetBufferSizeLimits returned AUDCLNT_E_OFFLOAD_MODE_ONLY.\n";
  else if(SUCCEEDED(hr))
    std::cout << "hw min = " << (minTime / 10000.0) << " hw max = " << (maxTime / 10000.0) << "\n";
  else
    VERIFY(hr);

  // Correctly? reports a minimum hardware period of 3ms and audio engine period of 10ms.
  VERIFY(client->GetDevicePeriod(&engineTime, &minTime));
  std::cout << "hw min = " << (minTime / 10000.0) << " engine = " << (engineTime / 10000.0) << "\n";

  // All values are set to a number of frames corresponding to 10ms.
  // This does not change if i change the device's sampling rate in the control panel.
  VERIFY(client3->GetSharedModeEnginePeriod(format, &default_, &fundamental, &min, &max));
  std::cout << "default = " << default_ 
            << " fundamental = " << fundamental 
            << " min = " << min 
            << " max = " << max 
            << " current = " << current << "\n";

  props.bIsOffload = FALSE;
  props.cbSize = sizeof(props);
  props.eCategory = AudioCategory_ForegroundOnlyMedia;
  props.Options = AUDCLNT_STREAMOPTIONS_RAW | AUDCLNT_STREAMOPTIONS_MATCH_FORMAT;

  // Doesn't seem to have any effect regardless of category/options values.
  VERIFY(client2->SetClientProperties(&props));

  format.Free();
  VERIFY(client3->GetCurrentSharedModeEnginePeriod(&format, &current));
  VERIFY(client3->GetSharedModeEnginePeriod(format, &default_, &fundamental, &min, &max));
  std::cout << "default = " << default_ 
            << " fundamental = " << fundamental 
            << " min = " << min 
            << " max = " << max 
            << " current = " << current << "\n";

error:
  CoUninitialize();
  return 0;

【问题讨论】:

这肯定是驱动问题,绝不是音频问题。我得到了相同的基本结果,Cirrus Logic CS4208 驱动程序版本 6.6001.3.24 和 Windows 10.0.10586。你应该提到你的。 使用文章中提到的“更新的驱动程序”使用板载高清音频进行了测试。将使用另一个界面再次测试,而且我似乎无法再找到从哪里获得此更新的驱动程序(但我知道它是 Windows 提供的特定于低延迟音频的驱动程序,所以如果它真的是它会很奇怪一个司机的事情)。我会调查一下,看看我的系统上到底有什么。 知道了。我使用了这里解释的驱动程序:msdn.microsoft.com/en-us/library/windows/hardware/…。引用:“为了测量不同缓冲区大小的往返延迟,用户需要安装支持小缓冲区的驱动程序。收件箱 HDAudio 驱动程序已更新为支持 128 个样本 (2.66ms@48kHz) 和 480 个样本之间的缓冲区大小 ( 10ms@48kHz)”。今晚将尝试使用其他设备。 因为他要求共享访问权限 更重要的是,因为大多数卡都不带asio驱动。 Wasapi 开箱即用。 【参考方案1】:

以上评论中的 Per Hans,请仔细检查您是否遵循了低延迟音频here 的说明。

为了确定,我会重新启动机器; Windows 对这种东西可能有点挑剔。

【讨论】:

以上是关于如何使用 WASAPI 共享模式获得低于 10 毫秒的延迟?的主要内容,如果未能解决你的问题,请参考以下文章

WASAPI 在 Windows 上捕获的缓冲区大小

使用 WASAPI 录制音频流

WASAPI:IAudioClient->Initialize 成功,即使 IAudioClient->IsFormatSupported 以相同格式失败

WASAPI 捕获的数据包不对齐

如何使用 NAudio 更改 WASAPI 记录比特率?

WASAPI 的问题