it-swarm.com.de

Wie kann ich im WASAPI-Shared-Modus eine Latenz von unter 10 ms erreichen?

Microsoft zufolge können Anwendungen, die WASAPI im gemeinsam genutzten Modus verwenden, ab Windows 10 Puffergrößen von weniger als 10 ms anfordern (siehe https://msdn.Microsoft.com/en-us/library/windows/hardware/mt298187%28v=) vs.85% 29.aspx ).

Laut dem Artikel sind einige Treiberaktualisierungen erforderlich, die ich durchgeführt habe, um so niedrige Latenzen zu erreichen. Unter Verwendung eines exklusiven Render- und Capture-Streams habe ich eine Gesamt-Round-Trip-Latenz (unter Verwendung eines Hardware-Loopback-Kabels) von ca. 13 ms gemessen. Dies lässt vermuten, dass mindestens einer der Endpunkte eine Latenz von <10ms erreicht. (Ist diese Annahme richtig?)

In dem Artikel wird erwähnt, dass Anwendungen die neue IAudioClient3-Schnittstelle verwenden können, um die von der Windows-Audio-Engine mit IAudioClient3::GetSharedModeEnginePeriod() unterstützte Mindestpuffergröße abzufragen. Diese Funktion gibt jedoch auf meinem System immer 10 ms zurück, und jeder Versuch, einen Audiostream mit IAudioClient::Initialize() oder IAudioClient3::InitializeSharedAudioStream() mit einem Zeitraum von weniger als 10 ms zu initialisieren, führt immer zu AUDCLNT_E_INVALID_DEVICE_PERIOD.

Zur Sicherheit habe ich auch die Verarbeitung von Effekten in den Audiotreibern deaktiviert. Was vermisse ich? Ist es überhaupt möglich, im gemeinsam genutzten Modus eine geringe Latenz zu erreichen? Im Folgenden finden Sie einige Beispielcodes.

#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;
}
21

Überprüfen Sie in dem obigen Kommentar, ob Sie die Anweisungen für Audio mit niedriger Latenz befolgt haben hier .

Ich würde die Maschine neu starten, nur um sicherzugehen; Windows kann mit solchen Dingen ein bisschen pingelig sein.

0
TriskalJM