2016-05-26 2 views
19

Согласно Microsoft, начиная с Windows 10, приложения, использующие общий режим WASAPI, могут запрашивать размеры буфера менее 10 мс (см. https://msdn.microsoft.com/en-us/library/windows/hardware/mt298187%28v=vs.85%29.aspx).Как получить ниже 10 мс латентности, используя общий режим WASAPI?

В соответствии с этой статьей, для достижения таких низких латентностей требуются некоторые обновления драйверов, которые я сделал. Используя поток рендеринга и захвата эксклюзивного режима, я измерил общую задержку в оба конца (используя кабель кольцевой петли) около 13 мс. Это говорит о том, что по крайней мере одна из конечных точек успешно достигает латентности < 10 мс. (Правильно ли это предположение?)

В статье упоминается, что приложения могут использовать новый интерфейс IAudioClient3 для запроса минимального размера буфера, поддерживаемого звуковым движком Windows, с использованием IAudioClient3::GetSharedModeEnginePeriod(). Однако эта функция всегда возвращает 10 мс в моей системе, и любая попытка инициализации аудиопотока с использованием IAudioClient::Initialize() или IAudioClient3::InitializeSharedAudioStream() с периодом ниже 10 мс всегда приводит к 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; 
} 
+0

Несомненно, это проблема с драйвером, никогда не проблема в аудио. Я получаю те же основные результаты, драйвер Cirrus Logic CS4208 версии 6.6001.3.24 и Windows 10.0.10586. Вы должны упомянуть о себе. –

+0

Протестировано с использованием встроенного HD-звука с использованием «обновленных драйверов», как указано в статье. Повторите попытку с помощью другого интерфейса, также я не могу найти, где можно получить эти обновленные драйверы (но я знаю, что это были драйверы для Windows, предназначенные для аудио с низкой задержкой, поэтому было бы странно, если бы это было действительно вещь водителя). Взгляните на него, чтобы узнать, что именно находится в моей системе. –

+0

Получил это. Я использовал драйверы, как описано здесь: https://msdn.microsoft.com/en-us/library/windows/hardware/mt298187(v=vs.85).aspx#Measurement_Tools. Цитата: «Чтобы измерить латентность roundtrip для разных размеров буфера, пользователям необходимо установить драйвер, который поддерживает небольшие буферы. Драйвер HDbox от Inbox обновлен для поддержки размеров буфера между 128 выборками (2.66 мс48 кГц) и 480 образцами (10ms @ 48кГц)». Сегодня вечером попробуем использовать другое устройство. –

ответ

0

Per Hans в комментарии выше, дважды проверьте, что вы следовали инструкциям по Low Latency Audio here.

Я бы перезагрузил машину, чтобы быть уверенным; Windows может быть немного утончён с такими вещами.

Смежные вопросы