如何解决如何在Windows 10上使用C ++将连续的原始音频数据记录到循环缓冲区中?
自Windows Multimedia turned out to be utterly incapable of recording continuous audio起,我得到使用Windows Core Audio的提示。有种手册here,但我不知道如何编写开销代码来使录音正常工作。任何人都可以向循环缓冲区提供连续音频录制的完整,最少的实现吗?
到目前为止,由于pEnumerator->GetDefaultAudioEndpoint(eRender,eConsole,&pDevice);
仍然是pEnumerator
,因此我停留在下面的代码中,没有越过nullptr
行。
#define VC_EXTRALEAN
#define _USE_MATH_DEFINES
#include <Windows.h>
#include <Audioclient.h>
#include <Mmdeviceapi.h>
#define REFTIMES_PER_SEC 10000000
#define REFTIMES_PER_MILLISEC 10000
int main() {
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
UINT32 bufferFrameCount;
UINT32 numFramesAvailable;
IMMDeviceEnumerator* pEnumerator = NULL;
IMMDevice* pDevice = NULL;
IAudioClient* pAudioClient = NULL;
IAudioCaptureClient* pCaptureClient = NULL;
WAVEFORMATEX* pwfx = NULL;
UINT32 packetLength = 0;
BYTE* pData;
DWORD flags;
CoCreateInstance(__uuidof(MMDeviceEnumerator),NULL,CLSCTX_ALL,__uuidof(IMMDeviceEnumerator),(void**)&pEnumerator);
pEnumerator->GetDefaultAudioEndpoint(eRender,&pDevice);
pDevice->Activate(__uuidof(IAudioClient),(void**)&pAudioClient);
pAudioClient->GetMixFormat(&pwfx);
pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,AUDCLNT_STREAMFLAGS_LOOPBACK,hnsRequestedDuration,pwfx,NULL);
pAudioClient->GetBufferSize(&bufferFrameCount); // Get the size of the allocated buffer.
pAudioClient->GetService(__uuidof(IAudioCaptureClient),(void**)&pCaptureClient);
// Calculate the actual duration of the allocated buffer.
REFERENCE_TIME hnsActualDuration = (double)REFTIMES_PER_SEC* bufferFrameCount / pwfx->nSamplesPerSec;
pAudioClient->Start(); // Start recording.
// Each loop fills about half of the shared buffer.
while(true) {
// Sleep for half the buffer duration.
Sleep(hnsActualDuration/REFTIMES_PER_MILLISEC/2);
pCaptureClient->GetNextPacketSize(&packetLength);
while(packetLength != 0) {
// Get the available data in the shared buffer.
pCaptureClient->GetBuffer(&pData,&numFramesAvailable,&flags,NULL);
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);
pCaptureClient->ReleaseBuffer(numFramesAvailable);
pCaptureClient->GetNextPacketSize(&packetLength);
}
}
pAudioClient->Stop();
return 0;
}
解决方法
您没有调用 CoInitializeEx
,因此所有 COM 调用都将失败。
您还应该测试所有调用以查看它们是否返回错误。
解决评论中提出的问题:
我相信如果你想在共享模式下操作端点,那么你必须使用GetFixFormat
返回的参数。这意味着:
-
您仅限于一个采样率(除非您编写代码来执行转换,这是一项非常重要的任务)
-
如果您希望样本为浮点数,则必须自己进行转换
要编写在所有机器上运行的代码,您必须满足混合格式的要求。这可能是:
-
16 位整数
-
24 位整数 (nBlockAlign = 3)
-
32 位容器中的 24 位整数 (nBlockAlign = 4)
-
32 位整数
-
32 位浮点数(罕见)
-
64 位浮点数(根据我的经验,闻所未闻)
样本将采用您的代码运行所在机器的本机字节顺序,并且是交错的。
因此,请考虑 pwfx
中的各种参数,并为您想要支持的每种示例格式编写相关代码。
假设您希望将 float
规范化为 -1 .. +1
和 2 通道输入数据,您可以对 16 位整数执行此操作,例如:
const int16_t *inbuf = (const int16_t *) pData;
float *outbuf = ...;
for (int i = 0; i < numFramesAvailable * 2; ++i)
{
int16_t sample = *inbuf++;
*outbuf++ = (float) (sample * (1.0 / 32767));
}
请注意,我通过乘以倒数来避免(缓慢的)浮点除法(编译器会预先计算 1.0 / 32767
)。
剩下的交给你。
,您可以改用此音频库。与尝试与特定于平台的 SDK 交互相比,它更容易启动和运行:
http://www.music.mcgill.ca/~gary/rtaudio/recording.html
此外,虽然在您的示例中删除 sleep 可能无济于事,但您永远不应该在音频处理期间调用 sleep、锁定互斥锁或分配内存。与较短的缓冲时间相比,这些引入的延迟完全是任意的,因此总会给您带来问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。