core audio 音频捕获

                  最近,接触了一个项目,这个项目捕获的音频,噪音很大,所以研究了core audio ,重写了音频捕获类。

Common.h

/*
*	author: zyb
*   \brief Common Macro
*/

#pragma once

#ifndef IS_NULLPTR
#define IS_NULLPTR(ptr)		(nullptr == (ptr))
#endif
#ifndef NOT_NULLPTR
#define NOT_NULLPTR(ptr)	(nullptr != (ptr))
#endif
#ifndef IS_TRUE
#define IS_TRUE(isTrue)		(true == (isTrue))
#endif
#ifndef IS_FALSE
#define IS_FALSE(isFalse)	(false == (isFalse))
#endif
#ifndef SafDelete_A
#define SafDelete_A(ptr)	if(NOT_NULLPTR(ptr)){ delete[] (ptr); (ptr) = nullptr; }
#endif
#ifndef SafRelease
#define SafRelease(ptr)		if(NOT_NULLPTR(ptr)){ (ptr)->Release(); (ptr) = nullptr; }
#endif
#ifndef SafCloseHandle
#define SafCloseHandle(handle)	if(NOT_NULLPTR(handle)){ CloseHandle(handle); (handle) = nullptr; }
#endif

#include <wtypes.h>

CaptureEvent.h

/*
*	author: zyb
*   \brief CaptureEvent Interface
*/

#include "Common.h"
#include <mmreg.h>

class ICaptureEvent
{
public:
	virtual ~ICaptureEvent(){};

	virtual void OnCaptureStart(DWORD dwInterval) = 0;
	virtual void OnCaptureStop() = 0;
	
	virtual void OnAdjustCaptureFormat(WAVEFORMATEX *pFormat) = 0;
	virtual void OnCaptureData(LPBYTE pData, int iDataLen) = 0;
};

AudioCapture.hpp

/*
*	author: zyb		
*	\brief:   
*		CAudioCaptureT<eRender>		: Capture Audio Output Stream
*		CAudioCaptureT<eCapture>	: Capture Audio Input Stream
*/

#pragma once

#include "CaptureEvent.h"
#include <mmdeviceapi.h>
#include <Audioclient.h>
#include <process.h>
#include <avrt.h>

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

namespace
{
	typedef struct
	{
		HANDLE hEventStarted;
		HANDLE hEventStop;
		ICaptureEvent *pEventHandle;
		IMMDevice *pDevice;
	}capture_thread_data;

	template<int _iDataFlow>
	struct TaskNameT{};

	template<>
	struct TaskNameT<eRender>
	{
		static wchar_t * Get()
		{
			return L"Capture";
		}
	};

	template<>
	struct TaskNameT<eCapture>
	{
		static wchar_t * Get()
		{
			return L"Audio";
		}
	};

	template<int _iDataFlow>
	struct StreamFlagT{};

	template<>
	struct StreamFlagT<eRender>
	{
		static int Get()
		{
			return AUDCLNT_STREAMFLAGS_LOOPBACK;
		}
	};

	template<>
	struct StreamFlagT<eCapture>
	{
		static int Get()
		{
			return 0;
		}
	};
}

template<int _iDataFlow>
class CAudioCaptureT
{
public:
	CAudioCaptureT();
	~CAudioCaptureT();

	bool Init(ICaptureEvent *pHandler);
	void UnInit();
	bool Start();
	void Stop();

	bool IsCapturing() const;
	bool IsInit() const;

private:
	static IMMDevice * _GetDefaultDevice();
	static UINT _CaptureAudio(IMMDevice *pDevice, HANDLE hEventStarted, HANDLE hEventStop, ICaptureEvent *pEventHandle);
	static UINT __stdcall _CaptureThreadProc(LPVOID param);

private:
	bool   m_bInited;

	HANDLE m_hEventStarted;
	HANDLE m_hEventStop;
	HANDLE m_hThreadCapture;

	IMMDevice *m_pDevice;
	ICaptureEvent *m_pEventHandler;
};

template<int _iDataFlow>
CAudioCaptureT<_iDataFlow>::CAudioCaptureT() :
m_bInited(false),
m_hEventStarted(nullptr),
m_hEventStop(nullptr),
m_hThreadCapture(nullptr),
m_pDevice(nullptr),
m_pEventHandler(nullptr)
{
}

template<int _iDataFlow>
CAudioCaptureT<_iDataFlow>::~CAudioCaptureT()
{
	UnInit();
}

template<int _iDataFlow>
bool CAudioCaptureT<_iDataFlow>::Init(ICaptureEvent *pHandler)
{
	if (m_bInited)
		return true;

#define checkRet(ret)	if(IS_NULLPTR(ret)) break;

	if (IS_NULLPTR(pHandler))
		return false;
	m_pEventHandler = pHandler;

	do
	{
		m_pDevice = _GetDefaultDevice();
		checkRet(m_pDevice);

		m_hEventStarted = CreateEvent(nullptr, true, false, nullptr);
		checkRet(m_hEventStarted);

		m_hEventStop = CreateEvent(nullptr, true, false, nullptr);
		checkRet(m_hEventStop);

		m_bInited = true;

	} while (0);

	if (IS_FALSE(m_bInited))
		UnInit();

	return m_bInited;
}

template<int _iDataFlow>
void CAudioCaptureT<_iDataFlow>::UnInit()
{
	m_pEventHandler = nullptr;
	SafRelease(m_pDevice);
	SafCloseHandle(m_hEventStarted);
	SafCloseHandle(m_hEventStop);
	m_bInited = false;
}

template<int _iDataFlow>
bool CAudioCaptureT<_iDataFlow>::IsCapturing() const
{
	return NOT_NULLPTR(m_hThreadCapture);
}

template<int _iDataFlow>
bool CAudioCaptureT<_iDataFlow>::IsInit() const
{
	return m_bInited;
}

template<int _iDataFlow>
bool CAudioCaptureT<_iDataFlow>::Start()
{
	if (IS_FALSE(m_bInited))
		return false;
	if (NOT_NULLPTR(m_hThreadCapture))
		return true;

	capture_thread_data data;
	data.hEventStarted = m_hEventStarted;
	data.hEventStop = m_hEventStop;
	data.pEventHandle = m_pEventHandler;
	data.pDevice = m_pDevice;

	m_hThreadCapture = (HANDLE)_beginthreadex(nullptr, 0, &_CaptureThreadProc, &data, 0, nullptr);
	if (IS_NULLPTR(m_hThreadCapture))
		return false;

	HANDLE ahWaits[2] = { m_hEventStarted, m_hThreadCapture };
	DWORD dwWaitResult = WaitForMultipleObjects(sizeof(ahWaits) / sizeof(ahWaits[0]), ahWaits, false, INFINITE);
	if (WAIT_OBJECT_0 != dwWaitResult)
	{
		Stop();
		return false;
	}

	return true;
}

template<int _iDataFlow>
void CAudioCaptureT<_iDataFlow>::Stop()
{
	if (IS_FALSE(m_bInited))
		return;

	if (NOT_NULLPTR(m_hEventStop) &&
		NOT_NULLPTR(m_hThreadCapture))
	{
		SetEvent(m_hEventStop);
		SafCloseHandle(m_hThreadCapture);
	}
}

template<int _iDataFlow>
IMMDevice * CAudioCaptureT<_iDataFlow>::_GetDefaultDevice()
{
	IMMDevice *pDevice = nullptr;

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

	hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint((EDataFlow)_iDataFlow, eConsole, &pDevice);
	SafRelease(pMMDeviceEnumerator);

	return pDevice;
}

template<int _iDataFlow>
UINT CAudioCaptureT<_iDataFlow>::_CaptureAudio(IMMDevice *pDevice, HANDLE hEventStarted, HANDLE hEventStop, ICaptureEvent *pEventHandle)
{
	HRESULT hr;
	IAudioClient *pAudioClient = nullptr;
	WAVEFORMATEX *pWfx = nullptr;
	REFERENCE_TIME hnsDefaultDevicePeriod(0);
	HANDLE hTimerWakeUp = nullptr;
	IAudioCaptureClient *pAudioCaptureClient = nullptr;
	DWORD nTaskIndex = 0;
	HANDLE hTask = nullptr;
	bool bStarted(false);

	do
	{
		hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void**)&pAudioClient);
		if (FAILED(hr))
			break;
		hr = pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, nullptr);
		if (FAILED(hr))
			break;
		hr = pAudioClient->GetMixFormat(&pWfx);
		if (FAILED(hr))
			break;
		hTimerWakeUp = CreateWaitableTimer(nullptr, false, nullptr);
		if (IS_NULLPTR(hTimerWakeUp))
			break;
		SetEvent(hEventStarted);

		pEventHandle->OnAdjustCaptureFormat(pWfx);
		hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, StreamFlagT<_iDataFlow>::Get(), 0, 0, pWfx, 0);
		if (FAILED(hr))
			break;
		hr = pAudioClient->GetService(__uuidof(IAudioCaptureClient), (void**)&pAudioCaptureClient);
		if (FAILED(hr))
			break;
		hTask = AvSetMmThreadCharacteristics(TaskNameT<_iDataFlow>::Get(), &nTaskIndex);
		if (IS_NULLPTR(hTask))
			break;

		LARGE_INTEGER liFirstFire;
		liFirstFire.QuadPart = -hnsDefaultDevicePeriod / 2;
		LONG lTimeBetweenFires = (LONG)hnsDefaultDevicePeriod / 2 / (10 * 1000);
#pragma warning(disable:4800)
		bool bOk = (bool)SetWaitableTimer(hTimerWakeUp, &liFirstFire, lTimeBetweenFires, nullptr, nullptr, false);
		if (IS_FALSE(bOk))
			break;
		hr = pAudioClient->Start();
		if (FAILED(hr))
			break;

		pEventHandle->OnCaptureStart(lTimeBetweenFires);
		bStarted = true;

		HANDLE ahWait[2] = { hEventStop, hTimerWakeUp };
		DWORD  dwWaitResult;
		UINT32 uiNextPacketSize(0);
		BYTE *pData = nullptr;
		UINT32 uiNumFramesToRead;
		DWORD dwFlags;
		while (true)
		{
			dwWaitResult = WaitForMultipleObjects(sizeof(ahWait) / sizeof(ahWait[0]), ahWait, false, INFINITE);
			if (WAIT_OBJECT_0 + 1 != dwWaitResult)
				break;				
			hr = pAudioCaptureClient->GetNextPacketSize(&uiNextPacketSize);
			if (FAILED(hr))
				break;
			if (0 == uiNextPacketSize)
				continue;
			hr = pAudioCaptureClient->GetBuffer(
				&pData,
				&uiNumFramesToRead,
				&dwFlags,
				nullptr,
				nullptr);
			if (FAILED(hr))
				break;
			if (0 != uiNumFramesToRead)
			{
				pEventHandle->OnCaptureData(pData, uiNumFramesToRead * pWfx->nBlockAlign);
			}

			pAudioCaptureClient->ReleaseBuffer(uiNumFramesToRead);
		}

	} while (0);

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

	SafRelease(pAudioCaptureClient);

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

	if (NOT_NULLPTR(hTimerWakeUp))
	{
		CancelWaitableTimer(hTimerWakeUp);
		CloseHandle(hTimerWakeUp);
		hTimerWakeUp = nullptr;
	}

	if (NOT_NULLPTR(pAudioClient))
	{
		if (IS_TRUE(bStarted))
		{
			pAudioClient->Stop();
			pEventHandle->OnCaptureStop();
		}
		pAudioClient->Release();
		pAudioClient = nullptr;
	}

	return 0;
}

template<int _iDataFlow>
UINT __stdcall CAudioCaptureT<_iDataFlow>::_CaptureThreadProc(LPVOID param)
{

	capture_thread_data *pData = (capture_thread_data*)param;

	CoInitialize(nullptr);

	UINT uiRet = _CaptureAudio(
		pData->pDevice,
		pData->hEventStarted,
		pData->hEventStop,
		pData->pEventHandle);

	CoUninitialize();
	return uiRet;
}

AudioRecord.hpp

/*
*	author: zyb
*   \brief	
*		AudioRecordT<eRender>
*		AudioRecordT<eCapture>
*/


#pragma once

#include "AudioCapture.hpp"
#include <list>

namespace
{
	typedef struct 
	{
		INT		iDataLen;
		LPBYTE	pData;
	}Audio_Data,	*PAudio_Data;

	template<int _iDataFlow>
	struct FileNameT{};

	template<>
	struct FileNameT<eRender>
	{
		static wchar_t* Get()
		{
			return L"./output.wav";
		}
	};

	template<>
	struct FileNameT<eCapture>
	{
		static wchar_t* Get()
		{
			return L"./input.wav";
		}
	};
}

template<int _iDataFlow>
class CAudioRecordT : public ICaptureEvent
{
public:
	typedef CAudioCaptureT<_iDataFlow>	CaptureType;
	typedef std::list<Audio_Data>		ListType;
	typedef typename ListType::iterator	IteratorType;
	typedef std::wstring				StrType;

public:
	CAudioRecordT();
	~CAudioRecordT();

	bool StartCapture();
	void StopCapture();
	bool IsCapturing() const;

	void SetFilePath(wchar_t* pFilePath);
	bool SaveFile();

public:
	virtual void OnCaptureStart(DWORD dwInterval) override;
	virtual void OnCaptureStop() override;
	virtual void OnAdjustCaptureFormat(WAVEFORMATEX *pFormat) override;
	virtual void OnCaptureData(LPBYTE pData, INT iDataLen) override;

private:
	void _ClearData();

private:
	CaptureType		m_Capture;
	WAVEFORMATEX*	m_pFormat;

	ListType		m_DataList;
	INT				m_iDataLen;

	StrType			m_strFilePath;
};

template<int _iDataFlow>
CAudioRecordT<_iDataFlow>::CAudioRecordT() :
m_pFormat(nullptr),
m_iDataLen(0)
{
	m_strFilePath = FileNameT<_iDataFlow>::Get();
}

template<int _iDataFlow>
CAudioRecordT<_iDataFlow>::~CAudioRecordT()
{
	_ClearData();
}

template<int _iDataFlow>
bool CAudioRecordT<_iDataFlow>::StartCapture()
{
	bool bRet = m_Capture.IsCapturing();

	if (IS_FALSE(bRet))
	{
		bRet = m_Capture.Init(this);
		if (IS_TRUE(bRet))
			bRet = m_Capture.Start();
	}

	return bRet;
}

template<int _iDataFlow>
void CAudioRecordT<_iDataFlow>::StopCapture()
{
	bool bResult = m_Capture.IsCapturing();
	if (IS_TRUE(bResult))
	{
		m_Capture.Stop();
		m_Capture.UnInit();
	}
}

template<int _iDataFlow>
bool CAudioRecordT<_iDataFlow>::IsCapturing() const
{
	return m_Capture.IsCapturing();
}

template<int _iDataFlow>
void CAudioRecordT<_iDataFlow>::_ClearData()
{
	LPBYTE p = (LPBYTE)m_pFormat;
	SafDelete_A(p);

	IteratorType itr = m_DataList.begin();
	while (itr != m_DataList.end())
	{
		delete[] itr->pData;
		itr++;
	}

	m_DataList.clear();
	m_iDataLen = 0;
}

template<int _iDataFlow>
void  CAudioRecordT<_iDataFlow>::OnCaptureStart(DWORD dwInterval)
{

}

template<int _iDataFlow>
void CAudioRecordT<_iDataFlow>::OnCaptureStop()
{

}

template<int _iDataFlow>
void CAudioRecordT<_iDataFlow>::OnAdjustCaptureFormat(WAVEFORMATEX *pFormat)
{
	_ClearData();

	int iDataLen = sizeof(WAVEFORMATEX) + pFormat->cbSize;
	LPBYTE pData = new (std::nothrow) BYTE[iDataLen];
	if (NOT_NULLPTR(pData))
	{
		memcpy_s(pData, iDataLen, pFormat, iDataLen);
		m_pFormat = (WAVEFORMATEX*)pData;
	}
}

template<int _iDataFlow>
void CAudioRecordT<_iDataFlow>::OnCaptureData(LPBYTE pData, INT iDataLen)
{
	Audio_Data item;
	item.iDataLen = iDataLen;
	item.pData = new (std::nothrow) BYTE[iDataLen];
	if (NOT_NULLPTR(item.pData))
	{
		memcpy_s(item.pData, iDataLen, pData, iDataLen);
		m_DataList.push_back(item);
		m_iDataLen += iDataLen;
	}
}

template<int _iDataFlow>
void CAudioRecordT<_iDataFlow>::SetFilePath(wchar_t* pFilePath)
{
	if (IS_NULLPTR(pFilePath))
		return;
	m_strFilePath = pFilePath;
}

///from msdn///
namespace{
	//
	//  WAV file writer.
	//
	//  This is a VERY simple .WAV file writer.
	//

	//
	//  A wave file consists of:
	//
	//  RIFF header:    8 bytes consisting of the signature "RIFF" followed by a 4 byte file length.
	//  WAVE header:    4 bytes consisting of the signature "WAVE".
	//  fmt header:     4 bytes consisting of the signature "fmt " followed by a WAVEFORMATEX 
	//  WAVEFORMAT:     <n> bytes containing a waveformat structure.
	//  DATA header:    8 bytes consisting of the signature "data" followed by a 4 byte file length.
	//  wave data:      <m> bytes containing wave data.
	//
	//
	//  Header for a WAV file - we define a structure describing the first few fields in the header for convenience.
	//
	struct WAVEHEADER
	{
		DWORD   dwRiff;                     // "RIFF"
		DWORD   dwSize;                     // Size
		DWORD   dwWave;                     // "WAVE"
		DWORD   dwFmt;                      // "fmt "
		DWORD   dwFmtSize;                  // Wave Format Size
	};

	//  Static RIFF header, we'll append the format to it.
	const BYTE WaveHeader[] =
	{
		'R', 'I', 'F', 'F', 0x00, 0x00, 0x00, 0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ', 0x00, 0x00, 0x00, 0x00
	};

	//  Static wave DATA tag.
	const BYTE WaveData[] = { 'd', 'a', 't', 'a' };
}
///

template<int _iDataFlow>
bool CAudioRecordT<_iDataFlow>::SaveFile()
{
	DWORD dwWaveFileSize = sizeof(WAVEHEADER) + sizeof(WAVEFORMATEX) + m_pFormat->cbSize + sizeof(WaveData) + sizeof(DWORD) + m_iDataLen;
	DWORD dwWaveFileNoDataSize = dwWaveFileSize - m_iDataLen;
	BYTE *pWaveFileNoData = new (std::nothrow) BYTE[dwWaveFileSize];
	BYTE *pWaveFileNoDataCopy = pWaveFileNoData;

	if (IS_NULLPTR(pWaveFileNoDataCopy))
	{
		return false;
	}

	WAVEHEADER *pWaveHeader = reinterpret_cast<WAVEHEADER *>(pWaveFileNoDataCopy);
	CopyMemory(pWaveFileNoDataCopy, WaveHeader, sizeof(WaveHeader));
	pWaveFileNoDataCopy += sizeof(WaveHeader);
	pWaveHeader->dwSize = dwWaveFileSize - (2 * sizeof(DWORD));
	pWaveHeader->dwFmtSize = sizeof(WAVEFORMATEX) + m_pFormat->cbSize;

	CopyMemory(pWaveFileNoDataCopy, m_pFormat, sizeof(WAVEFORMATEX) + m_pFormat->cbSize);
	pWaveFileNoDataCopy += sizeof(WAVEFORMATEX) + m_pFormat->cbSize;

	CopyMemory(pWaveFileNoDataCopy, WaveData, sizeof(WaveData));
	pWaveFileNoDataCopy += sizeof(WaveData);
	*(reinterpret_cast<DWORD*>(pWaveFileNoDataCopy)) = static_cast<DWORD>(m_iDataLen);

	HANDLE FileHandle = CreateFile(m_strFilePath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);

	if (FileHandle == INVALID_HANDLE_VALUE)
	{
		SafDelete_A(pWaveFileNoData)
		return false;
	}

	DWORD dwWritten = 0;
	WriteFile(FileHandle, pWaveFileNoData, dwWaveFileNoDataSize, &dwWritten, nullptr);

	for (IteratorType it = m_DataList.begin(); it != m_DataList.end(); it++)
	{
		WriteFile(FileHandle, it->pData, it->iDataLen, &dwWritten, nullptr);
	}

	CloseHandle(FileHandle);

	SafDelete_A(pWaveFileNoData);

	return true;
}

typedef CAudioRecordT<eCapture>		CInputRecord;
typedef CAudioRecordT<eRender>		COutputRecord;


使用的测试工程,下载地址:

http://download.csdn.net/download/huanongying131/10136777


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值