windows下使用CoreAudio采集音频

最近看obs的音频采集,发现它在采集音频时用到了两个方法:默认音频设备时采用CoreAudio、指定音频设备时采用DirectShow

对windows下的CoreAudio技术不是太熟,于是就认真学了一下。

参考微软官方文档:https://docs.microsoft.com/zh-cn/windows/desktop/CoreAudio/capturing-a-stream

//-----------------------------------------------------------
// 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.
//-----------------------------------------------------------
#include <mmdeviceapi.h>
#include <Audioclient.h>
#include <audiopolicy.h>
#include <devicetopology.h>
#include <endpointvolume.h>
#include <stdio.h>
// 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()
{
	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 = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	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);
			printf("size=%d\n", numFramesAvailable);
			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 main()
{
	RecordAudioStream();
	return 0;
}

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
嗨!对于 Windows 平台上的音频播放,可以使用 Core Audio API。以下是一个简单的示例代码,展示如何使用 Core Audio API 播放音频: ```c++ #include <Windows.h> #include <Mmdeviceapi.h> #include <Audioclient.h> #include <iostream> int main() { HRESULT hr; // 初始化 COM 组件 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) { std::cout << "COM 初始化失败" << std::endl; return 1; } // 创建设备枚举器 IMMDeviceEnumerator* pEnumerator = NULL; hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator); if (FAILED(hr)) { std::cout << "设备枚举器创建失败" << std::endl; CoUninitialize(); return 1; } // 获取默认音频渲染设备 IMMDevice* pDevice = NULL; hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice); if (FAILED(hr)) { std::cout << "获取默认音频设备失败" << std::endl; pEnumerator->Release(); CoUninitialize(); return 1; } // 激活设备接口 IAudioClient* pAudioClient = NULL; hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient); if (FAILED(hr)) { std::cout << "音频客户端激活失败" << std::endl; pDevice->Release(); pEnumerator->Release(); CoUninitialize(); return 1; } // 设置音频格式 WAVEFORMATEX* pWaveFormat; hr = pAudioClient->GetMixFormat(&pWaveFormat); if (FAILED(hr)) { std::cout << "获取音频格式失败" << std::endl; pAudioClient->Release(); pDevice->Release(); pEnumerator->Release(); CoUninitialize(); return 1; } // 初始化音频流 hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 10000000, 0, pWaveFormat, NULL); if (FAILED(hr)) { std::cout << "音频流初始化失败" << std::endl; CoTaskMemFree(pWaveFormat); pAudioClient->Release(); pDevice->Release(); pEnumerator->Release(); CoUninitialize(); return 1; } // 获取音频缓冲区 IAudioRenderClient* pRenderClient = NULL; hr = pAudioClient->GetService(__uuidof(IAudioRenderClient), (void**)&pRenderClient); if (FAILED(hr)) { std::cout << "获取音频渲染客户端失败" << std::endl; CoTaskMemFree(pWaveFormat); pAudioClient->Release(); pDevice->Release(); pEnumerator->Release(); CoUninitialize(); return 1; } // 启动音频流 hr = pAudioClient->Start(); if (FAILED(hr)) { std::cout << "音频流启动失败" << std::endl; CoTaskMemFree(pWaveFormat); pRenderClient->Release(); pAudioClient->Release(); pDevice->Release(); pEnumerator->Release(); CoUninitialize(); return 1; } // 从音频缓冲区写入数据 UINT32 bufferSize = 0; BYTE* pData; hr = pRenderClient->GetBuffer(bufferSize, &pData); if (FAILED(hr)) { std::cout << "获取音频缓冲区失败" << std::endl; CoTaskMemFree(pWaveFormat); pRenderClient->Release(); pAudioClient->Release(); pDevice->Release(); pEnumerator->Release(); CoUninitialize(); return 1; } // 在这里填充音频数据到 pData 缓冲区 // 释放音频缓冲区 hr = pRenderClient->ReleaseBuffer(bufferSize, 0); if (FAILED(hr)) { std::cout << "释放音频缓冲区失败" << std::endl; } // 停止音频流 hr = pAudioClient->Stop(); if (FAILED(hr)) { std::cout << "停止音频流失败" << std::endl; } // 清理资源 CoTaskMemFree(pWaveFormat); pRenderClient->Release(); pAudioClient->Release(); pDevice->Release(); pEnumerator->Release(); CoUninitialize(); return 0; } ``` 这是一个基本示例,你可以根据自己的需求进行修改和扩展。记得在使用完毕后,释放所有的资源以避免内存泄漏。希望对你有帮助!如果你还有其他问题,请随时提问。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱技术爱生活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值