Звук с низкой задержкой
В этой статье рассматриваются изменения задержки звука в Windows 10. В нем рассматриваются варианты API для разработчиков приложений и изменения в драйверах, которые могут быть внесены для поддержки звука с низкой задержкой. Задержка звука — это задержка между моментом создания звука и его услышанным звуком. Низкая задержка звука важна для нескольких ключевых сценариев, таких как:
- Pro audio
- Создание музыки
- Коммуникации
- Виртуальная реальность
- Игры
Цель этого документа:
- Описывать источники задержки звука в Windows.
- Объяснить изменения, которые сокращают задержку звука в Windows 10 аудио стеке.
- Предоставьте справочные сведения о том, как разработчики приложений и производители оборудования могут воспользоваться преимуществами новой инфраструктуры для разработки приложений и драйверов с низкой задержкой звука.
В этой статье рассматриваются следующие вопросы:
- Новый API AudioGraph для интерактивных сценариев и сценариев создания мультимедиа.
- Изменения в WASAPI для поддержки низкой задержки.
- Усовершенствования в DDIs драйвера.
Терминология
Термин | Описание |
---|---|
Задержка отрисовки | Задержка между временем отправки приложением буфера звуковых данных в API отрисовки до момента, когда они будут услышаны от динамиков. |
Задержка записи | Задержка между временем захвата звука с микрофона до момента его отправки в API захвата, используемые приложением. |
Задержка круглого пути | Задержка между временем, когда звук захватывается с микрофона, обрабатывается приложением и отправляется приложением для отрисовки в динамики. Задержка отрисовки и задержка записи примерно равна. |
Задержка сенсорного ввода в приложение | Задержка между временем, когда пользователь касается экрана, до момента отправки сигнала в приложение. |
Задержка сенсорного ввода и звука | Задержка между тем, когда пользователь касается экрана, событие переходит в приложение и звук будет слышен через динамики. Это равно задержке отрисовки + задержке сенсорного ввода в приложение. |
Звуковой стек Windows
На следующей схеме показана упрощенная версия звукового стека Windows.
Ниже приведена сводка по задержкам в пути отрисовки: объекты обработки звука
Приложение записывает данные в буфер.
Звуковой модуль считывает данные из буфера и обрабатывает их. Он также загружает звуковые эффекты в виде объектов аудиообработки (APOs). Дополнительные сведения о объектах API см. в разделе Объекты обработки звука Windows.
Задержка apos зависит от обработки сигнала в apos.
До Windows 10 задержка обработчика звука была равна ~12 мс для приложений, использующих данные с плавающей запятой, и ~6 мс для приложений, использующих целочисленные данные.
В Windows 10 и более поздних версиях задержка сократилась до 1,3 мс для всех приложений.
Подсистема аудиозаписи записывает обработанные данные в буфер.
До Windows 10 буфер всегда был установлен равным ~10 мс.
Начиная с Windows 10 размер буфера определяется звуковым драйвером (дополнительные сведения о буфере описаны далее в этой статье).
Звуковой драйвер считывает данные из буфера и записывает их в оборудование.
Оборудование также может повторно обрабатывать данные в виде дополнительных звуковых эффектов.
Пользователь слышит звук от говорящего.
Ниже приведена сводка задержки в пути захвата.
Звук захватывается с микрофона.
Оборудование может обрабатывать данные. Например, чтобы добавить звуковые эффекты.
Драйвер считывает данные с оборудования и записывает данные в буфер.
До Windows 10 для этого буфера всегда устанавливалось значение 10 мс.
Начиная с Windows 10 размер буфера определяется звуковым драйвером (дополнительные сведения см. ниже).
Звуковой модуль считывает данные из буфера и обрабатывает их. Он также загружает звуковые эффекты в виде объектов аудиообработки (APOs).
Задержка apos зависит от обработки сигнала в apos.
До 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 рабочей очереди в режиме реального времени или 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 . Это свойство может быть любым из значений, показанных в таблице ниже:
Значение | Описание |
---|---|
SystemDefault | Задает размер буфера по умолчанию (~10 мс) |
Наименьшая латентность | Задает для буфера минимальное значение, поддерживаемое драйвером. |
ClosestToDesired | Задает размер буфера, равный либо значению, определенному свойством 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 | Возвращает текущий формат и периодичность обработчика звука. |
GetSharedModeEnginePeriod | Возвращает диапазон периодичности, поддерживаемый подсистемой для указанного формата потока. |
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 рабочих очередей в режиме реального времени или MFCreateMFByteStreamOnStreamEx для создания рабочих элементов и добавления тегов к ним как Audio или Pro Audio вместо собственных потоков. Это позволит Windows управлять ими таким образом, чтобы избежать помех, не являющихся звуковыми подсистемами. В отличие от этого, Windows автоматически управляет всеми потоками AudioGraph. В следующем фрагменте кода из примера 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
Кроме того, в примере sysvad показано, как использовать эти свойства, чтобы драйвер объявлял минимальный буфер для каждого режима.
Улучшение координации между драйвером и ОС
DDIs, описанные в этом разделе, позволяют драйверу:
- Четко укажите, какая половина (пакет) буфера доступна Для Windows, а не угадывание ОС на основе позиции ссылки кодека. Это помогает Windows быстрее восстанавливаться после сбоев звука.
- При необходимости оптимизируйте или упростите передачу данных в буфер WaveRT и из него. Это преимущество зависит от структуры подсистемы DMA или другого механизма передачи данных между буфером WaveRT и оборудованием (возможно, DSP).
- "Ускорение" захватывает данные быстрее, чем в режиме реального времени, если драйвер имеет внутренние собранные данные. Это в первую очередь предназначено для сценариев голосовой активации, но может применяться и во время обычной потоковой передачи.
- Предоставьте сведения о текущей позиции потока, а не о том, что windows угадывает, что потенциально позволяет получить точные сведения о положении.
Этот DDI полезен в случае, когда используется DSP. Тем не менее, стандартный драйвер HD Audio или другие простые циклические буферы DMA могут не найти большого преимущества в этих новых DDIs, перечисленных здесь.
Некоторые подпрограммы драйвера возвращают метки времени счетчика производительности Windows, отражающие время сбора или представления примеров устройством.
На устройствах со сложными конвейерами DSP и обработкой сигналов вычисление точной метки времени может оказаться сложной задачей и должно выполняться вдумчиво. Метки времени не должны отражать время передачи примеров в Windows или в DSP.
Чтобы вычислить значения счетчиков производительности, драйвер и DSP могут использовать некоторые из следующих методов.
- В DSP отслеживайте примеры меток времени с помощью некоторых внутренних настенных часов DSP.
- Между драйвером и DSP вычислите корреляцию между счетчиком производительности Windows и настенными часами DSP. Процедуры для этого могут варьироваться от простых (но менее точных) до довольно сложных или новых (но более точных).
- Учитывайте постоянные задержки, вызванные алгоритмами обработки сигналов, конвейером или транспортировкой оборудования, если эти задержки не учитываются иным образом.
В примере sysvad показано, как использовать указанные выше DIS.
Регистрация ресурсов драйверов
Чтобы обеспечить бесперебойную работу, аудиодрайверы должны зарегистрировать свои ресурсы потоковой передачи в Portcls. Это позволяет Windows управлять ресурсами, чтобы избежать помех между потоковой передачей звука и другими подсистемами.
Потоковые ресурсы — это любые ресурсы, используемые аудиодрайвером для обработки аудиопотоков или обеспечения потока аудиоданных. Поддерживаются только два типа потоковых ресурсов: прерывания и потоки, принадлежащие драйверу. Аудиодрайверы должны зарегистрировать ресурс после создания ресурса и отменить регистрацию ресурса перед его удалением.
Аудиодрайверы могут регистрировать ресурсы во время инициализации, когда драйвер загружен, или во время выполнения, например при перебалансации ресурсов ввода-вывода. Portcls использует глобальное состояние для отслеживания всех ресурсов потоковой передачи звука.
В некоторых случаях использования, например для тех, для которых требуется очень низкая задержка звука, Windows пытается изолировать зарегистрированные ресурсы звукового драйвера от помех от других действий ОС, приложений и оборудования. Операционная система и звуковая подсистема выполняют это по мере необходимости, не взаимодействуя с аудиодрайвером, за исключением регистрации ресурсов аудиодрайвером.
Это требование для регистрации потоковых ресурсов подразумевает, что все драйверы, которые находятся в пути конвейера потоковой передачи, должны регистрировать свои ресурсы прямо или косвенно в Portcls. Драйвер аудио минипорта имеет следующие параметры:
- Драйвер аудио минипорта — это нижний драйвер стека (напрямую взаимодействующий с h/w). В этом случае драйвер знает свои ресурсы потока и может зарегистрировать их с помощью Portcls.
- Драйвер аудио минипорта выполняет потоковую передачу звука с помощью других драйверов (например, драйверов аудиошины). Эти другие драйверы также используют ресурсы, которые должны быть зарегистрированы в Portcls. Эти стеки параллельных или шинных драйверов могут предоставлять общедоступный (или частный интерфейс, если все драйверы принадлежат одному поставщику), который используется драйверами аудиовыводов минипорта для сбора этой информации.
- Аудиодрайвер минипорта выполняет потоковую передачу звука с помощью других драйверов (например, hdaudbus). Эти другие драйверы также используют ресурсы, которые должны быть зарегистрированы в Portcls. Эти параллельные драйверы и драйверы шины могут связываться с Portcls и напрямую регистрировать свои ресурсы. Аудиодрайверы минипорта должны сообщить Portcls, что они зависят от ресурсов этих других параллельных или шинных устройств (PDO). Инфраструктура hd audio использует этот параметр, то есть драйвер hd audio-bus связывается с Portcls и автоматически выполняет следующие действия:
- регистрирует ресурсы водителя автобуса, и
- Уведомляет Portcls о том, что ресурсы дочерних объектов зависят от родительских ресурсов. В архитектуре hd audio драйверу аудио минипорта достаточно зарегистрировать собственные потоковые ресурсы, принадлежащие драйверу.
Примечания.
- Драйверам функций мини-порта HDAudio, перечисленным драйвером автобуса HDAudio в папке "Входящие", hdaudbus.sys не нужно регистрировать прерывания HDAudio, так как это уже делается hdaudbus.sys. Однако если драйвер мини-порта создает собственные потоки, необходимо зарегистрировать их.
- Драйверы, которые связываются с portcls только для регистрации ресурсов потоковой передачи, должны обновить свои inFs, включив wdmaudio.inf и копировать portcls.sys (и зависимые файлы). Новый раздел inf copy определен в wdmaudio.inf для копирования только этих файлов.
- Аудиодрайверы, которые работают только в Windows 10 и более поздних версиях, могут жестко связываться с:
- Аудиодрайверы, которые должны работать в ОС нижнего уровня, могут использовать следующий интерфейс (минипорт может вызывать QueryInterface для интерфейса IID_IPortClsStreamResourceManager и регистрировать его ресурсы, только если PortCls поддерживает интерфейс).
- Эти DDIs используют следующее перечисление и структуру:
Наконец, драйверы, которые связывают portCls с единственной целью регистрации ресурсов, должны добавить следующие две строки в раздел DDInstall inf. Аудиодрайверам минипорта это не нужно, так как у них уже есть включение и потребности в 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 и более поздних версий).
- Запустите диспетчер устройств.
- В разделе Звуковые видео- и игровые контроллеры дважды щелкните устройство, соответствующее вашим внутренним динамикам.
- В следующем окне перейдите на вкладку Драйвер .
- Выберите Обновить драйвер ->Обзор моего компьютера для программного обеспечения драйверов ->Позвольте выбрать из списка драйверов на этом компьютере ->Выберите звуковое устройство высокой четкости и нажмите кнопку Далее.
- Если появится окно "Обновление предупреждения драйвера", выберите Да.
- Нажмите кнопку Закрыть.
- Если вам будет предложено перезагрузить систему, выберите Да для перезагрузки.
- После перезагрузки система будет использовать драйвер 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 мс.