Core Audio声卡输出采集

#define _CRT_SECURE_NO_WARNINGS

#pragma comment(lib,"avrt.lib")
#include<Audioclient.h>
#include <mmdeviceapi.h>
#include<iostream>
#include<avrt.h>

class CSoundCardAudioCapture
{

public:

	CSoundCardAudioCapture()
	{
		m_pAudioCaptureClient = NULL;
		m_pAudioClient = NULL;
		m_pMMDevice = NULL;
		m_hEventStop = NULL;
		m_hTimerWakeUp = NULL;
		m_hTask = NULL;
		m_pwfx = NULL;
	}

	int StartCapture()
	{
		CoInitialize(NULL);
		IMMDeviceEnumerator *pMMDeviceEnumerator = NULL;
		HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
			__uuidof(IMMDeviceEnumerator), (void**)&pMMDeviceEnumerator);
		if (FAILED(hr))
		{
			CoUninitialize();
			return -1;
		}
		hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pMMDevice);
		if (FAILED(hr))
		{
			CoUninitialize();
			return -1;
		}
		pMMDeviceEnumerator->Release();

		m_hEventStop = CreateEvent(NULL, TRUE, FALSE, NULL);
		if (m_hEventStop == NULL)
		{
			CoUninitialize();
			return -1;
		}

		hr = m_pMMDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
		if (FAILED(hr))
			goto error;

		REFERENCE_TIME hnsDefaultDevicePeriod(0);
		hr = m_pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, NULL);
		if (FAILED(hr))
			goto error;

		hr = m_pAudioClient->GetMixFormat(&m_pwfx);
		if (FAILED(hr))
			goto error;

		if (!AdjustFormatTo16Bits(m_pwfx))
			goto error;

		m_hTimerWakeUp = CreateWaitableTimer(NULL, FALSE, NULL);
		if (m_hTimerWakeUp == NULL)
			goto error;

		hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, m_pwfx, 0);
		if (FAILED(hr))
			goto error;

		hr = m_pAudioClient->GetService(__uuidof(IAudioCaptureClient), (void**)&m_pAudioCaptureClient);
		if (FAILED(hr))
			goto error;

		DWORD nTaskIndex = 0;
		m_hTask = AvSetMmThreadCharacteristics(L"Capture", &nTaskIndex);
		if (NULL == m_hTask)
			goto error;

		LARGE_INTEGER liFirstFire;
		liFirstFire.QuadPart = -hnsDefaultDevicePeriod / 2; // negative means relative time
		LONG lTimeBetweenFires = (LONG)hnsDefaultDevicePeriod / 2 / (10 * 1000); // convert to milliseconds

		BOOL bOK = SetWaitableTimer(m_hTimerWakeUp, &liFirstFire, lTimeBetweenFires, NULL, NULL, FALSE);
		if (!bOK)
			goto error;

		hr = m_pAudioClient->Start();
		if (FAILED(hr))
			goto error;

		m_hThread = CreateThread(NULL, 0, PTHREAD_START_ROUTINE_CALLBACK, this, 0, 0);
		if (m_hThread == NULL)
			goto error;

		CoUninitialize();
		return 0;
	error:
		Close();
		CoUninitialize();
		return -1;
	}

	int StopCapture()
	{
		if (m_pAudioClient)
			m_pAudioClient->Stop();
		SetEvent(m_hEventStop);
		WaitForSingleObject(m_hThread, -1);
		Close();
		return 0;
	}

	void DoWork()
	{
		HANDLE waitArray[2] = { m_hEventStop, m_hTimerWakeUp };
		DWORD dwWaitResult;
		UINT32 nNextPacketSize(0);
		BYTE *pData = NULL;
		UINT32 nNumFramesToRead;
		DWORD dwFlags;
		CoInitialize(NULL);
		FILE *file = fopen("D:\\pwm.data", "wb+");
		while (TRUE)
		{
			dwWaitResult = WaitForMultipleObjects(sizeof(waitArray) / sizeof(waitArray[0]), waitArray, FALSE, INFINITE);
			if (WAIT_OBJECT_0 == dwWaitResult) break;

			if (WAIT_OBJECT_0 + 1 != dwWaitResult)
			{
				break;
			}

			HRESULT hr = m_pAudioCaptureClient->GetNextPacketSize(&nNextPacketSize);
			if (FAILED(hr))
			{
				break;
			}

			if (nNextPacketSize == 0) continue;

			hr = m_pAudioCaptureClient->GetBuffer(&pData, &nNumFramesToRead, &dwFlags, NULL, NULL);
			if (FAILED(hr))
			{
				break;
			}

			if (0 != nNumFramesToRead)
			{
				std::cout << "capture data " << nNumFramesToRead * m_pwfx->nBlockAlign << std::endl;
				fwrite(pData, 1, nNumFramesToRead * m_pwfx->nBlockAlign,file);
			}
			m_pAudioCaptureClient->ReleaseBuffer(nNumFramesToRead);
		}
		CoUninitialize();
	}

	static DWORD WINAPI PTHREAD_START_ROUTINE_CALLBACK(LPVOID lpThreadParameter);

protected:

	void Close()
	{
		if (m_hEventStop != NULL)
		{
			CloseHandle(m_hEventStop);
			m_hEventStop = NULL;
		}
		if (m_pAudioClient)
		{
			m_pAudioClient->Release();
			m_pAudioClient = NULL;
		}
		if (m_pwfx != NULL)
		{
			CoTaskMemFree(m_pwfx);
			m_pwfx = NULL;
		}
		if (m_hTimerWakeUp != NULL)
		{
			CancelWaitableTimer(m_hTimerWakeUp);
			CloseHandle(m_hTimerWakeUp);
			m_hTimerWakeUp = NULL;
		}
		if (m_hTask != NULL)
		{
			AvRevertMmThreadCharacteristics(m_hTask);
			m_hTask = NULL;
		}
		if (m_pAudioCaptureClient != NULL)
		{
			m_pAudioCaptureClient->Release();
			m_pAudioCaptureClient = NULL;
		}
	}

	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;
	}


private:

	HANDLE m_hThread;
	HANDLE m_hTask;
	HANDLE m_hTimerWakeUp;
	IAudioCaptureClient * m_pAudioCaptureClient;
	IAudioClient * m_pAudioClient;
	WAVEFORMATEX * m_pwfx;
	HANDLE m_hEventStop;
	IMMDevice* m_pMMDevice;

};

DWORD CSoundCardAudioCapture::PTHREAD_START_ROUTINE_CALLBACK(LPVOID lpThreadParameter)
{
	CSoundCardAudioCapture* pCapture = (CSoundCardAudioCapture*)lpThreadParameter;
	pCapture->DoWork();
	return 0;
}


int main(void)
{
	CSoundCardAudioCapture cap;
	while (true)
	{
		cap.StartCapture();
		getchar();
		cap.StopCapture();
	}
	return 0;
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
嗨!对于 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; } ``` 这是一个基本示例,你可以根据自己的需求进行修改和扩展。记得在使用完毕后,释放所有的资源以避免内存泄漏。希望对你有帮助!如果你还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值