Windows下Core Audio APIs音频应用开发

时间:2021-09-01 19:26:32

   对于一个音频应用程序,最基本也是最重要的两点就是:音频数据的采集;音频数据的播放。首先我们来了解下面几个概念:

   ·IMMDevice:创建音频设备终端,我们可以把它简单的理解为设备对象;

   ·IAudioClient:创建一个用来管理音频数据流的对象,应用程序通过这个对象可以获取的音频设备里的数据,我们可以把它想象成一个大水池,里面都是一些数据。

   ·IAudioCaptureClient:很明显,专用于获取采集数据的对象,它还有个兄弟IAudioRenderClient。


    下面直接上官网示例代码,解释代码大家就清楚怎么做了。

 //首先枚举你的音频设备,你可以在这个时候获取到你机器上所有可用的设备,并指定你需要用到的那个设置
    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)

//这个buffersize,指的是缓冲区最多可以存放多少帧的数据量
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(hnsActualDuration/REFTIMES_PER_MILLISEC/2);

hr = pCaptureClient->GetNextPacketSize(&packetLength);
EXIT_ON_ERROR(hr)

while (packetLength != 0)
{
//锁定缓冲区,获取数据
hr = pCaptureClient->GetBuffer(
&pData,
&numFramesAvailable,
&flags, NULL, NULL);
EXIT_ON_ERROR(hr)

if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
{
pData = NULL;
}

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();
EXIT_ON_ERROR(hr)

    代码就这么多,这是官网给出的最简单的一个关于获取音频数据的示例,这里面取到的数据是最原始的,我们可以对这些数据进行任何处理,达到我们需要的效果。

   音频数据量的计算:数据量(字节/秒)=(采样频率(HZ)*采样位数(bit)*声道数)/8

   在代码中,创建完管理对象后,我们就可以获取到当前设备的音频数据的格式,然后对pMySink设置了数据格式

   hr = pAudioClient->GetMixFormat(&pwfx);//这里就可以获取数据格式:频率、采集位数、声道数

   hr = pMySink->SetFormat(pwfx); //设置数据格式,计算数据量

  这就决定了pMySink每次读取数据量的大小,保证我们在获取的每一帧数据都是正确的

   hr = pMySink->CopyData(pData, numFramesAvailable, &bDone);

   这里就是简单的拷贝数据了。