2016-05-26 23 views
19

Według firmy Microsoft, począwszy od systemu Windows 10, aplikacje korzystające z trybu WASAPI z trybem współużytkowanym mogą żądać rozmiarów buforów mniejszych niż 10 ms (patrz https://msdn.microsoft.com/en-us/library/windows/hardware/mt298187%28v=vs.85%29.aspx).Jak uzyskać mniej niż 10ms opóźnienia przy użyciu wspólnego trybu WASAPI?

Zgodnie z artykułem, osiągnięcie tak niskich opóźnień wymaga pewnych aktualizacji sterowników, co zrobiłem. Korzystając z trybu renderowania i strumienia przechwytywania w trybie wyłączności, zmierzyłem całkowite opóźnienie w czasie podróży (przy użyciu kabla sprzężenia zwrotnego) około 13 ms. Sugeruje to mi, że co najmniej jeden z punktów końcowych pomyślnie osiąga opóźnienie wynoszące < 10 ms. (Czy to założenie jest poprawne?)

W artykule wspomniano, że aplikacje mogą korzystać z nowego interfejsu zapytań IAudioClient3 minimalny rozmiar bufora obsługiwanego przez silnik audio, Windows przy użyciu IAudioClient3::GetSharedModeEnginePeriod(). Jednak ta funkcja zawsze zwraca 10ms w moim systemie, a każda próba zainicjowania strumienia audio przy użyciu albo IAudioClient::Initialize() lub IAudioClient3::InitializeSharedAudioStream() z okresem niższym niż 10 ms zawsze skutkuje AUDCLNT_E_INVALID_DEVICE_PERIOD.

Dla pewności wyłączyłem także przetwarzanie efektów w sterownikach audio. Czego mi brakuje? Czy możliwe jest uzyskanie niskiego opóźnienia z trybu współdzielonego? Zobacz poniżej przykładowy kod.

#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; 
} 
+0

Z pewnością jest to problem ze sterownikiem, nigdy nie stanowi problemu w dźwięku. Otrzymuję te same podstawowe wyniki, sterownik Cirrus Logic CS4208 w wersji 6.6001.3.24 i Windows 10.0.10586. Powinieneś wspomnieć o swojej. –

+0

Testowano za pomocą wbudowanego dźwięku HD za pomocą "zaktualizowanych sterowników", jak wspomniano w artykule. Przetestuję ponownie używając innego interfejsu, także nie mogę się już zorientować, skąd pobrać te zaktualizowane sterowniki (ale wiem, że to były sterowniki dla Windows przeznaczone dla dźwięku o niskim opóźnieniu, więc byłoby dziwnie, gdyby tak naprawdę było rzecz kierowcy). Patrzę na niego, aby zobaczyć, co dokładnie jest w moim systemie. –

+0

Mam to. Użyłem sterowników, jak wyjaśniono tutaj: https://msdn.microsoft.com/en-us/library/windows/hardware/mt298187(v=vs.85).aspx#Measurement_Tools. Cytat: "Aby zmierzyć opóźnienie w obie strony dla różnych rozmiarów buforów, użytkownicy muszą zainstalować sterownik, który obsługuje małe bufory. Sterownik HDAudio skrzynki odbiorczej został zaktualizowany w celu obsługi buforów o rozmiarach od 128 próbek ([email protected]) do 480 próbek (10 ms przy 48 kHz) ". Spróbuję dziś skorzystać z innego urządzenia. –

Odpowiedz

0

Per Hans w komentarzu powyżej, double-check, które zostały wykonane instrukcje dla niskiej latencji audio here.

Chciałbym zrestartować maszynę tylko dla pewności; System Windows może być trochę skomplikowany z tego rodzaju rzeczy.