当前位置: 首页 > article >正文

windows 桌面采集音频

头文件:

#ifndef __CAPTURE_AUDIO__
#define __CAPTURE_AUDIO__

#include <functional>
#include <windows.h>
#pragma comment(lib, "winmm.lib")

class CaptureAudio
{
public:
	CaptureAudio();
	~CaptureAudio();

public:
	bool Init(const std::function<void(unsigned char* pPcmAudioData, long nLen)>& pFunc);
	void Uninit();

private:
	bool Capture();

private:
	static unsigned int __stdcall Process(void* args);

private:
	unsigned char* m_pAudioData = nullptr;

private:
	HANDLE m_threadRecv = INVALID_HANDLE_VALUE;
	HANDLE m_threadEvent = INVALID_HANDLE_VALUE;

private:
	WAVEHDR m_wHdr; //采集音频时包含数据缓存的结构体
	HWAVEIN m_hWaveIn;//输入设备

private:
	std::function<void(unsigned char* pPcmAudioData, long nLen)> m_pFunc;
};

#endif

源文件:

#include "CaptureAudio.h"
#include <chrono>
#include <thread>

using namespace std;

CaptureAudio::CaptureAudio()
{
	while (!m_pAudioData) {
		try{
			m_pAudioData = new unsigned char[1024 * 1024];
		}
		catch (...){}
	}
}
CaptureAudio::~CaptureAudio()
{
	if (m_pAudioData) {
		delete[]m_pAudioData;
		m_pAudioData = nullptr;
	}
}


bool CaptureAudio::Init(const std::function<void(unsigned char* pPcmAudioData, long nLen)>& pFunc)
{
	UINT nDev = waveInGetNumDevs();
	if (nDev == 0) {
		return false;
	}


	WAVEFORMATEX waveform; //采集音频的格式,结构体
	waveform.wFormatTag = WAVE_FORMAT_PCM;//声音格式为PCM
	waveform.nSamplesPerSec = 48000;//采样率,16000次/秒
	waveform.wBitsPerSample = 16;//采样比特,16bits/次
	waveform.nChannels = 1;//采样声道数,2声道
	waveform.nAvgBytesPerSec = 16000;//每秒的数据率,就是每秒能采集多少字节的数据
	waveform.nBlockAlign = 2;//一个块的大小,采样bit的字节数乘以声道数
	waveform.cbSize = 0;//一般为0
	MMRESULT hResults = waveInOpen(&m_hWaveIn, WAVE_MAPPER, &waveform, (DWORD_PTR)0, (DWORD_PTR)this, CALLBACK_NULL);//使用waveInOpen函数开启音频采集
	if (hResults != MMSYSERR_NOERROR) {
		return false;
	}

	m_threadEvent = CreateEvent(NULL, true, false, L"");
	m_threadRecv = (HANDLE)_beginthreadex(NULL, 0, Process, this, 0, NULL);

	m_pFunc = pFunc;
	return true;
}

void CaptureAudio::Uninit()
{
	if (m_threadRecv != INVALID_HANDLE_VALUE && m_threadEvent != INVALID_HANDLE_VALUE) {
		SetEvent(m_threadEvent);
		WaitForSingleObject(m_threadRecv, INFINITE);
		CloseHandle(m_threadRecv);
		CloseHandle(m_threadEvent);

		m_threadRecv = INVALID_HANDLE_VALUE;
		m_threadEvent = INVALID_HANDLE_VALUE;
	}

	waveInUnprepareHeader(m_hWaveIn, &m_wHdr, sizeof(WAVEHDR));
	waveInStop(m_hWaveIn);
	waveInClose(m_hWaveIn);
}

bool CaptureAudio::Capture()
{
	waveInUnprepareHeader(m_hWaveIn, &m_wHdr, sizeof(WAVEHDR));

	memset(m_pAudioData, 0, 1024 * 1024);
	m_wHdr.lpData = (LPSTR)m_pAudioData;
	m_wHdr.dwBufferLength = 1024 * 1024;
	m_wHdr.dwBytesRecorded = 0;
	m_wHdr.dwUser = 0;
	m_wHdr.dwFlags = WHDR_DONE;
	m_wHdr.dwLoops = 1;
	waveInPrepareHeader(m_hWaveIn, &m_wHdr, sizeof(WAVEHDR));//准备一个波形数据块头用于录音
	waveInAddBuffer(m_hWaveIn, &m_wHdr, sizeof(WAVEHDR));//指定波形数据块为录音输入缓存
	MMRESULT hResults = waveInStart(m_hWaveIn);//开始录音
	if (hResults != MMSYSERR_NOERROR) {
		return false;
	}
	std::this_thread::sleep_for(std::chrono::milliseconds(100));

	waveInReset(m_hWaveIn);

	if (m_pFunc) {
		m_pFunc(m_pAudioData, m_wHdr.dwBytesRecorded);
	}

	return true;
}

unsigned int CaptureAudio::Process(void* args)
{
	CaptureAudio* pThis = (CaptureAudio*)args;

	while (true) {
		if (WaitForSingleObject(pThis->m_threadEvent, 0) == WAIT_OBJECT_0) {
			break;
		}
		pThis->Capture();
	}
	return 0;
}

生成的文件pcm:

 


http://www.kler.cn/news/329745.html

相关文章:

  • SpringBoot启动过程简述 和 SpringCloud 的五大组键
  • Vue下载pubsub-js中错误问题解决
  • Unity角色控制及Animator动画切换如走跑跳攻击全流程详解
  • 爬取元气手机壁纸简单案例(仅用于教学,禁止任何非法获利)
  • Activiti7 工作流引擎学习
  • 【文心智能体 | AI大师工坊】如何使用智能体插件,完成一款旅游类智能体的开发,来体验一下我的智能体『​​​​​​​厦门CityWalk』
  • ②无需编程 独立通道 Modbus主站EtherNet/IP转ModbusRTU/ASCII工业EIP网关串口服务器
  • WebRTC Connection Negotiate解决
  • 遥感图像语义分割数据集制作(使用ArcGIS Pro)
  • C++中substr用法记录
  • 开源链动2+1模式、AI智能名片与S2B2C商城小程序在精准选品与定位决策中的应用
  • 大数据毕业设计选题推荐-广东旅游数据分析系统-Hive-Hadoop-Spark
  • 问:JAVA中阻塞队列的概念、原理及使用场景?
  • springboot基于Vue的电影在线预定与管理系统
  • C0012.Clion改用VS编译器开发Qt界面
  • TCP的第三次握手没有回复,会出现哪些问题现象
  • Python | Leetcode Python题解之第448题找到所有数组中消失的数字
  • Go语言接口的基本概念
  • Qt-QTableWidget多元素控件(37)
  • element-ui 通过按钮式触发日期选择器
  • 【流计算】流计算概论
  • 如何安装和设置 Go 版本的 fabric AI 工作流框架?
  • MySQL基础篇 - 多表查询
  • Jmeter生成JWT token
  • 海外媒体投稿:如何运用3种国内外媒体套餐发稿突出重围?
  • 注册安全分析报告:人民卫生音像
  • profile-spec-ref元素
  • 【JavaEE】——线程池大总结
  • 代码随想录算法训练营DAY10之动态规划(二)背包问题
  • 什么是 Supply chain attack(供应链攻击)