桌面录音
Posted xianjian_x
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了桌面录音相关的知识,希望对你有一定的参考价值。
公司做一个项目,需要把 windows 扬声器的声音捕捉下来,这个可以参考MSDN文档,上面有示例程序:
Loopback Recording
这程序并不完整,还需要做一些修改才行:
下面是我 调试通过的代码:
#include <Mmdeviceapi.h>
#include <Audioclient.h>
//-----------------------------------------------------------
// 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);
class MyAudioSink
public:
//WAVEFORMATEX *pwfx = NULL;
int SetFormat(WAVEFORMATEX *pwfx);
int CopyData(char * pData,UINT32 numFramesAvailable,BOOL *pbDone);
;
int MyAudioSink::SetFormat(WAVEFORMATEX *pwfx)
printf("wFormatTag is %x\\n", pwfx->wFormatTag);
printf("nChannels is %x\\n", pwfx->nChannels);
printf("nSamplesPerSec is %d\\n", pwfx->nSamplesPerSec);
printf("nAvgBytesPerSec is %d\\n", pwfx->nAvgBytesPerSec);
printf("wBitsPerSample is %d\\n", pwfx->wBitsPerSample);
return 0;
int MyAudioSink::CopyData(char * pData,UINT32 numFramesAvailable,BOOL *pbDone)
if(pData != NULL)
fwrite(pData, numFramesAvailable ,1,fp);
return 0;
/// pwfx->nSamplesPerSec = 44100;
/// 不支持修改采样率, 看来只能等得到数据之后再 swr 转换了
BOOL AdjustFormatTo16Bits(WAVEFORMATEX *pwfx)
BOOL bRet(FALSE);
if(pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
pwfx->wFormatTag = WAVE_FORMAT_PCM;
pwfx->wBitsPerSample = 16;
pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
bRet = TRUE;
else if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat))
pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
pEx->Samples.wValidBitsPerSample = 16;
pwfx->wBitsPerSample = 16;
pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
bRet = TRUE;
return bRet;
HRESULT RecordAudioStream(MyAudioSink *pMySink)
HRESULT hr;
REFERENCE_TIME hnsActualDuration;
UINT32 bufferFrameCount;
UINT32 numFramesAvailable;
BYTE * pData;
DWORD flags;
REFERENCE_TIME hnsDefaultDevicePeriod(0);
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
IMMDeviceEnumerator* pEnumerator = NULL;
IMMDevice * pDevice = NULL;
IAudioClient * pAudioClient = NULL;
IAudioCaptureClient * pCaptureClient = NULL;
WAVEFORMATEX * pwfx = NULL;
UINT32 packetLength = 0;
BOOL bDone = FALSE;
HANDLE hTimerWakeUp = NULL;
hr = CoCreateInstance( CLSID_MMDeviceEnumerator, NULL,CLSCTX_ALL, IID_IMMDeviceEnumerator,(void**)&pEnumerator );
EXIT_ON_ERROR(hr)
hr = pEnumerator->GetDefaultAudioEndpoint( eRender /*eCapture*/, eConsole, &pDevice );
EXIT_ON_ERROR(hr)
hr = pDevice->Activate( IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
EXIT_ON_ERROR(hr)
hr = pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, NULL);
hr = pAudioClient->GetMixFormat(&pwfx);
EXIT_ON_ERROR(hr)
AdjustFormatTo16Bits(pwfx);
hTimerWakeUp = CreateWaitableTimer(NULL, FALSE, NULL);
hr = pAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,AUDCLNT_STREAMFLAGS_LOOPBACK /*0*/ ,0 ,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)
LARGE_INTEGER liFirstFire;
liFirstFire.QuadPart = -hnsDefaultDevicePeriod / 2; // negative means relative time
LONG lTimeBetweenFires = (LONG)hnsDefaultDevicePeriod / 2 / (10 * 1000); // convert to milliseconds
BOOL bOK = SetWaitableTimer(hTimerWakeUp,&liFirstFire,lTimeBetweenFires,NULL, NULL, FALSE);
// 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)
HANDLE waitArray[1] = /*htemp hEventStop,*/ hTimerWakeUp ;
// Each loop fills about half of the shared buffer.
while (bDone == FALSE)
// Sleep for half the buffer duration.
//Sleep(hnsActualDuration/REFTIMES_PER_MILLISEC/2);
//WaitForSingleObject(hTimerWakeUp,INFINITE);
WaitForMultipleObjects(sizeof(waitArray)/sizeof(waitArray[0]), waitArray, FALSE, INFINITE);
//WaitForMultipleObjects(sizeof(waitArray)/sizeof(waitArray[0]), waitArray, FALSE, INFINITE);
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((char *) pData, numFramesAvailable * pwfx->nBlockAlign, &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;
int _tmain(int argc, _TCHAR* argv[])
fp = fopen("F://work//record.pcm","wb");
CoInitialize(NULL);
MyAudioSink test;
RecordAudioStream(&test);
return 0;
留着以后使用
以上是关于桌面录音的主要内容,如果未能解决你的问题,请参考以下文章