我尝试捕获并保存计算机的音频环回流。我使用MSDN的示例代码。我可以将声音捕捉到波形文件中并且我可以播放它,但声音质量很糟糕(很多静电,声音是溅射)。我不知道我的代码中出了什么问题。这是:
#include "stdafx.h"
#define REFTIMES_PER_SEC 10000000
#define REFTIMES_PER_MILLISEC 10000
#define SAMPLE_TO_REC 10
#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);
UINT32 packetLength = 0;
UINT32 totalRecorded = 0;
UINT32 getPacketSize()
{
return packetLength;
}
void writeToFile(std::ofstream *myFile, BYTE** buffer, WAVEFORMATEX *wfmt)
{
PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(wfmt);
pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
pEx->Samples.wValidBitsPerSample = wfmt->wBitsPerSample;
wfmt->nBlockAlign = wfmt->nChannels * wfmt->wBitsPerSample / 8;
wfmt->nAvgBytesPerSec = wfmt->nBlockAlign * wfmt->nSamplesPerSec;
int chunksize, pcmsize, NumSamples, subchunk1size;
int audioFormat = 1;
int numChannels = wfmt->nChannels;
int bitsPerSample = wfmt->wBitsPerSample;
pcmsize = sizeof(PCMWAVEFORMAT);
subchunk1size = 40;
int byteRate = wfmt->nAvgBytesPerSec;
int blockAlign = wfmt->nBlockAlign;
int sampleRate = wfmt->nSamplesPerSec;
int subchunk2size = totalRecorded*numChannels*4;
int chunkfactsize = 4;
int sampleNumber = totalRecorded / 2 / 4;
chunksize = subchunk2size + sizeof(chunksize) + 4 + 4 + sizeof(subchunk1size) + sizeof(wfmt->wFormatTag) + sizeof(wfmt->nChannels) + sizeof(wfmt->nSamplesPerSec) + sizeof(wfmt->nAvgBytesPerSec) + sizeof(wfmt->nBlockAlign) +
sizeof(wfmt->wBitsPerSample) + sizeof(wfmt->cbSize) + sizeof(pEx->Samples.wValidBitsPerSample) + sizeof(pEx->dwChannelMask) + sizeof(pEx->SubFormat) + 4 + sizeof(chunkfactsize) + sizeof(sampleNumber);
printf("channels = %d\nbyterate = %d\nblockAlign = %d\nsampleRate = %d\nData size = %d\nbitsPerSample = %d\nwValidBitsPerSample = %d\n", numChannels, byteRate, blockAlign, sampleRate, subchunk2size, wfmt->wBitsPerSample, pEx->Samples.wValidBitsPerSample);
// write the wav file per the wav file format
myFile->seekp(0, std::ios::beg);
myFile->write("RIFF", 4); // chunk id
myFile->write((char*)&chunksize, 4); // chunk size (36 + SubChunk2Size))
myFile->write("WAVE", 4); // format
myFile->write("fmt ", 4);
myFile->write((char*)&subchunk1size, sizeof(subchunk1size));
myFile->write((char*)&wfmt->wFormatTag, sizeof(wfmt->wFormatTag));
myFile->write((char*)&wfmt->nChannels, sizeof(wfmt->nChannels));
myFile->write((char*)&wfmt->nSamplesPerSec, sizeof(wfmt->nSamplesPerSec));
myFile->write((char*)&wfmt->nAvgBytesPerSec, sizeof(wfmt->nAvgBytesPerSec));
myFile->write((char*)&wfmt->nBlockAlign, sizeof(wfmt->nBlockAlign));
myFile->write((char*)&wfmt->wBitsPerSample, sizeof(wfmt->wBitsPerSample));
myFile->write((char*)&wfmt->cbSize, sizeof(wfmt->cbSize));
myFile->write((char*)&pEx->Samples.wValidBitsPerSample, sizeof(pEx->Samples.wValidBitsPerSample));
myFile->write((char*)&pEx->dwChannelMask, sizeof(pEx->dwChannelMask));
myFile->write((char*)&pEx->SubFormat, sizeof(pEx->SubFormat));
myFile->write("fact", 4);
myFile->write((char*)&chunkfactsize, sizeof(chunkfactsize));
myFile->write((char*)&sampleNumber, sizeof(sampleNumber));
myFile->write("data", 4);
myFile->write((char*)&subchunk2size, 4);
int i = -1;
while (++i < SAMPLE_TO_REC)
{
if (buffer[i] != NULL)
myFile->write((char *)buffer[i], 384000);
}
}
HRESULT WINAPI RecordAudioStream(LPVOID _hnd)
{
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;
BOOL bDone = FALSE;
DWORD flags;
BYTE** pData;
BYTE* pDataTemp;
std::string bufTemp;
AudioStreamHandler* hnd = (AudioStreamHandler *)_hnd;
int totalPerSecond = 0;
printf("addr CAPTURE thread = %p\n", hnd);
std::ofstream myFile("C:\\Users\\tanguy\\Documents\\GitHub\\bobomb\\x64\\Release\\test.wav", std::fstream::out | std::fstream::binary);
myFile.imbue(std::locale::classic());
pData = (BYTE **)malloc(sizeof(*pData) * (SAMPLE_TO_REC));
hr = CoInitialize(NULL);
EXIT_ON_ERROR(hr)
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
EXIT_ON_ERROR(hr)
hr = pEnumerator->GetDefaultAudioEndpoint(
eRender, 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,
AUDCLNT_STREAMFLAGS_LOOPBACK,
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)
// 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)
int i = -1;
while (++i < SAMPLE_TO_REC && hnd->_bExit == false)
{
Sleep(1000);
hr = pCaptureClient->GetNextPacketSize(&packetLength);
EXIT_ON_ERROR(hr)
totalPerSecond = 0;
pData[i] = (BYTE*)malloc(sizeof(BYTE) * pwfx->nAvgBytesPerSec);
while (packetLength != 0)
{
totalRecorded += packetLength;
// Get the available data in the shared buffer.
hr = pCaptureClient->GetBuffer(
&pDataTemp,
&numFramesAvailable,
&flags, NULL, NULL);
EXIT_ON_ERROR(hr)
memcpy(pData[i] + totalPerSecond, pDataTemp, numFramesAvailable * 2 * 4);
totalPerSecond += numFramesAvailable * 2 * 4;
//printf("%d\n", numFramesAvailable);
if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
{
pData[i] = NULL; // Tell CopyData to write silence.
}
//hnd->setAudioBuffer(&pData);
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)
if (hnd->_bExit == false)
{
printf("writing ...\n");
writeToFile(&myFile, pData, pwfx);
myFile.close();
}
Exit:
CoTaskMemFree(pwfx);
SAFE_RELEASE(pEnumerator)
SAFE_RELEASE(pDevice)
SAFE_RELEASE(pAudioClient)
SAFE_RELEASE(pCaptureClient)
return hr;
}
这是一些输出(来自我的printf):
channels = 2
byterate = 384000
blockAlign = 8
sampleRate = 48000
Data size = 3840000
bitsPerSample = 32
wValidBitsPerSample = 32
我不知道我在这里缺少什么。