windows采集音频

1、 定义线程类

线程类比较简单,使用标准c++ 的thread,线程类的Run函数为纯虚函数。

/*
Author:钱波
email: 418511899@qq.com
wei:   18091589062
func  :线程类
time:  2018年5月30日
*/

#ifndef _TTHREAD_RUN_ABLE_H_
#define _TTHREAD_RUN_ABLE_H_


#include <mutex>
#include <queue>
#include <thread>
#include <atomic>
#include <condition_variable>
using namespace std;

class TThreadRunable
{
private:

	//线程
	thread _thread;
	//等待信号
	std::mutex _signal_mutex;
	std::condition_variable _cond;
protected:
	//char  _running = false;
	char _stop = true;
	//锁定运行状态
	std::mutex _mutex;
public:
	TThreadRunable()
	{}
	virtual ~TThreadRunable()
	{}

public:
	char * status(){
		return &_stop;
	}
	
	void Join()
	{
		if (_thread.joinable())
			_thread.join();
	}
	bool  IsStop()
	{
		return _stop == 1 ? true : false;
	}
	void WaitForSignal()
	{
		std::unique_lock<std::mutex> ul(_signal_mutex);
		_cond.wait(ul);
	}
	void Notify()
	{
		_cond.notify_one();
	}

	virtual int Start()
	{
		if (_stop == 0)
			return -1;
		_stop = 0;
		_thread = std::thread(std::bind(&TThreadRunable::Run, this));
		return 0;
	}	
	
	virtual void Stop()
	{
		_stop = 1; // true;
	}

	virtual void Run() = 0;
};
#endif

定义回调

typedef void(*VoiceCallback)(uint8_t *data, int len);
回调函数注入实现后,在线程中获取函数后,就调用回调函数。

定义实现类

#include <windows.h>
#include <windowsx.h>
#include <mmdeviceapi.h>
#include <Audioclient.h>
#include <process.h>
#include <avrt.h>
#include "TThreadRunable.h"
typedef void(*VoiceCallback)(uint8_t *data, int len);
class CAudioCapThread:public TThreadRunable
{
public:

	enum {SPEAKER = 1,MICPHONE};

public:
	CAudioCapThread();
	~CAudioCapThread();
	//开始捕获
	int Start();
	//停止捕获
	void Stop();

	void SetDeiveType(int nType);

	int GetDeviceType();
	


	IMMDevice * GetDevice();

	WAVEFORMATEX * GetWaveFormat();

	DWORD GetDataSize();

	VoiceCallback m_callback = NULL;

	void Run();
protected:
	bool m_bInit;
	bool Init();
	void SaveFormat(WAVEFORMATEX * wf);
	void OnCaptureData(LPBYTE pData, INT iDataLen);

	WAVEFORMATEX m_WaveFormat;

	int m_nDeviceType = 1;


	IMMDevice * m_pDevice = NULL;


	IMMDevice * GetDefaultDevice(int nType);

	DWORD m_dwDataSize;

};
#include "AudioCapThread.h"

#define REFTIMES_PER_SEC  10000000
#define REFTIMES_PER_MILLISEC  10000

#pragma comment(lib, "Avrt.lib")

CAudioCapThread::CAudioCapThread()
{
	m_dwDataSize = 0;
	m_bInit = false;
	//::InitializeCriticalSection(&m_cs);
}

CAudioCapThread::~CAudioCapThread()
{
}

void CAudioCapThread::SetDeiveType(int nType)
{
	m_nDeviceType = nType;
}


int CAudioCapThread::GetDeviceType()
{
	return m_nDeviceType;
}

void CAudioCapThread::OnCaptureData(LPBYTE pData, INT iDataLen)
{

	if (m_callback != NULL)
		m_callback(pData, iDataLen);
}


IMMDevice * CAudioCapThread::GetDefaultDevice(int nType)
{
	IMMDevice *pDevice = nullptr;

	IMMDeviceEnumerator *pMMDeviceEnumerator = nullptr;
	HRESULT hr = CoCreateInstance(
		__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
		__uuidof(IMMDeviceEnumerator),
		(void**)&pMMDeviceEnumerator);
	if (FAILED(hr))
		return nullptr;

	if (nType == CAudioCapThread::MICPHONE)
		hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint((EDataFlow)eCapture, eConsole, &pDevice);
	else if (nType == CAudioCapThread::SPEAKER)
		hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint((EDataFlow)eRender, eConsole, &pDevice);
	else
		pDevice = nullptr;

	if (pMMDeviceEnumerator)
	{
		pMMDeviceEnumerator->Release();
		pMMDeviceEnumerator = nullptr;
	}

	return pDevice;
}

bool CAudioCapThread::Init()
{
	if (m_bInit)
		return true;


	m_pDevice = GetDefaultDevice(m_nDeviceType);

	if (!m_pDevice)
		return false;

	m_dwDataSize = 0;

	m_bInit = true;

	return true;
}

DWORD CAudioCapThread::GetDataSize()
{
	DWORD dwSize = m_dwDataSize;
	return dwSize;
}

IMMDevice * CAudioCapThread::GetDevice()
{
	return m_pDevice;
}


void CAudioCapThread::Run()
{
	CoInitialize(NULL);

	HRESULT hr = 0;
	IAudioClient *pAudioClient = nullptr;
	WAVEFORMATEX *pWfx = nullptr;
	IAudioCaptureClient *pAudioCaptureClient = nullptr;
	DWORD nTaskIndex = 0;
	HANDLE hTask = nullptr;
	bool bStarted(false);
	int nDeviceType = 0;
	IMMDevice * pDevice = m_pDevice;

	REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
	REFERENCE_TIME hnsActualDuration;

	UINT bufferFrameCount = 0;

	if (!pDevice )
		return ;

	do
	{
		hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void**)&pAudioClient);
		if (FAILED(hr))
			break;

		hr = pAudioClient->GetMixFormat(&pWfx);
		
		if (FAILED(hr))
			break;


		SaveFormat(pWfx);

		nDeviceType = GetDeviceType();

		if (nDeviceType == CAudioCapThread::MICPHONE)
			hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, pWfx, 0);
		else if (nDeviceType == CAudioCapThread::SPEAKER)
			hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, pWfx, 0);
		else
			break;

		if (FAILED(hr))
			break;

		hr = pAudioClient->GetBufferSize(&bufferFrameCount);

		if (FAILED(hr))
			break;

		hr = pAudioClient->GetService(__uuidof(IAudioCaptureClient), (void**)&pAudioCaptureClient);

		if (FAILED(hr))
			break;

		hnsActualDuration = (double)REFTIMES_PER_SEC * bufferFrameCount / pWfx->nSamplesPerSec;

		if (nDeviceType == CAudioCapThread::MICPHONE)
			hTask = AvSetMmThreadCharacteristics(L"Audio", &nTaskIndex);
		else
			hTask = AvSetMmThreadCharacteristics(L"Capture", &nTaskIndex);

		if (!hTask)
			break;

		hr = pAudioClient->Start();
		if (FAILED(hr))
			break;

		bStarted = true;

		UINT32 uiNextPacketSize(0);
		BYTE *pData = nullptr;
		UINT32 uiNumFramesToRead;
		DWORD dwFlags;

		while (1)
		{
			if (IsStop())
				break;
			Sleep(hnsActualDuration / REFTIMES_PER_MILLISEC / 2);

			hr = pAudioCaptureClient->GetNextPacketSize(&uiNextPacketSize);
			if (FAILED(hr))
				break;

			while (uiNextPacketSize != 0)
			{
				hr = pAudioCaptureClient->GetBuffer(
					&pData,
					&uiNumFramesToRead,
					&dwFlags,
					nullptr,
					nullptr);

				if (FAILED(hr))
					break;

				if (dwFlags & AUDCLNT_BUFFERFLAGS_SILENT)
				{
					pData = NULL;
				}
		
				OnCaptureData(pData, uiNumFramesToRead * pWfx->nBlockAlign);	
	
				pAudioCaptureClient->ReleaseBuffer(uiNumFramesToRead);

				hr = pAudioCaptureClient->GetNextPacketSize(&uiNextPacketSize);

				if (FAILED(hr))
					break;
			}
		}

	} while (0);

	if (hTask)
	{
		AvRevertMmThreadCharacteristics(hTask);
		hTask = nullptr;
	}

	if (pAudioCaptureClient)
	{
		pAudioCaptureClient->Release();
		pAudioCaptureClient = nullptr;
	}

	if (pWfx)
	{
		CoTaskMemFree(pWfx);
		pWfx = nullptr;
	}

	if (pAudioClient)
	{
		if (bStarted)
		{
			pAudioClient->Stop();
		}

		pAudioClient->Release();
		pAudioClient = nullptr;
	}

}


void CAudioCapThread::SaveFormat(WAVEFORMATEX * wf)
{
	if (!wf)
		return;

	
	memcpy(&m_WaveFormat, wf, sizeof(WAVEFORMATEX));

	return;
}

WAVEFORMATEX * CAudioCapThread::GetWaveFormat()
{
	return &m_WaveFormat;
}



int CAudioCapThread::Start()
{
	if (!m_bInit)
		Init();
	TThreadRunable::Start();
	return 0;
}

void CAudioCapThread::Stop()
{
	if (m_bInit == false)
		return ;

	TThreadRunable::Stop();
	Join();
	if (m_pDevice)
	{
		m_pDevice->Release();
		m_pDevice = NULL;
	}
	m_bInit = false;

}

3、main主函数中测试

#include "AudioCapThread.h"
#include <conio.h>
void voice_Callback(uint8_t *data, int len)
{
	printf("the length is %d\n", len);
}


int main()
{
	CoInitialize(NULL);
	CAudioCapThread thread;
	//thread.Init();
	thread.m_callback = voice_Callback;
	thread.Start();

	thread.Join();
	printf("test");
	CoUninitialize();
	return 0;
}

4、执行结果

播放声音
当系统开始播放时,回调函数开始显示有数据,停止播放时,回调函数停止响应
在这里插入图片描述
即使系统静音,依然可以捕获声音。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qianbo_insist

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

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

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

打赏作者

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

抵扣说明:

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

余额充值