Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Az ügyfél meghívja az IAudioCaptureClient felület metódusait, hogy beolvassa a rögzített adatokat egy végpontpufferből. Az ügyfél megosztott módban és kizárólagos módban osztja meg a végpontpuffert a hangmotorral és a hangeszközzel. Egy adott méretű végpontpuffer lekéréséhez az ügyfél meghívja a IAudioClient::Initialize metódust. A lefoglalt puffer méretének lekéréséhez, amely eltérhet a kért mérettől, az ügyfél meghívja a IAudioClient::GetBufferSize metódust.
A rögzített adatok adatfolyamának a végpontpufferen keresztül történő áthelyezéséhez az ügyfél felváltva meghívja a IAudioCaptureClient::GetBuffer metódust és az IAudioCaptureClient::ReleaseBuffer metódust. Az ügyfél adatcsomagok sorozataként fér hozzá a végpontpufferben lévő adatokhoz. A GetBuffer hívás lekéri a következő rögzített adatcsomagot a pufferből. Miután beolvasta az adatokat a csomagból, az ügyfél meghívja ReleaseBuffer, hogy engedje fel a csomagot, és tegye elérhetővé a rögzítettebb adatok számára.
A csomag mérete eltérhet az egyik GetBuffer hívástól a következőig. GetBufferhívása előtt az ügyfél meghívhatja a IAudioCaptureClient::GetNextPacketSize metódust a következő csomag méretének előzetes lekéréséhez. Emellett az ügyfél meghívhatja az IAudioClient::GetCurrentPadding metódust a pufferben elérhető rögzített adatok teljes mennyiségének lekéréséhez. A csomag mérete bármikor kisebb vagy egyenlő a pufferben rögzített adatok teljes mennyiségénél.
Minden feldolgozási folyamat során az ügyfélnek lehetősége van a rögzített adatok feldolgozására az alábbi módok egyikével:
- Az ügyfél felváltva hívja meg a GetBuffer és a ReleaseBufferfüggvényt, minden híváspárnál egy csomagot olvasva be, amíg a GetBuffer vissza nem adja az AUDCNT_S_BUFFEREMPTY értéket, jelezve, hogy a puffer kiürült.
- Az ügyfél minden egyes híváspár előtt hívja a GetNextPacketSize, majd ugyanazon párba tartozóan a GetBuffer és ReleaseBuffer függvényeket, amíg a GetNextPacketSize függvény 0 csomagméretet nem jelez, ami azt jelzi, hogy a puffer üres.
A két technika egyenértékű eredményeket ad.
Az alábbi példakód bemutatja, hogyan rögzíthet hangstreamet az alapértelmezett rögzítési eszközről:
//-----------------------------------------------------------
// 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;
}
Az előző példában a RecordAudioStream függvény egyetlen paramétert vesz fel, pMySink, amely egy ügyfél által definiált osztályhoz, a MyAudioSinkhez tartozó objektumra mutató mutató, két függvénnyel, a CopyData és a SetFormat függvénnyel. A példakód nem tartalmazza a MyAudioSink implementációját, mert:
- Az osztálytagok egyike sem kommunikál közvetlenül a WASAPI felületeinek egyik metódusával sem.
- Az osztály többféleképpen is implementálható az ügyfél követelményeitől függően. (Például megírhatja a rögzítési adatokat egy WAV-fájlba.)
A két módszer működésével kapcsolatos információk azonban hasznosak a példa megértéséhez.
A CopyData függvény egy megadott számú hangkeretet másol egy megadott pufferhelyről. A RecordAudioStream függvény a CopyData függvénnyel olvassa és menti a hangadatokat a megosztott pufferből. A SetFormat függvény megadja az adatokhoz használni kívánt CopyData függvény formátumát.
Mindaddig, amíg a MyAudioSink objektum további adatokat igényel, a CopyData függvény a FALSE értéket adja ki a harmadik paraméteren keresztül, amely az előző kódpéldában a bDoneváltozóra mutató mutató. Amikor a MyAudioSink objektum rendelkezik minden szükséges adattal, a CopyData függvény bDone értékét TRUEállítja be, ami miatt a program kilép a RecordAudioStream függvény ciklusából.
A RecordAudioStream függvény egy egy másodperces időtartamú megosztott puffert foglal le. (A lefoglalt puffer időtartama kissé hosszabb lehet.) A fő hurokban a Windows Alvó függvény hívása miatt a program fél másodpercig várakozik. Minden Alvó hívás elején a megosztott puffer üres vagy majdnem üres. Amikor a Alvó hívás visszatér, a megosztott puffer körülbelül félig tele van rögzítési adatokkal.
A IAudioClient::Initialize metódus meghívását követően a stream nyitva marad, amíg az ügyfél nem adja ki az összes hivatkozását az IAudioClient felületre, valamint az ügyfél által az IAudioClient::GetService metóduson keresztül beszerzett szolgáltatási felületekre mutató összes hivatkozást. Az utolsó kiadási hívás bezárja a streamet.
Kapcsolódó témakörök