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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值