Dela via


Ljud med låg svarstid

I den här artikeln beskrivs ändringar av ljudfördröjning i Windows 10. Den omfattar API-alternativ för programutvecklare och ändringar i drivrutiner som kan göras för att stödja ljud med låg svarstid. Svarstid för ljud är fördröjningen mellan den tidpunkt då ljudet skapas och när det hörs. Det är viktigt med korta svarstider för flera viktiga scenarier, till exempel:

  • Pro-ljud
  • Skapa musik
  • Kommunikation
  • Virtuell verklighet
  • Spel

Syftet med det här dokumentet är att:

  1. Beskriv källorna till ljudfördröjning i Windows.
  2. Förklara de ändringar som minskar ljudfördröjningen i Windows 10-ljudstacken.
  3. Ange en referens för hur programutvecklare och maskinvarutillverkare kan dra nytta av den nya infrastrukturen för att utveckla program och drivrutiner med låg svarstid för ljud.

Den här artikeln beskriver:

  1. API:et AudioGraph för interaktiva scenarier och scenarier för medieskapande.
  2. Ändringar i WASAPI för att stödja låg svarstid.
  3. Förbättringar i drivrutins-DDI:er.

Terminologi

Termin Beskrivning
Återgivningsfördröjning Fördröjning mellan den tid då ett program skickar en buffert med ljuddata till renderings-API:erna tills det hörs från högtalarna.
Svarstid för avbildning Fördröjning mellan den tid då ett ljud hämtas från mikrofonen tills det skickas till de avbildnings-API:er som används av programmet.
Latens för tur och retur Fördröjning mellan den tid då ett ljud fångas från mikrofonen, bearbetas av programmet och skickas av programmet för återgivning till högtalarna. Det är ungefär lika med återgivningssvarstid + svarstid för avbildning.
Fördröjning från tryck till app Fördröjning mellan den tid då en användare trycker på skärmen tills signalen skickas till programmet.
Svarstid från touch till ljud Fördröjning mellan den tid då en användare trycker på skärmen, händelsen går till programmet och ett ljud hörs via högtalarna. Det motsvarar renderfördröjning + fördröjning från beröring till app.

Windows-ljudstacken

Följande diagram visar en förenklad version av Windows-ljudstacken.

Diagram som visar ljudstacken med låg latens med appar, drivrutin för ljudmotor och maskinvara.

Här är en sammanfattning av latensen i renderingsvägen: ljudbehandlingsobjekt.

  1. Programmet skriver data till en buffert

  2. Ljudmotorn läser data från bufferten och bearbetar dem. Den läser också in ljudeffekter i form av ljudbearbetningsobjekt (API:er). Mer information om API:er finns i Windows-ljudbearbetningsobjekt.

  3. Svarstiden för API:erna varierar beroende på signalbearbetningen i API:erna.

  4. Innan Windows 10 var svarstiden för ljudmotorn lika med ~12 ms för program som använder flyttalsdata och ~6 ms för program som använder heltalsdata

  5. I Windows 10 och senare har svarstiden minskats till 1,3 ms för alla program

  6. Ljudmotorn skriver bearbetade data till en buffert.

  7. Före Windows 10 var bufferten alltid inställd på ~10 ms.

  8. Från och med Windows 10 definieras buffertstorleken av ljuddrivrutinen (mer information om bufferten beskrivs senare i den här artikeln).

  9. Ljuddrivrutinen läser data från bufferten och skriver dem till maskinvaran.

  10. Maskinvaran kan också bearbeta data igen i form av fler ljudeffekter.

  11. Användaren hör ljud från högtalaren.

Här är en sammanfattning av latensen i inspelningsvägen:

  1. Ljud hämtas från mikrofonen.

  2. Maskinvaran kan bearbeta data. Om du till exempel vill lägga till ljudeffekter.

  3. Drivrutinen läser data från maskinvaran och skriver data till en buffert.

  4. Före Windows 10 var den här bufferten alltid inställd på 10 ms.

  5. Från och med Windows 10 definieras buffertstorleken av ljuddrivrutinen (mer information nedan).

  6. Ljudmotorn läser data från bufferten och bearbetar dem. Den läser också in ljudeffekter i form av ljudbearbetningsobjekt (API:er).

  7. Svarstiden för API:erna varierar beroende på signalbearbetningen i API:erna.

  8. Innan Windows 10 var svarstiden för ljudmotorn lika med ~6 ms för program som använder flyttalsdata och ~0ms för program som använder heltalsdata.

  9. I Windows 10 och senare har svarstiden minskats till ~0 ms för alla program.

  10. Applikationen signaleras att data är tillgängliga för läsning så snart ljudmotorn är klar med sin bearbetning. Ljudstacken ger också möjlighet till exklusivt läge. I så fall kringgår data ljudmotorn och går direkt från programmet till bufferten där drivrutinen läser den från. Men om ett program öppnar en slutpunkt i exklusivt läge finns det inget annat program som kan använda slutpunkten för att återge eller avbilda ljud.

Ett annat populärt alternativ för program som behöver låg svarstid är att använda ASIO-modellen (Audio Stream Input/Output), som använder exklusivt läge. När en användare har installerat en ASIO-drivrutin från tredje part kan program skicka data direkt från programmet till ASIO-drivrutinen. Programmet måste dock skrivas på ett sådant sätt att det talar direkt till ASIO-drivrutinen.

Båda alternativen (exklusivt läge och ASIO) har sina egna begränsningar. De ger låg svarstid, men de har sina egna begränsningar (av vilka några beskrevs ovan). Därför har ljudmotorn ändrats för att sänka svarstiden, samtidigt som flexibiliteten bibehålls.

Förbättringar av ljudstacken

Windows 10 och senare har förbättrats på tre områden för att minska svarstiden:

  1. Alla program som använder ljud ser en minskning på 4,5–16 ms av svarstiden tur och retur (som beskrivs i avsnittet ovan) utan några kodändringar eller drivrutinsuppdateringar jämfört med Windows 8.1.
    1. Program som använder flyttalsdata har 16 ms kortare svarstid.
    2. Program som använder heltalsdata har 4,5 ms lägre svarstid.
  2. System med uppdaterade drivrutiner ger ännu lägre svarstid för tur och retur:
    1. Drivrutiner kan använda DDI:er med låg latens för att rapportera de storlekar som stöds för bufferten som används för att överföra data mellan Windows och maskinvaran. Dataöverföringar behöver inte alltid använda buffertar på 10 ms, som de gjorde i tidigare Windows-versioner. I stället kan drivrutinen ange om den kan använda små buffertar, till exempel 5 ms, 3 ms, 1 ms osv.
    2. Program som kräver låg svarstid kan använda ljud-API:er med låg latens (AudioGraph eller WASAPI) för att fråga efter de buffertstorlekar som stöds av drivrutinen och välja den som ska användas för dataöverföringen till/från maskinvaran.
  3. När ett program använder buffertstorlekar under ett visst tröskelvärde för att återge och avbilda ljud, går Windows in i ett särskilt läge, där det hanterar sina resurser på ett sätt som undviker störningar mellan ljudströmningen och andra undersystem. Detta minskar avbrotten i körningen av ljudundersystemet och minimerar sannolikheten för ljudfel. När programmet slutar strömma återgår Windows till sitt normala körningsläge. Ljudundersystemet består av följande resurser:
    1. Ljudmotortråden som bearbetar ljud med låg latens.
    2. Alla trådar och avbrott som har registrerats av drivrutinen (med hjälp av DDI:er med låg svarstid som beskrivs i avsnittet om registrering av drivrutinsresurser).
    3. Vissa eller alla ljudtrådar från program som begär små buffertar och från alla program som delar samma ljudenhetsdiagram (till exempel samma signalbehandlingsläge) med alla program som begärde små buffertar:
  4. AudioGraph-återanrop på strömningsvägen.
  5. Om programmet använder WASAPI är det bara de arbetsobjekt som skickades till Real-Time Work Queue API eller MFCreateMFByteStreamOnStreamEx och som markerades som "Audio" eller "ProAudio".

API-förbättringar

Följande två Windows 10-API:er ger funktioner med låg svarstid:

Så här avgör du vilka av de två API:erna som ska användas:

  • Favor AudioGraph, där det är möjligt för ny programutveckling.
  • Använd endast WASAPI om:
    • Du behöver mer kontroll än den som tillhandahålls av AudioGraph.
    • Du behöver kortare svarstid än den som tillhandahålls av AudioGraph.

I avsnittet mätningsverktyg i den här artikeln visas specifika mätningar från ett Haswell-system som använder förinladdade HDAudio-drivrutiner.

I följande avsnitt förklaras funktionerna med låg svarstid i varje API. Som det noterades i föregående avsnitt, för att systemet ska uppnå minsta svarstid, måste det ha uppdaterade drivrutiner som stöder små buffertstorlekar.

AudioGraph

AudioGraph är ett Universal Windows Platform-API i Windows 10 och senare som syftar till att enkelt förverkliga scenarier för interaktiv musik och musikskapande. AudioGraph finns på flera programmeringsspråk (C++, C#, JavaScript) och har en enkel och funktionsrik programmeringsmodell.

För att kunna rikta in sig på scenarier med låg latens tillhandahåller AudioGraph egenskapen AudioGraphSettings::QuantumSizeSelectionMode. Den här egenskapen kan vara något av de värden som visas i tabellen nedan:

Värde Beskrivning
SystemDefault Anger bufferten till standardbuffertstorleken (~10 ms)
Lägsta latens Anger bufferten till det minsta värde som stöds av drivrutinen
Närmaste till önskat Anger att buffertstorleken antingen ska vara lika med värdet som definieras av egenskapen DesiredSamplesPerQuantum eller till ett värde som ligger så nära DesiredSamplesPerQuantum som stöds av drivrutinen.

Exemplet AudioCreation visar hur du använder AudioGraph för låg svarstid. Följande kodfragment visar hur du anger minsta buffertstorlek:

AudioGraphSettings settings = new AudioGraphSettings(AudioRenderCategory.Media);
settings.QuantumSizeSelectionMode = QuantumSizeSelectionMode.LowestLatency;
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);

API för Windows-ljudsession (WASAPI)

Från och med Windows 10 har WASAPI förbättrats till:

  • Tillåt att ett program identifierar intervallet med buffertstorlekar (dvs. periodicitetsvärden) som stöds av ljuddrivrutinen för en viss ljudenhet. Detta gör det möjligt för ett program att välja mellan standardbuffertstorleken (10 ms) eller en liten buffert (mindre än 10 ms) när du öppnar en ström i delat läge. Om ett program inte anger någon buffertstorlek använder det standardbuffertstorleken.
  • Tillåt att ett program identifierar ljudmotorns aktuella format och periodicitet. Detta gör det möjligt för program att anpassa sig efter de aktuella inställningarna för ljudmotorn.
  • Tillåt att en app anger att den vill återge/avbilda i det format som den anger utan någon omsampling av ljudmotorn

Ovanstående funktioner kommer att vara tillgängliga på alla Windows-enheter. Vissa enheter med tillräckligt med resurser och uppdaterade drivrutiner ger dock en bättre användarupplevelse än andra.

Ovanstående funktioner tillhandahålls av ett gränssnitt som kallas IAudioClient3, som härleds från IAudioClient2.

IAudioClient3 definierar följande tre metoder:

Metod Beskrivning
GetCurrentSharedModeEnginePeriod Returnerar ljudmotorns aktuella format och periodicitet
GetSharedModeEnginePeriod Returnerar intervallet med periodiciteter som stöds av motorn för det angivna strömformatet
InitieraSharedAudioStream Initierar en delad ström med angiven periodicitet

Exemplet WASAPIAudio visar hur du använder IAudioClient3 för låg svarstid.

Följande kodfragment visar hur en app för att skapa musik kan fungera i den lägsta svarstidsinställningen som stöds av systemet.

// 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)) {
       ...
}

Dessutom rekommenderar Microsoft att program som använder WASAPI även använder Real-Time Work Queue API eller MFCreateMFByteStreamOnStreamEx för att skapa arbetsobjekt och tagga dem som Ljud eller Pro Audio, i stället för att använda sina egna trådar. På så sätt kan Windows hantera dem på ett sätt som undviker störningar i undersystem som inte är ljud. Däremot hanteras alla AudioGraph-trådar automatiskt korrekt av Windows. Följande kodfragment från WASAPIAudio-exemplet visar hur du använder API:erna för MF-arbetskö.

// 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 );

Alternativt visar följande kodfragment hur du använder RT Work Queue-API:erna.

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

Slutligen måste programutvecklare som använder WASAPI tagga sina strömmar med ljudkategorin och om de ska använda raw-signalbearbetningsläget baserat på funktionerna i varje ström. Microsoft rekommenderar att alla ljudströmmar inte använder det råa signalbearbetningsläget, såvida inte konsekvenserna förstås. Raw-läget kringgår all signalbearbetning som har valts av OEM-tillverkaren, så:

  • Återgivningssignalen för en viss slutpunkt kan vara suboptimal.
  • Avbildningssignalen kan komma i ett format som programmet inte kan förstå.
  • Svarstiden kan förbättras.

Förbättringar av drivrutiner

För att ljuddrivrutiner ska ha stöd för låg svarstid tillhandahåller Windows 10 och senare följande funktioner:

  1. [Obligatoriskt] Deklarera den minsta buffertstorlek som stöds i varje läge.
  2. [Valfritt, men rekommenderas] Förbättra samordningen för dataflödet mellan drivrutinen och Windows.
  3. [Valfritt, men rekommenderas] Registrera drivrutinsresurserna (avbrott, trådar) så att de kan skyddas av Windows i scenarier med låg svarstid. HDAudio miniport-funktionsdrivrutiner som listas av den inbyggda HDAudio-bussdrivrutinen hdaudbus.sys behöver inte registrera HDAudio-avbrotten, eftersom detta redan görs av hdaudbus.sys. Men om miniportdrivrutinen skapar sina egna trådar måste den registrera dem.

I följande tre avsnitt förklaras varje funktion mer ingående.

Deklarera minsta buffertstorlek

En drivrutin fungerar under olika begränsningar när du flyttar ljuddata mellan Windows, drivrutinen och maskinvaran. Dessa begränsningar kan bero på den fysiska maskinvarutransport som flyttar data mellan minne och maskinvara, eller på grund av signalbearbetningsmodulerna inom maskinvaran eller tillhörande DSP.

Från och med Windows 10, version 1607, kan drivrutinen uttrycka sina buffertstorleksmöjligheter med hjälp av enhetsegenskapen DEVPKEY_KsAudio_PacketSize_Constraints2. Med den här egenskapen kan användaren definiera den absoluta minsta buffertstorlek som stöds av drivrutinen och specifika begränsningar för buffertstorlek för varje signalbearbetningsläge. De lägesspecifika begränsningarna måste vara högre än drivrutinernas minsta buffertstorlek, annars ignoreras de av ljudstacken.

Följande kodfragment visar till exempel hur en drivrutin kan deklarera att den absolut lägsta buffertstorleken som stöds är 2 ms, men standardläget stöder 128 bildrutor, vilket motsvarar 3 ms om vi antar en exempelfrekvens på 48 kHz.

 
//
// 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
        },
    }
};

Mer detaljerad information om dessa strukturer finns i följande artiklar:

Dessutom visar sysvad-exempel hur du använder dessa egenskaper för att en drivrutin ska deklarera den minsta bufferten för varje läge.

Förbättra samordningen mellan drivrutin och operativsystem

Med de DDI:er som beskrivs i det här avsnittet kan drivrutinen:

  • Ange tydligt vilken halva (paket) av bufferten som är tillgänglig för Windows, i stället för operativsystemets gissning baserat på en codec-länkposition. Detta hjälper Windows att återställa från ljudfel snabbare.
  • Du kan också optimera eller förenkla dataöverföringarna in och ut ur WaveRT-bufferten. Mängden fördelar här beror på DMA-motorns design eller annan dataöverföringsmekanism mellan WaveRT-bufferten och (eventuellt DSP)-maskinvaran.
  • ** "Burst" fångar data snabbare än i realtid om drivrutinen har ackumulerat data internt. Detta är främst avsett för röstaktiveringsscenarier men kan även tillämpas under normal strömning.
  • Ange tidsstämpelinformation om dess aktuella strömposition i stället för Windows-gissningar, vilket potentiellt möjliggör korrekt positionsinformation.

Denna DDI är användbar i det fall där en DSP används. Men en standard HD Audio-drivrutin eller andra enkla cirkulära DMA-buffertdesigner kanske inte har någon större fördel i dessa DDI:er som anges här.

Flera av drivrutinsrutinerna returnerar tidsstämplar för Windows-prestandaräknare som återspeglar den tid då exempel samlas in eller presenteras av enheten.

På enheter som har komplexa DSP-pipelines och signalbearbetning kan det vara svårt att beräkna en korrekt tidsstämpel och bör göras eftertänksamt. Tidsstämplarna bör inte återspegla den tidpunkt då exemplen överfördes till eller från Windows till DSP.

För att beräkna prestandaräknarens värden kan drivrutinen och DSP använda några av följande metoder.

  • I DSP spårar du tidsstämplar för exempel med hjälp av en intern DSP-väggklocka.
  • Mellan drivrutinen och DSP beräknar du en korrelation mellan Prestandaräknaren för Windows och DSP-väggklockan. Procedurer för detta kan variera från enkla (men mindre exakta) till ganska komplexa eller nya (men mer exakta).
  • Räkna in eventuella konstanta fördröjningar på grund av signalbearbetningsalgoritmer eller pipeline- eller maskinvarutransporter, såvida inte dessa förseningar annars redovisas.

sysvad-exempel visar hur du använder ovanstående DDI:er.

Registrera förarresurser

För att säkerställa problemfri drift måste ljuddrivrutiner registrera sina strömmande resurser med Portcls. På så sätt kan Windows hantera resurser för att undvika störningar mellan ljudströmning och andra undersystem.

Stream-resurser är resurser som används av ljuddrivrutinen för att bearbeta ljudströmmar eller säkerställa ljuddataflöde. Endast två typer av strömresurser stöds: avbrott och drivrutinsägda trådar. Ljuddrivrutiner bör registrera en resurs när resursen har skapats och avregistrera resursen innan den tas bort.

Ljuddrivrutiner kan registrera resurser vid initieringstiden när drivrutinen läses in, eller vid körning, till exempel när det finns en ombalansering av I/O-resurser. Portcls använder ett globalt tillstånd för att hålla reda på alla ljudströmningsresurser.

I vissa användningsfall, till exempel sådana som kräver ljud med mycket låg svarstid, försöker Windows isolera ljuddrivrutinens registrerade resurser från interferens från annan os-, program- och maskinvaruaktivitet. Operativsystemet och ljudundersystemet gör detta efter behov utan att interagera med ljuddrivrutinen, med undantag för ljuddrivrutinens registrering av resurserna.

Kravet på att registrera strömresurser innebär att alla drivrutiner som är en del av strömmande pipeline måste registrera sina resurser direkt eller indirekt genom Portcls. Ljudminiportdrivrutinen har följande alternativ:

  • Ljud-miniportdrivrutinen är den nedre drivrutinen i sin stack (genom att koppla direkt till h/w), i det här fallet, känner drivrutinen till sina strömresurser och den kan registrera dem med Portcls.
  • Miniportdrivrutinen för ljud strömmar ljud med hjälp av andra drivrutiner (till exempel ljudbussdrivrutiner). Dessa andra drivrutiner använder också resurser som måste registreras med Portcls. Dessa parallella drivrutinsstackar kan tillhandahålla ett offentligt (eller privat) gränssnitt, om en enskild leverantör äger alla drivrutiner, som ljudminiportdrivrutiner använder för att samla in den här informationen.
  • Ljudminiportdrivrutinen strömmar ljud med hjälp av andra drivrutiner, exempelvis hdaudbus. Dessa andra drivrutiner använder också resurser som måste registreras med Portcls. Dessa parallella/bussdrivrutiner kan länka till Portcls och registrera sina resurser direkt. Ljudminiportdrivrutinerna måste låta Portcls veta att de är beroende av resurserna för dessa andra parallella/bussenheter (PDO:er). HD-ljudinfrastrukturen använder det här alternativet, det vill: HD-ljudbussdrivrutinen länkar till Portcls och utför automatiskt följande steg:
    • registrerar busschaufförens resurser och
    • meddelar Portcls att de underordnade resurserna är beroende av den överordnade resursen. I HD-ljudarkitekturen behöver ljudminiportdrivrutinen bara registrera sina egna drivrutinsägda trådresurser.

Anteckningar:

  • HDAudio miniport-funktiondrivrutiner som enumereras av den inbyggda HDAudio-bussdrivrutinen hdaudbus.sys behöver inte registrera HDAudio-interruptar, eftersom detta redan görs av hdaudbus.sys. Men om miniportdrivrutinen skapar sina egna trådar måste den registrera dem.
  • Drivrutiner som endast länkar till Portcls för att registrera strömmande resurser måste uppdatera sina INF:er så att de inkluderar wdmaudio.inf och kopierar portcls.sys (och beroende filer). Ett nytt INF-kopieringsavsnitt definieras i wdmaudio.inf för att endast kopiera dessa filer.
  • Ljuddrivrutiner som bara körs i Windows 10 och senare kan hårdlänka till:
  • Ljuddrivrutiner som måste köras på ett operativsystem på nednivå kan använda följande gränssnitt (miniporten kan anropa QueryInterface för IID_IPortClsStreamResourceManager-gränssnittet och registrera dess resurser endast när PortCls stöder gränssnittet).
  • Dessa DDI:er använder den här uppräkningen och strukturen:

Slutligen måste drivrutiner som länkar till PortCls enbart för att registrera resurser lägga till följande två rader i inf-avsnittet DDInstall. Ljudminiportdrivrutiner behöver inte detta eftersom de redan har include/needs i wdmaudio.inf.

[<install-section-name>]
Include=wdmaudio.inf
Needs=WDMPORTCLS.CopyFilesOnly

Raderna ovan ser till att PortCls och dess beroende filer är installerade.

Mätverktyg

För att mäta svarstiden tur och retur kan användaren använda verktyg som spelar pulser via högtalarna och fångar dem via mikrofonen. De mäter fördröjningen på följande väg:

  1. Programmet anropar renderings-API:et (AudioGraph eller WASAPI) för att spela upp pulsen
  2. Ljudet spelas upp via högtalarna
  3. Ljudet hämtas från mikrofonen
  4. Pulsen identifieras av avbildnings-API:et (AudioGraph eller WASAPI) För att mäta svarstiden för tur och retur för olika buffertstorlekar måste användarna installera en drivrutin som stöder små buffertar. Inkorgens HDAudio-drivrutin har uppdaterats för att stödja buffertstorlekar mellan 128 exempel (2.66ms@48kHz) och 480 exempel (10ms@48kHz). Följande steg visar hur du installerar inkorgens HDAudio-drivrutin (som ingår i alla Windows 10- och senare SKU:er):
  • Starta Enhetshanteraren.
  • Under Ljud video- och spelstyrenheterdubbelklickar du på enheten som motsvarar dina interna högtalare.
  • I nästa fönster går du till fliken Drivrutin.
  • Välj Uppdateringsdrivrutin –>Bläddra efter drivrutinsprogramvara –>Låt mig välja från en lista över enhetsdrivrutiner på den här datorn –>Välj hd-ljudenhet och välj Nästa.
  • Om ett fönster med namnet "Uppdateringsdrivrutinsvarning" visas väljer du Ja.
  • Välj stäng.
  • Om du uppmanas att starta om systemet väljer du Ja att starta om.
  • Efter omstarten kommer systemet att använda den inbyggda Microsoft HDAudio-drivrutinen och inte codec-drivrutinen från tredje part. Kom ihåg vilken drivrutin du använde tidigare så att du kan återgå till drivrutinen om du vill använda de optimala inställningarna för din ljudkod.

Graf som illustrerar skillnader i fördröjning mellan WASAPI och AudioGraph för olika buffertstorlekar.

Skillnaderna i svarstiden mellan WASAPI och AudioGraph beror på följande:

  • AudioGraph lägger till en buffert med svarstid på avbildningssidan för att synkronisera återgivning och avbildning, vilket inte tillhandahålls av WASAPI. Det här tillägget förenklar koden för program som skrivits med AudioGraph.
  • Det finns en annan buffert med svarstid i AudioGraphs återgivningssida när systemet använder större än 6 ms buffertar.
  • AudioGraph har inte möjligheten att inaktivera inspelningsljudeffekter.

Prover

FAQ

Vore det inte bättre om alla program använder de nya API:erna för låg svarstid? Garanterar inte låg svarstid alltid en bättre användarupplevelse?

Inte nödvändigtvis. Korta svarstider har sina kompromisser:

  • Låg svarstid innebär högre strömförbrukning. Om systemet använder buffertar på 10 ms innebär det att processorn vaknar var 10:e ms, fyller databufferten och försätts i viloläge. Men om systemet använder buffertar på 1 ms innebär det att processorn vaknar var 1 ms. I det andra scenariot innebär det att processorn vaknar oftare och att energiförbrukningen ökar. Detta minskar batteritiden.
  • De flesta program förlitar sig på ljudeffekter för att ge den bästa användarupplevelsen. Mediaspelare vill till exempel tillhandahålla ljud med hög återgivning. Kommunikationsprogram vill minimera eko och brus. Om du lägger till dessa typer av ljudeffekter i en ström ökar svarstiden. Dessa program är mer intresserade av ljudkvalitet än av ljudfördröjning.

Sammanfattningsvis har varje programtyp olika behov när det gäller svarstid för ljud. Om ett program inte behöver låg svarstid bör det inte använda de nya API:erna för låg svarstid.

Kommer alla system som uppdateras till Windows 10 och senare att uppdateras automatiskt för att stödja små buffertar? Har alla system samma minsta buffertstorlek?

Nej, för att ett system ska kunna stödja små buffertar måste det ha uppdaterade drivrutiner. Det är upp till OEM:erna att bestämma vilka system som ska uppdateras för att stödja små buffertar. Dessutom är nyare system mer benägna att stödja mindre buffertar än äldre system. Svarstiden i nya system kommer sannolikt att vara lägre än äldre system.

Om en drivrutin stöder små buffertstorlekar, kommer alla program i Windows 10 och senare automatiskt att använda små buffertar för att återge och avbilda ljud?

Nej, som standard använder alla program i Windows 10 och senare 10 ms buffertar för att återge och avbilda ljud. Om ett program behöver använda små buffertar måste det använda de nya AudioGraph-inställningarna eller WASAPI IAudioClient3-gränssnittet för att kunna göra det. Men om ett program begär användning av små buffertar börjar ljudmotorn överföra ljud med den specifika buffertstorleken. I så fall växlar alla program som använder samma slutpunkt och läge automatiskt till den lilla buffertstorleken. När programmet med låg svarstid avslutas växlar ljudmotorn till 10 ms buffertar igen.