2016-05-26 40 views
19

Secondo Microsoft, a partire da Windows 10, le applicazioni che utilizzano WASAPI in modalità condivisa possono richiedere dimensioni del buffer inferiori a 10 ms (vedere https://msdn.microsoft.com/en-us/library/windows/hardware/mt298187%28v=vs.85%29.aspx).Come ottenere una latenza inferiore a 10 ms utilizzando la modalità condivisa WASAPI?

Secondo l'articolo, il raggiungimento di tali latenze richiede alcuni aggiornamenti del driver, cosa che ho fatto. Usando un rendering in modalità esclusiva e un flusso di acquisizione, ho misurato una latenza totale di andata e ritorno (utilizzando un cavo loopback hardware) di circa 13 ms. Questo mi suggerisce che almeno uno degli endpoint raggiunge con successo una latenza di < 10 ms. (Questa supposizione è corretta?)

L'articolo indica che le applicazioni possono utilizzare la nuova interfaccia IAudioClient3 per richiedere la dimensione minima del buffer supportata dal motore audio di Windows utilizzando IAudioClient3::GetSharedModeEnginePeriod(). Tuttavia, questa funzione restituisce sempre 10 ms sul mio sistema e qualsiasi tentativo di inizializzare un flusso audio utilizzando IAudioClient::Initialize() o IAudioClient3::InitializeSharedAudioStream() con un periodo inferiore a 10 ms risulta sempre in AUDCLNT_E_INVALID_DEVICE_PERIOD.

Per sicurezza, ho disabilitato anche l'elaborazione degli effetti nei driver audio. Cosa mi manca? È anche possibile ottenere una bassa latenza dalla modalità condivisa? Vedi sotto per alcuni esempi di codice.

#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

Sicuramente questo è un problema di driver, mai un problema nell'audio. Ottengo gli stessi risultati di base, Cirrus Logic CS4208 versione driver 6.6001.3.24 e Windows 10.0.10586. Dovresti menzionare il tuo. –

+0

Testato utilizzando l'audio HD integrato utilizzando "driver aggiornati" come indicato nell'articolo. Testerà nuovamente utilizzando un'altra interfaccia, inoltre non riesco a trovare dove trovare i driver aggiornati più (ma so per certo che erano driver specifici per Windows per l'audio a bassa latenza, quindi sarebbe strano se fosse davvero una cosa del guidatore). Lo esaminerò per vedere cosa è esattamente sul mio sistema. –

+0

Capito. Ho usato i driver come spiegato qui: https://msdn.microsoft.com/en-us/library/windows/hardware/mt298187(v=vs.85).aspx#Measurement_Tools. Citazione: "Per misurare la latenza di roundtrip per diverse dimensioni del buffer, gli utenti devono installare un driver che supporti piccoli buffer. Il driver di posta in arrivo HDAudio è stato aggiornato per supportare le dimensioni del buffer tra 128 campioni (2,[email protected]) e 480 campioni (10ms @ 48kHz)". Proverò a usare un altro dispositivo stasera. –

risposta

0

Per Hans nel commento di cui sopra, doppio controllo che hai seguito le istruzioni per la bassa latenza audio here.

Avrei riavviato la macchina solo per essere sicuro; Windows può essere un po 'schizzinoso con quel genere di cose.