Звук с низкой задержкой
В этой статье рассматриваются изменения задержки звука в Windows 10. В ней рассматриваются параметры API для разработчиков приложений и изменения драйверов, которые можно вносить для поддержки звука с низкой задержкой. Задержка звука — это задержка между тем временем создания звука и время его прослушивания. Низкая задержка звука важна для нескольких ключевых сценариев, таких как:
- профессиональный звук
- Создание музыки
- Связь
- Виртуальная реальность
- Игры
Целями этого документа являются следующие задачи.
- Описание источников задержки звука в Windows.
- Объясните изменения, которые снижают задержку звука в стеке звука Windows 10.
- Укажите ссылку на то, как разработчики приложений и производители оборудования могут воспользоваться новой инфраструктурой для разработки приложений и драйверов с низкой задержкой звука.
В этой статье рассматриваются следующие темы:
- API AudioGraph для интерактивных сценариев создания мультимедиа.
- Изменения в WASAPI для поддержки низкой задержки.
- Улучшения в интерфейсах драйвера DDIs.
Терминология
Срок | Описание |
---|---|
Задержка отрисовки | Задержка между моментом отправки приложением буфера звуковых данных в API отрисовки и моментом воспроизведения из динамиков. |
Задержка записи | Задержка между временем захвата звука с микрофона до момента его отправки в API записи, которые используются приложением. |
Задержка полного цикла | Задержка между моментом захвата звука с микрофона, его обработки приложением и отправки на динамики для воспроизведения. Это примерно равно задержке отрисовки и задержке записи. |
Задержка отклика приложения на касание | Задержка между временем, когда пользователь нажимает экран до момента отправки сигнала приложению. |
Задержка звука после касания | Задержка между временем, когда пользователь нажимает на экран, событие поступает в приложение, а звук воспроизводится через динамики. Это равно задержке отрисовки и задержке сенсорного ввода в приложение. |
Звуковой стек Windows
На следующей схеме показана упрощенная версия стека звука Windows.
Ниже приведена сводка по задержкам в пути отрисовки: объекты обработки звука
Приложение записывает данные в буфер
Звуковой модуль считывает данные из буфера и обрабатывает его. Он также загружает звуковые эффекты в виде объектов обработки звука (API). Дополнительные сведения об API см. в объектах обработки звука Windows.
Задержка APO может варьироваться в зависимости от обработки сигналов внутри APO.
До Windows 10 задержка звукового модуля была равна ~12 мс для приложений, использующих данные с плавающей запятой и ~6 мс для приложений, использующих целые данные
В Windows 10 и более поздних версиях задержка сократилась до 1,3 мс для всех приложений.
Модуль аудиозаписи записывает обработанные данные в буфер.
До Windows 10 буфер всегда был установлен на ~10 мс.
Начиная с Windows 10 размер буфера определяется звуковым драйвером (дополнительные сведения о буфере описаны далее в этой статье).
Звуковой драйвер считывает данные из буфера и записывает их в оборудование.
Оборудование также может обрабатывать данные снова в виде дополнительных звуковых эффектов.
Пользователь слышит звук от динамика.
Ниже приведена сводка по задержке в пути записи:
Звук записывается с микрофона.
Оборудование может обрабатывать данные. Например, чтобы добавить звуковые эффекты.
Драйвер считывает данные из оборудования и записывает данные в буфер.
До Windows 10 этот буфер всегда был установлен на 10 мс.
Начиная с Windows 10 размер буфера определяется звуковым драйвером (дополнительные сведения ниже).
Звуковой модуль считывает данные из буфера и обрабатывает их. Он также загружает звуковые эффекты в виде объектов обработки звука (API).
Задержка AПО зависит от обработки сигналов в AПО.
До Windows 10 задержка звукового обработчика составила около 6 мс для приложений, использующих данные с плавающей запятой и ~0 мс для приложений, использующих целые данные.
В Windows 10 и более поздних версиях задержка сократилась до 0 мс для всех приложений.
Приложение сигнализирует о том, что данные доступны для чтения, как только звуковой механизм завершает обработку. Звуковой стек также предоставляет возможность монопольного режима. В этом случае данные проходят звуковой механизм и передаются непосредственно из приложения в буфер, из которого драйвер считывает его. Однако если приложение открывает конечную точку в монопольном режиме, то нет другого приложения, которое может использовать такую конечную точку для отрисовки или записи звука.
Еще одна популярная альтернатива для приложений, которым требуется низкая задержка, заключается в использовании модели ASIO (входные и выходные данные аудиопотока), которая использует монопольный режим. После установки стороннего драйвера ASIO приложения могут отправлять данные непосредственно из приложения в драйвер ASIO. Однако приложение должно быть записано таким образом, чтобы он разговаривал непосредственно с драйвером ASIO.
Оба варианта (монопольный режим и ASIO) имеют свои собственные ограничения. Они обеспечивают низкую задержку, но имеют свои собственные ограничения (некоторые из которых описаны выше). В результате звуковой механизм был изменен, чтобы снизить задержку, сохраняя гибкость.
Улучшения аудио стека
Windows 10 и более поздних версий были улучшены в трех областях, чтобы уменьшить задержку:
- Все приложения, использующие звук, заметят снижение задержки передачи данных туда и обратно на 4,5-16 мс (как описано в разделе выше) без каких-либо изменений кода или обновлений драйверов по сравнению с Windows 8.1.
- Приложения, использующие данные с плавающей запятой, будут иметь более низкую задержку в 16 мс.
- Приложения, использующие целые данные, будут иметь более низкую задержку 4,5 мс.
- Системы с обновленными драйверами обеспечивают еще более низкую задержку кругового пути:
- Драйверы могут использовать DDIS с низкой задержкой, чтобы сообщить о поддерживаемых размерах буфера, который используется для передачи данных между Windows и оборудованием. Передача данных не обязательно использует 10-мс буферов, как и в предыдущих версиях Windows. Вместо этого драйвер может указать, может ли он использовать небольшие буферы, например 5 мс, 3 мс, 1 мс и т. д.
- Приложения, которым требуется низкая задержка, могут использовать API аудиофайлов с низкой задержкой (AudioGraph или WASAPI), чтобы запросить размеры буферов, поддерживаемые драйвером, и выбрать тот, который будет использоваться для передачи данных в оборудование или из оборудования.
- Если приложение использует размер буфера ниже определенного порогового значения для отрисовки и записи звука, Windows входит в специальный режим, где он управляет своими ресурсами таким образом, чтобы избежать помех между потоковой передачей звука и другими подсистемами. Это уменьшит прерывания выполнения звуковой подсистемы и свести к минимуму вероятность сбоев звука. Когда приложение прекращает потоковую передачу, Windows возвращается в обычный режим выполнения. Звуковая подсистема состоит из следующих ресурсов:
- Поток звукового модуля, обрабатывающий звук с низкой задержкой.
- Все потоки и прерывания, зарегистрированные драйвером (используя dDIS с низкой задержкой, описанные в разделе о регистрации ресурсов драйвера).
- Некоторые или все звуковые потоки из приложений, запрашивающих небольшие буферы, и из всех приложений, использующих один и тот же граф аудиоустройств (например, один и тот же режим обработки сигналов) с любым приложением, запрашивающим небольшие буферы:
- Обратные вызовы AudioGraph в пути потоковой передачи.
- Если приложение использует WASAPI, то только те рабочие элементы, которые были отправлены в API Real-Time рабочих очередей или MFCreateMFByteStreamOnStreamEx и отмечены как "Audio" или "ProAudio".
Улучшения API
Следующие два API Windows 10 предоставляют возможности с низкой задержкой.
Чтобы определить, какие из двух API следует использовать:
- Предпочитать AudioGraph, где это возможно для разработки новых приложений.
- Используйте только WASAPI, если:
- Вам требуется больше управления, чем это предоставляется AudioGraph.
- Требуется более низкая задержка, чем предусмотрено в AudioGraph.
В разделе этой статьи показаны конкретные измерения из системы на базе Haswell с использованием встроенного драйвера HDAudio.
В следующих разделах описаны возможности низкой задержки в каждом API. Как было отмечено в предыдущем разделе, для достижения минимальной задержки система должна иметь обновленные драйверы, поддерживающие небольшие размеры буферов.
AudioGraph
AudioGraph — это API универсальной платформы Windows в Windows 10 и более поздних версиях, предназначенный для реализации сценариев интерактивного и музыкального создания с легкостью. AudioGraph доступен на нескольких языках программирования (C++, C#, JavaScript) и имеет простую и многофункциональную модель программирования.
Для целевых сценариев низкой задержки AudioGraph предоставляет свойство AudioGraphSettings::QuantumSizeSelectionMode. Это свойство может быть любым из значений, показанных в таблице ниже:
Ценность | Описание |
---|---|
Системные настройки по умолчанию | Задает размер буфера по умолчанию (~10 мс) |
Самая низкая латентность | Задает буфер минимальному значению, поддерживаемого драйвером. |
Ближайший к желаемому | Задает размер буфера либо равным значению, определенному свойством DesiredSamplesPerQuantum, либо значением, которое близко к DesiredSamplesPerQuantum, как поддерживается драйвером. |
В примере AudioCreation показано, как использовать AudioGraph для низкой задержки. В следующем фрагменте кода показано, как задать минимальный размер буфера:
AudioGraphSettings settings = new AudioGraphSettings(AudioRenderCategory.Media);
settings.QuantumSizeSelectionMode = QuantumSizeSelectionMode.LowestLatency;
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
API аудиосеансов Windows (WASAPI)
Начиная с Windows 10, WASAPI был расширен для:
- Разрешите приложению обнаруживать диапазон размеров буфера (т. е. периодические значения), поддерживаемые звуковым драйвером заданного звукового устройства. Это позволяет приложению выбирать размер буфера по умолчанию (10 мс) или небольшой буфер (менее 10 мс) при открытии потока в общем режиме. Если приложение не указывает размер буфера, он будет использовать размер буфера по умолчанию.
- Разрешите приложению обнаруживать текущий формат и периодичность звукового модуля. Это позволяет приложениям выполнять привязку к текущим параметрам звукового модуля.
- Разрешить приложению указать, что он хочет отрисовывать или записывать данные в формате, который он указывает без каких-либо перезаписей звукового модуля
Перечисленные выше функции будут доступны на всех устройствах с Windows. Однако некоторые устройства с достаточным количеством ресурсов и обновленными драйверами обеспечивают лучший пользовательский интерфейс, чем другие.
Приведенные выше функции предоставляются интерфейсом, который называется IAudioClient3, который является производным от IAudioClient2.
IAudioClient3 определяет следующие 3 метода:
Метод | Описание |
---|---|
GetCurrentSharedModeEnginePeriod | Возвращает текущий формат и периодичность звукового модуля. |
ПолучитьПериодДвижкаВОбщемРежиме | Возвращает диапазон периодичности, поддерживаемый подсистемой для указанного формата потока. |
InitializeSharedAudioStream | Инициализирует общий поток с указанной периодичностью |
В примере WASAPIAudio показано, как использовать IAudioClient3 для низкой задержки.
В следующем фрагменте кода показано, как приложение создания музыки может работать в наименьшем параметре задержки, поддерживаемом системой.
// 1. Activation
// Get a string representing the Default Audio (Render|Capture) Device
m_DeviceIdString = MediaDevice::GetDefaultAudio(Render|Capture)Id(
Windows::Media::Devices::AudioDeviceRole::Default );
// This call must be made on the main UI thread. Async operation will call back to
// IActivateAudioInterfaceCompletionHandler::ActivateCompleted, which must be an agile // interface implementation
hr = ActivateAudioInterfaceAsync( m_DeviceIdString->Data(), __uuidof(IAudioClient3),
nullptr, this, &asyncOp );
// 2. Setting the audio client properties – note that low latency offload is not supported
AudioClientProperties audioProps = {0};
audioProps.cbSize = sizeof( AudioClientProperties );
audioProps.eCategory = AudioCategory_Media;
// if the device has System.Devices.AudioDevice.RawProcessingSupported set to true and you want to use raw mode
// audioProps.Options |= AUDCLNT_STREAMOPTIONS_RAW;
//
// if it is important to avoid resampling in the audio engine, set this flag
// audioProps.Options |= AUDCLNT_STREAMOPTIONS_MATCH_FORMAT;
hr = m_AudioClient->SetClientProperties( &audioProps ); if (FAILED(hr)) { ... }
// 3. Querying the legal periods
hr = m_AudioClient->GetMixFormat( &mixFormat ); if (FAILED(hr)) { ... }
hr = m_AudioClient->GetSharedModeEnginePeriod(wfx, &defaultPeriodInFrames, &fundamentalPeriodInFrames, &minPeriodInFrames, &maxPeriodInFrames); if (FAILED(hr)) { ... }
// legal periods are any multiple of fundamentalPeriodInFrames between
// minPeriodInFrames and maxPeriodInFrames, inclusive
// the Windows shared-mode engine uses defaultPeriodInFrames unless an audio client // has specifically requested otherwise
// 4. Initializing a low-latency client
hr = m_AudioClient->InitializeSharedAudioStream(
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
desiredPeriodInFrames,
mixFormat,
nullptr); // audio session GUID
if (AUDCLNT_E_ENGINE_PERIODICITY_LOCKED == hr) {
/* engine is already running at a different period; call m_AudioClient->GetSharedModeEnginePeriod to see what it is */
} else if (FAILED(hr)) {
...
}
// 5. Initializing a client with a specific format (if the format needs to be different than the default format)
AudioClientProperties audioProps = {0};
audioProps.cbSize = sizeof( AudioClientProperties );
audioProps.eCategory = AudioCategory_Media;
audioProps.Options |= AUDCLNT_STREAMOPTIONS_MATCH_FORMAT;
hr = m_AudioClient->SetClientProperties( &audioProps );
if (FAILED(hr)) { ... }
hr = m_AudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, appFormat, &closest);
if (S_OK == hr) {
/* device supports the app format */
} else if (S_FALSE == hr) {
/* device DOES NOT support the app format; closest supported format is in the "closest" output variable */
} else {
/* device DOES NOT support the app format, and Windows could not find a close supported format */
}
hr = m_AudioClient->InitializeSharedAudioStream(
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
defaultPeriodInFrames,
appFormat,
nullptr); // audio session GUID
if (AUDCLNT_E_ENGINE_FORMAT_LOCKED == hr) {
/* engine is already running at a different format */
} else if (FAILED(hr)) {
...
}
Кроме того, корпорация Майкрософт рекомендует для приложений, использующих WASAPI, также использовать API рабочих очередей Real-Time или MFCreateMFByteStreamOnStreamEx для создания рабочих элементов и помечать их как аудио или Pro Audio вместо потоков. Это позволит Windows управлять ими таким образом, чтобы избежать помех со стороны неаудиоподсистем. В отличие от этого, все потоки AudioGraph автоматически управляются Windows. В следующем фрагменте кода из примера WASAPIAudio показано, как использовать API рабочих очередей MF.
// Specify Source Reader Attributes
Attributes->SetUnknown( MF_SOURCE_READER_ASYNC_CALLBACK, static_cast<IMFSourceReaderCallback *>(this) );
if (FAILED( hr ))
{
goto exit;
}
Attributes->SetString( MF_READWRITE_MMCSS_CLASS_AUDIO, L"Audio" );
if (FAILED( hr ))
{
goto exit;
}
Attributes->SetUINT32( MF_READWRITE_MMCSS_PRIORITY_AUDIO, 0 );
if (FAILED( hr ))
{
goto exit;
}
// Create a stream from IRandomAccessStream
hr = MFCreateMFByteStreamOnStreamEx (reinterpret_cast<IUnknown*>(m_ContentStream), &ByteStream );
if ( FAILED( hr ) )
{
goto exit;
}
// Create source reader
hr = MFCreateSourceReaderFromByteStream( ByteStream, Attributes, &m_MFSourceReader );
Кроме того, в следующем фрагменте кода показано, как использовать API рабочей очереди RT.
#define INVALID_WORK_QUEUE_ID 0xffffffff
DWORD g_WorkQueueId = INVALID_WORK_QUEUE_ID;
//#define MMCSS_AUDIO_CLASS L"Audio"
//#define MMCSS_PROAUDIO_CLASS L"ProAudio"
STDMETHODIMP TestClass::GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
HRESULT hr = S_OK;
*pdwFlags = 0;
*pdwQueue = g_WorkQueueId;
return hr;
}
//-------------------------------------------------------
STDMETHODIMP TestClass::Invoke(IRtwqAsyncResult* pAsyncResult)
{
HRESULT hr = S_OK;
IUnknown *pState = NULL;
WCHAR className[20];
DWORD bufferLength = 20;
DWORD taskID = 0;
LONG priority = 0;
printf("Callback is invoked pAsyncResult(0x%0x) Current process id :0x%0x Current thread id :0x%0x\n", (INT64)pAsyncResult, GetCurrentProcessId(), GetCurrentThreadId());
hr = RtwqGetWorkQueueMMCSSClass(g_WorkQueueId, className, &bufferLength);
IF_FAIL_EXIT(hr, Exit);
if (className[0])
{
hr = RtwqGetWorkQueueMMCSSTaskId(g_WorkQueueId, &taskID);
IF_FAIL_EXIT(hr, Exit);
hr = RtwqGetWorkQueueMMCSSPriority(g_WorkQueueId, &priority);
IF_FAIL_EXIT(hr, Exit);
printf("MMCSS: [%ws] taskID (%d) priority(%d)\n", className, taskID, priority);
}
else
{
printf("non-MMCSS\n");
}
hr = pAsyncResult->GetState(&pState);
IF_FAIL_EXIT(hr, Exit);
Exit:
return S_OK;
}
//-------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;
HANDLE signalEvent;
LONG Priority = 1;
IRtwqAsyncResult *pAsyncResult = NULL;
RTWQWORKITEM_KEY workItemKey = NULL;;
IRtwqAsyncCallback *callback = NULL;
IUnknown *appObject = NULL;
IUnknown *appState = NULL;
DWORD taskId = 0;
TestClass cbClass;
NTSTATUS status;
hr = RtwqStartup();
IF_FAIL_EXIT(hr, Exit);
signalEvent = CreateEvent(NULL, true, FALSE, NULL);
IF_TRUE_ACTION_EXIT(signalEvent == NULL, hr = E_OUTOFMEMORY, Exit);
g_WorkQueueId = RTWQ_MULTITHREADED_WORKQUEUE;
hr = RtwqLockSharedWorkQueue(L"Audio", 0, &taskId, &g_WorkQueueId);
IF_FAIL_EXIT(hr, Exit);
hr = RtwqCreateAsyncResult(NULL, reinterpret_cast<IRtwqAsyncCallback*>(&cbClass), NULL, &pAsyncResult);
IF_FAIL_EXIT(hr, Exit);
hr = RtwqPutWaitingWorkItem(signalEvent, Priority, pAsyncResult, &workItemKey);
IF_FAIL_EXIT(hr, Exit);
for (int i = 0; i < 5; i++)
{
SetEvent(signalEvent);
Sleep(30);
hr = RtwqPutWaitingWorkItem(signalEvent, Priority, pAsyncResult, &workItemKey);
IF_FAIL_EXIT(hr, Exit);
}
Exit:
if (pAsyncResult)
{
pAsyncResult->Release();
}
if (INVALID_WORK_QUEUE_ID != g_WorkQueueId)
{
hr = RtwqUnlockWorkQueue(g_WorkQueueId);
if (FAILED(hr))
{
printf("Failed with RtwqUnlockWorkQueue 0x%x\n", hr);
}
hr = RtwqShutdown();
if (FAILED(hr))
{
printf("Failed with RtwqShutdown 0x%x\n", hr);
}
}
if (FAILED(hr))
{
printf("Failed with error code 0x%x\n", hr);
}
return 0;
}
Наконец, разработчикам приложений, используюющим WASAPI, необходимо пометить потоки с категорией звука и использовать режим обработки необработанных сигналов на основе функциональных возможностей каждого потока. Корпорация Майкрософт рекомендует, чтобы все звуковые потоки не использовали режим обработки необработанных сигналов, если не понимаются последствия. Необработанный режим обходит всю обработку сигналов, выбранную изготовителем оборудования:
- Сигнал отрисовки для конкретной конечной точки может быть неоптимальным.
- Сигнал записи может появиться в формате, который приложение не может понять.
- Может быть улучшена задержка.
Улучшения драйвера
Чтобы звуковые драйверы поддерживали низкую задержку, Windows 10 и более поздних версий предоставляют следующие функции:
- [Обязательный] Объявите минимальный размер буфера, поддерживаемый в каждом режиме.
- [Необязательно, но рекомендуется] Улучшение координации потока данных между драйвером и Windows.
- [Необязательно, но рекомендуется] Зарегистрируйте ресурсы драйвера (прерывания, потоки), чтобы они могли быть защищены Windows в сценариях с низкой задержкой. Драйверам функций мини-порта HDAudio, перечисленным встроенным драйвером шины HDAudio hdaudbus.sys, не нужно регистрировать прерывания HDAudio, так как это уже сделано hdaudbus.sys. Однако если драйвер минипорта создает собственные потоки, необходимо зарегистрировать их.
В следующих трех разделах подробно описана каждая функция.
Объявление минимального размера буфера
Драйвер работает под различными ограничениями при перемещении звуковых данных между Windows, драйвером и оборудованием. Эти ограничения могут быть вызваны физическим аппаратным транспортом, который перемещает данные между памятью и оборудованием или из-за модулей обработки сигналов в аппаратном или связанном DSP.
Начиная с Windows 10 версии 1607 драйвер может выразить свои возможности размера буфера с помощью свойства устройства DEVPKEY_KsAudio_PacketSize_Constraints2. Это свойство позволяет пользователю определить абсолютный минимальный размер буфера, поддерживаемый драйвером, и ограничения размера буфера для каждого режима обработки сигналов. Ограничения, относящиеся к режиму, должны быть выше минимального размера буфера драйверов, в противном случае они игнорируются стеком звука.
Например, в следующем фрагменте кода показано, как драйвер может объявить, что абсолютный минимальный поддерживаемый размер буфера составляет 2 мс, но режим по умолчанию поддерживает 128 кадров, который соответствует 3 мс, если предполагается частота выборки 48 кГц.
//
// Describe buffer size constraints for WaveRT buffers
//
static struct
{
KSAUDIO_PACKETSIZE_CONSTRAINTS2 TransportPacketConstraints;
KSAUDIO_PACKETSIZE_PROCESSINGMODE_CONSTRAINT AdditionalProcessingConstraints[1];
} SysvadWaveRtPacketSizeConstraintsRender =
{
{
2 * HNSTIME_PER_MILLISECOND, // 2 ms minimum processing interval
FILE_BYTE_ALIGNMENT, // 1 byte packet size alignment
0, // no maximum packet size constraint
2, // 2 processing constraints follow
{
STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT, // constraint for default processing mode
128, // 128 samples per processing frame
0, // NA hns per processing frame
},
},
{
{
STATIC_AUDIO_SIGNALPROCESSINGMODE_MOVIE, // constraint for movie processing mode
1024, // 1024 samples per processing frame
0, // NA hns per processing frame
},
}
};
Дополнительные сведения об этих структурах см. в следующих статьях:
- структура KSAUDIO_PACKETSIZE_CONSTRAINTS
- KSAUDIO_PACKETSIZE_CONSTRAINTS2 структура
- структура KSAUDIO_PACKETSIZE_PROCESSINGMODE_CONSTRAINT
Кроме того, в примере
Улучшение координации между драйвером и ОС
DDIs, описанные в этом разделе, позволяют драйверу:
- Четко укажите, какая половина буфера (пакет) доступна для Windows, чтобы операционная система не делала предположения на основе положения ссылки на кодек. Это помогает Windows быстрее восстанавливаться из звуковых сбоев.
- При необходимости оптимизируйте или упрощайте передачу данных из буфера WaveRT. Объем выгоды здесь зависит от проектирования подсистемы DMA или другого механизма передачи данных между буфером WaveRT и, возможно, оборудованием DSP.
- "Всплеск" захватывал данные быстрее, чем в режиме реального времени, если драйвер внутренне накапливал собранные данные. Это в основном предназначено для сценариев активации голосовой связи, но может применяться во время обычной потоковой передачи.
- Предоставьте информацию о текущей позиции потока вместо того, чтобы позволять Windows угадывать её, что потенциально позволяет получить более точные данные о положении.
Этот DDI полезен в случае использования DSP. Однако стандартный драйвер HD Audio или другие простые кольцевые конструкции буфера DMA могут не найти много преимуществ в этих DDI, перечисленных здесь.
Некоторые процедуры драйверов возвращают метки времени счетчика производительности Windows, отражающие момент захвата или воспроизведения данных устройством.
На устройствах, имеющих сложные конвейеры DSP и обработку сигналов, вычисление точной метки времени может быть сложной задачей и должно выполняться тщательно. Метки времени не должны отражать время передачи образцов из Windows в DSP или обратно.
Для вычисления значений счетчика производительности драйвер и DSP могут использовать некоторые из следующих методов.
- В рамках DSP отслеживайте временные метки выборок с помощью некоторых внутренних системных часов DSP.
- Для взаимодействия драйвера и DSP вычислите корреляцию между счетчиком производительности Windows и настенными часами DSP. Процедуры для этого могут варьироваться от простых (но менее точных) до довольно сложных или новых (но более точных).
- Учитывайте любые постоянные задержки из-за алгоритмов обработки сигналов, конвейера или аппаратного транспорта, если они не учтены иначе.
В примере sysvad показано, как использовать вышеупомянутые DDIs.
Регистрация ресурсов драйвера
Чтобы обеспечить работу без сбоев, звуковые драйверы должны зарегистрировать свои ресурсы потоковой передачи с помощью Portcls. Это позволяет Windows управлять ресурсами, чтобы избежать помех между потоковой передачей звука и другими подсистемами.
Потоковые ресурсы — это все ресурсы, используемые звуковым драйвером для обработки аудиопотоков или обеспечения потока аудиопотоков. Поддерживаются только два типа ресурсов потока: прерывания и потоки, принадлежащие драйверу. Звуковые драйверы должны зарегистрировать ресурс после создания ресурса и отменить регистрацию ресурса перед его удалением.
Звуковые драйверы могут регистрировать ресурсы во время инициализации при загрузке драйвера или во время выполнения, например при перебалансации ресурсов ввода-вывода. Portcls использует глобальное состояние для отслеживания всех ресурсов потоковой передачи звука.
В некоторых случаях использования, таких как те, которые требуют очень низкой задержки звука, Windows пытается изолировать зарегистрированные ресурсы звукового драйвера от помех от других ос, приложений и аппаратных действий. ОС и аудио подсистемы делают это по мере необходимости, не взаимодействуя с аудиодрайвером, за исключением регистрации ресурсов аудиодрайвером.
Это требование для регистрации ресурсов потока подразумевает, что все драйверы, которые находятся в пути конвейера потоковой передачи, должны регистрировать свои ресурсы напрямую или косвенно в Portcls. Драйвер аудиопорта имеет следующие параметры:
- Драйвер минипорта аудио находится внизу стека драйверов (непосредственное взаимодействие с аппаратным обеспечением), в этом случае этот драйвер знает свои потоковые ресурсы и может осуществить их регистрацию в Portcls.
- Минипорт-драйвер аудио осуществляет потоковую передачу звука с помощью других драйверов, таких как драйверы аудиошин. Эти другие драйверы также используют ресурсы, которые должны быть зарегистрированы в Portcls. Эти стеки параллельных и шинных драйверов могут предоставлять общедоступный (или частный интерфейс, если один поставщик владеет всеми драйверами), который используют минипорт драйверы аудио для сбора этой информации.
- Драйвер аудиоминспорта выполняет потоковое воспроизведение звука вместе с другими драйверами, например, hdaudbus. Эти другие драйверы также используют ресурсы, которые должны быть зарегистрированы в Portcls. Эти драйверы параллелизма и шины могут связаться с Portcls и напрямую зарегистрировать свои ресурсы. Драйверы минипортов аудио должны сообщить Portcls, что они зависят от ресурсов других параллельных и шинных устройств (PDOs). Инфраструктура HD-аудио использует эту опцию, т. е. драйвер HD-аудиошины связывается с Portcls и автоматически выполняет следующие действия:
- регистрирует ресурсы драйвера шины и
- Уведомляет Portcls о том, что ресурсы потомков зависят от ресурсов родителей. В архитектуре HD-аудио минипорт-драйвер просто должен зарегистрировать свои ресурсы потоков, принадлежащие драйверу.
Примечания:
- Драйверам функций мини-порта HDAudio, перечисленным встроенным драйвером шины HDAudio hdaudbus.sys, не требуется регистрировать прерывания HDAudio, так как это уже выполнено hdaudbus.sys. Однако если драйвер минипорта создает собственные потоки, необходимо зарегистрировать их.
- Драйверы, которые подключаются только к Portcls для регистрации ресурсов потоковой передачи, должны обновить свои INFs, чтобы включить wdmaudio.inf и скопировать portcls.sys (и связанные файлы). Новый раздел INF-копирования определен в wdmaudio.inf только для копирования этих файлов.
- Звуковые драйверы, которые работают только в Windows 10 и более поздних версиях, могут жестко ссылаться на:
- Звуковые драйверы, которые должны работать на ос нижнего уровня, могут использовать следующий интерфейс (минипорт может вызывать QueryInterface для интерфейса IID_IPortClsStreamResourceManager и регистрировать свои ресурсы только в том случае, если PortCls поддерживает интерфейс).
- Эти DDIs используют это перечисление и структуру:
Наконец, драйверы, которые включают PortCls с единственной целью регистрации ресурсов, должны добавить в раздел DDInstall следующие две строки. Драйверы аудио минипортов не нуждаются в этом, так как у них уже есть Include и Needs в wdmaudio.inf.
[<install-section-name>]
Include=wdmaudio.inf
Needs=WDMPORTCLS.CopyFilesOnly
Приведенные выше строки обеспечивают установку PortCls и его зависимых файлов.
Средства измерения
Чтобы измерить время задержки цикла, пользователь может использовать инструменты, которые проигрывают импульсы через динамики и улавливают их микрофоном. Они измеряют задержку указанного пути.
- Приложение вызывает API отрисовки (AudioGraph или WASAPI), чтобы воспроизвести импульс
- Звук воспроизводится через динамики
- Звук записывается с микрофона
- Пульс обнаруживается API захвата (AudioGraph или WASAPI). Для измерения задержки прохождения для разных размеров буферов требуется установка драйвера, поддерживающего небольшие буферы. Драйвер HDAudio для папки "Входящие" обновлен для поддержки размеров буфера между 128 примерами (2.66ms@48kHz) и 480 примерами (10ms@48kHz). Ниже показано, как установить драйвер HDAudio для папки "Входящие" (который входит во все номера SKU Windows 10 и более поздних версий):
- Запустите диспетчер устройств.
- В разделе Звуковые видео и игровые контроллерыдважды щелкните устройство, соответствующее внутренним динамикам.
- В следующем окне перейдите на вкладку драйвера
. - Выберите обновить драйвер —>Просмотр программного обеспечения драйверов на моем компьютере —>Дайте мне выбрать из списка драйверов устройств на этом компьютере —>выберите устройство High Definition Audio и нажмите Далее.
- Если появится окно с заголовком "Предупреждение об обновлении драйвера", выберите Да.
- Выберите закрыть.
- Если вам будет предложено перезагрузить систему, выберите Да для перезагрузки.
- После перезагрузки система будет использовать драйвер Microsoft HDAudio в папке "Входящие", а не сторонний драйвер кодека. Помните, какой драйвер вы использовали раньше, чтобы вы могли вернуться к тому драйверу, если вы хотите использовать оптимальные параметры для аудиокодека.
Различия в задержке между WASAPI и AudioGraph обусловлены следующими причинами:
- AudioGraph добавляет один буфер задержки в стороне захвата, чтобы синхронизировать отрисовку и запись, которая не предоставляется WASAPI. Это дополнение упрощает код для приложений, написанных с помощью AudioGraph.
- Существует еще один буфер задержки на стороне отрисовки AudioGraph, когда система использует больше 6 мс буферов.
- AudioGraph не имеет возможности отключить звуковые эффекты записи.
Образцы
Вопросы и ответы
Было бы лучше, если все приложения используют новые API для низкой задержки? Не гарантирует ли низкая задержка лучшего взаимодействия с пользователем?
Необязательно. Низкая задержка имеет свои компромиссы:
- Низкая задержка означает более высокое потребление энергии. Если система использует 10-мс буферов, это означает, что ЦП будет проснуться каждые 10 мс, заполнить буфер данных и перейти в спящий режим. Однако если система использует 1-мс буферов, это означает, что ЦП будет проснуться каждые 1 мс. Во втором сценарии это означает, что ЦП будет проснуться чаще, а потребление энергии увеличится. Это уменьшит время работы батареи.
- Большинство приложений полагаются на звуковые эффекты, чтобы обеспечить лучший пользовательский интерфейс. Например, проигрыватели мультимедиа хотят предоставить звук с высоким уровнем точности. Приложения связи хотят минимального эхо и шума. Добавление этих типов звуковых эффектов в поток увеличивает задержку. Эти приложения более заинтересованы в качестве звука, чем в задержке звука.
В итоге каждый тип приложения имеет разные потребности в отношении задержки звука. Если приложению не требуется низкая задержка, он не должен использовать новые API для низкой задержки.
Будут ли все системы, которые обновляются до Windows 10 и более поздних версий, автоматически обновляются для поддержки небольших буферов? Будут ли все системы поддерживать одинаковый минимальный размер буфера?
Нет, чтобы система поддерживала небольшие буферы, она должна иметь обновленные драйверы. Решение о том, какие системы будут обновлены с целью поддержки небольших буферов, принимается изготовителями оборудования. Кроме того, более новые системы, скорее всего, поддерживают меньшие буферы, чем старые системы. Задержка в новых системах, скорее всего, будет ниже старых систем.
Если драйвер поддерживает небольшие размеры буферов, все приложения в Windows 10 и более поздних версиях автоматически используют небольшие буферы для отрисовки и записи звука?
Нет, по умолчанию все приложения в Windows 10 и более поздних версиях будут использовать 10-мс буферов для отрисовки и записи звука. Если приложению необходимо использовать небольшие буферы, для этого необходимо использовать новые параметры AudioGraph или интерфейс WASAPI IAudioClient3. Тем не менее, если одно приложение запрашивает использование небольших буферов, звуковой модуль начнет передавать звук с использованием определенного размера буфера. В этом случае все приложения, использующие одну и ту же конечную точку и режим, автоматически переключаются на этот небольшой размер буфера. Когда приложение с низкой задержкой завершает работу, аудиосистема снова переключится на 10-мс буферы.