Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Klient volá metody v rozhraní IAudioCaptureClient pro čtení zachycených dat z vyrovnávací paměti koncového bodu. Klient sdílí vyrovnávací paměť koncového bodu se zvukovým modulem v režimu sdílení a se zvukovým zařízením v exkluzivním režimu. Aby klient požádal o vyrovnávací paměť koncového bodu určité velikosti, volá metodu IAudioClient::Initialize. Pokud chce klient zjistit velikost přidělené vyrovnávací paměti, která se může lišit od požadované velikosti, volá metodu IAudioClient::GetBufferSize.
Pokud chcete přesunout datový proud zachycených dat přes vyrovnávací paměť koncového bodu, klient střídavě volá metodu IAudioCaptureClient::GetBuffer a metodu IAudioCaptureClient::ReleaseBuffer. Klient přistupuje k datům v vyrovnávací paměti koncového bodu jako řada datových paketů. Volání GetBuffer načte další paket zachycených dat z vyrovnávací paměti. Po načtení dat z paketu klient volá ReleaseBuffer, aby uvolnil paket a zpřístupnil ho pro další zachycená data.
Velikost paketu se může lišit od jednoho GetBuffer volání k dalšímu. Před voláním GetBuffermá klient možnost nejprve zavolat metodu IAudioCaptureClient::GetNextPacketSize ke zjištění velikosti dalšího paketu předem. Kromě toho může klient volat metodu IAudioClient::GetCurrentPadding, aby získal celkové množství zachycených dat, která jsou k dispozici ve vyrovnávací paměti. V jakémkoli okamžiku je velikost paketu menší nebo rovna celkovému množství zachycených dat ve vyrovnávací paměti.
Během každého průchodu zpracování má klient možnost zpracovávat zachycená data jedním z následujících způsobů:
- Klient střídavě volá GetBuffer a ReleaseBuffer, čte jeden paket při každé dvojici volání, dokud GetBuffer nevrátí AUDCNT_S_BUFFEREMPTY, což znamená, že vyrovnávací paměť je vyčerpaná.
- Klient volá GetNextPacketSize před každou dvojicí volání GetBuffer a ReleaseBuffer, dokud GetNextPacketSize hlásí velikost paketu 0, což znamená, že vyrovnávací paměť je prázdná.
Dvě techniky poskytují ekvivalentní výsledky.
Následující příklad kódu ukazuje, jak nahrát zvukový stream z výchozího záznamového zařízení:
//-----------------------------------------------------------
// Record an audio stream from the default audio capture
// device. The RecordAudioStream function allocates a shared
// buffer big enough to hold one second of PCM audio data.
// The function uses this buffer to stream data from the
// capture device. The main loop runs every 1/2 second.
//-----------------------------------------------------------
// REFERENCE_TIME time units per second and per millisecond
#define REFTIMES_PER_SEC 10000000
#define REFTIMES_PER_MILLISEC 10000
#define EXIT_ON_ERROR(hres) \
if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk) \
if ((punk) != NULL) \
{ (punk)->Release(); (punk) = NULL; }
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
HRESULT RecordAudioStream(MyAudioSink *pMySink)
{
HRESULT hr;
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
REFERENCE_TIME hnsActualDuration;
UINT32 bufferFrameCount;
UINT32 numFramesAvailable;
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;
IAudioClient *pAudioClient = NULL;
IAudioCaptureClient *pCaptureClient = NULL;
WAVEFORMATEX *pwfx = NULL;
UINT32 packetLength = 0;
BOOL bDone = FALSE;
BYTE *pData;
DWORD flags;
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
EXIT_ON_ERROR(hr)
hr = pEnumerator->GetDefaultAudioEndpoint(
eCapture, eConsole, &pDevice);
EXIT_ON_ERROR(hr)
hr = pDevice->Activate(
IID_IAudioClient, CLSCTX_ALL,
NULL, (void**)&pAudioClient);
EXIT_ON_ERROR(hr)
hr = pAudioClient->GetMixFormat(&pwfx);
EXIT_ON_ERROR(hr)
hr = pAudioClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
0,
hnsRequestedDuration,
0,
pwfx,
NULL);
EXIT_ON_ERROR(hr)
// Get the size of the allocated buffer.
hr = pAudioClient->GetBufferSize(&bufferFrameCount);
EXIT_ON_ERROR(hr)
hr = pAudioClient->GetService(
IID_IAudioCaptureClient,
(void**)&pCaptureClient);
EXIT_ON_ERROR(hr)
// Notify the audio sink which format to use.
hr = pMySink->SetFormat(pwfx);
EXIT_ON_ERROR(hr)
// Calculate the actual duration of the allocated buffer.
hnsActualDuration = (double)REFTIMES_PER_SEC *
bufferFrameCount / pwfx->nSamplesPerSec;
hr = pAudioClient->Start(); // Start recording.
EXIT_ON_ERROR(hr)
// Each loop fills about half of the shared buffer.
while (bDone == FALSE)
{
// Sleep for half the buffer duration.
Sleep(hnsActualDuration/REFTIMES_PER_MILLISEC/2);
hr = pCaptureClient->GetNextPacketSize(&packetLength);
EXIT_ON_ERROR(hr)
while (packetLength != 0)
{
// Get the available data in the shared buffer.
hr = pCaptureClient->GetBuffer(
&pData,
&numFramesAvailable,
&flags, NULL, NULL);
EXIT_ON_ERROR(hr)
if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
{
pData = NULL; // Tell CopyData to write silence.
}
// Copy the available capture data to the audio sink.
hr = pMySink->CopyData(
pData, numFramesAvailable, &bDone);
EXIT_ON_ERROR(hr)
hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);
EXIT_ON_ERROR(hr)
hr = pCaptureClient->GetNextPacketSize(&packetLength);
EXIT_ON_ERROR(hr)
}
}
hr = pAudioClient->Stop(); // Stop recording.
EXIT_ON_ERROR(hr)
Exit:
CoTaskMemFree(pwfx);
SAFE_RELEASE(pEnumerator)
SAFE_RELEASE(pDevice)
SAFE_RELEASE(pAudioClient)
SAFE_RELEASE(pCaptureClient)
return hr;
}
V předchozím příkladu funkce RecordAudioStream přebírá jeden parametr, pMySink, což je ukazatel na objekt, který patří do třídy definované klientem, MyAudioSink, se dvěma funkcemi, CopyData a SetFormat. Ukázkový kód neobsahuje implementaci MyAudioSink, protože:
- Žádný ze členů třídy nekomunikuje přímo s žádnou metodou v rozhraních v WASAPI.
- Třídu je možné implementovat různými způsoby v závislosti na požadavcích klienta. (Může například zapisovat data zachytávání do souboru WAV.)
Informace o provozu těchto dvou metod jsou však užitečné pro pochopení příkladu.
Funkce CopyData zkopíruje z určeného umístění v vyrovnávací paměti daný počet zvukových snímků. Funkce RecordAudioStream používá funkci CopyData ke čtení a ukládání zvukových dat ze sdílené vyrovnávací paměti. Funkce SetFormat určuje formát funkce CopyData, který se má použít pro data.
Pokud objekt MyAudioSink vyžaduje další data, funkce CopyData vypíše hodnotu FALSE prostřednictvím třetího parametru, který v předchozím příkladu kódu je ukazatel na proměnnou bDone. Když objekt MyAudioSink má všechna data, která vyžaduje, funkce CopyData nastaví bDone na TRUE, což způsobí, že program ukončí smyčku ve funkci RecordAudioStream.
Funkce RecordAudioStream přidělí sdílenou vyrovnávací paměť, která má dobu trvání jedné sekundy. (Přidělená vyrovnávací paměť může mít něco delší dobu trvání.) Ve hlavní smyčce volání funkce Windows Sleep způsobí, že program počká polovinu sekundy. Na začátku každého volání Sleep je sdílená vyrovnávací paměť prázdná nebo téměř prázdná. V době, kdy se volání Sleep vrátí, je sdílená vyrovnávací paměť přibližně z poloviny naplněná zachycenými daty.
Po volání metody IAudioClient::Initialize zůstane stream otevřený, dokud klient neuvolní všechny své odkazy na rozhraní IAudioClient a na všechny odkazy na rozhraní služeb, které klient získal prostřednictvím metody IAudioClient::GetService. Volání Release uzavírá datový proud.
Související témata