使用WASAPI捕获声卡音频
参考文档:
- 主要的代码参考了官方文档的 Capturing a Stream 和 Loopback Recording 两篇
- WAVHead 代码参考了 C++生成简单WAV文件(三)——根据简谱生成菊花台
直接上代码
主体代码:
#include "pch.h"
#include "WAVHead.h"using namespace std;//-----------------------------------------------------------
// Record an audio stream from the default audio capture
// device. The RecordAudioStream function allocates a shared
// buffer big enough to hold one second of PCM audio data.
// The function uses this buffer to stream data from the
// capture device. The main loop runs every 1/2 second.
//-----------------------------------------------------------// REFERENCE_TIME time units per second and per millisecond
#define REFTIMES_PER_SEC 10000000
#define REFTIMES_PER_MILLISEC 10000#define EXIT_ON_ERROR(hres) \if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk) \if ((punk) != NULL) \{ (punk)->Release(); (punk) = NULL; }const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);vector<BYTE> body;
unsigned int recordCount = 20;// 2147483648;HRESULT RecordAudioStream()
{HRESULT hr;REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;REFERENCE_TIME hnsActualDuration;UINT32 bufferFrameCount;UINT32 numFramesAvailable;IMMDeviceEnumerator *pEnumerator = NULL;IMMDevice *pDevice = NULL;IAudioClient *pAudioClient = NULL;IAudioCaptureClient *pCaptureClient = NULL;WAVEFORMATEX *pwfx = NULL;UINT32 packetLength = 0;BOOL bDone = FALSE;BYTE *pData;DWORD flags;hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,IID_IMMDeviceEnumerator, (void**)&pEnumerator);EXIT_ON_ERROR(hr)hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);EXIT_ON_ERROR(hr)hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);EXIT_ON_ERROR(hr)// 因为接下来要手动指定音频格式,所以就不需要了// hr = pAudioClient->GetMixFormat(&pwfx);// EXIT_ON_ERROR(hr)WAVEFORMATEX waveFormat;waveFormat.wFormatTag = WAVE_FORMAT_PCM;waveFormat.nChannels = 2;waveFormat.nSamplesPerSec = 48000;waveFormat.nAvgBytesPerSec = 192000;waveFormat.wBitsPerSample = 16;waveFormat.nBlockAlign = 4;waveFormat.cbSize = 0;pwfx = &waveFormat;hr = pAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,AUDCLNT_STREAMFLAGS_LOOPBACK,hnsRequestedDuration, 0, pwfx, NULL);EXIT_ON_ERROR(hr)// Get the size of the allocated buffer.hr = pAudioClient->GetBufferSize(&bufferFrameCount);EXIT_ON_ERROR(hr)hr = pAudioClient->GetService(IID_IAudioCaptureClient, (void**)&pCaptureClient);EXIT_ON_ERROR(hr)// Notify the audio sink which format to use.// 如上一行注释,以下的代码是将获取到的音频格式传给另外的类(自己定义的),同样的,因为// 手动制定了音频格式,所以就不需要通知了// hr = pMySink->SetFormat(pwfx);// EXIT_ON_ERROR(hr)// Calculate the actual duration of the allocated buffer.hnsActualDuration = (double)REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;hr = pAudioClient->Start(); // Start recording.EXIT_ON_ERROR(hr)// Each loop fills about half of the shared buffer.while (bDone == FALSE && recordCount > 0){// Sleep for half the buffer duration.// 如需降低延迟,可删除以下代码Sleep(hnsActualDuration / REFTIMES_PER_MILLISEC / 2);hr = pCaptureClient->GetNextPacketSize(&packetLength);EXIT_ON_ERROR(hr)while (packetLength != 0){// Get the available data in the shared buffer.hr = pCaptureClient->GetBuffer(&pData, &numFramesAvailable, &flags, NULL, NULL);EXIT_ON_ERROR(hr)if (flags & AUDCLNT_BUFFERFLAGS_SILENT){pData = NULL; // Tell CopyData to write silence.}// Copy the available capture data to the audio sink.// 如上一行注释,以下代码是将捕获到的音频数据传给另外的类处理,因为接下// 来就要在这里处理了,所以也不需要了// hr = pMySink->CopyData(pData, numFramesAvailable, &bDone);// EXIT_ON_ERROR(hr)int dataSize = numFramesAvailable * 4;for (int i = 0; i < dataSize; i++) {BYTE tem = pData[i];body.push_back(pData[i]);}hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);EXIT_ON_ERROR(hr)hr = pCaptureClient->GetNextPacketSize(&packetLength);EXIT_ON_ERROR(hr)}recordCount--;}hr = pAudioClient->Stop(); // Stop recording.EXIT_ON_ERROR(hr)Exit:// CoTaskMemFree(pwfx);SAFE_RELEASE(pEnumerator)SAFE_RELEASE(pDevice)SAFE_RELEASE(pAudioClient)SAFE_RELEASE(pCaptureClient)return hr;
}int main() {CoInitialize(NULL);RecordAudioStream();CoUninitialize();WAVHead head;head.setSize(body.size());ofstream ocout;ocout.open("1214.wav", ios::out | ios::binary);ocout.write((char*)&head, sizeof head);for (BYTE n : body) {ocout.write((char*)&n, 1);}ocout.close();return 0;
}
pch.h
#ifndef PCH_H
#define PCH_H// TODO: 添加要在此处预编译的标头
#include <iostream>
#include <fstream>
#include <vector>#include <dshow.h>
#include <Windows.h>
#include <winerror.h>
#include <mmdeviceapi.h>
#include <Functiondiscoverykeys_devpkey.h>#include <Audioclient.h>
#include <audiopolicy.h>#endif //PCH_H
WAVHead.h
#pragma once
class WAVHead
{
public:WAVHead();~WAVHead();void setSize(int);long int getsa();long int getsize();
private:char RIFFChunkID[4]; // 4 Bytes 文档标识 long int RIFFChunkSize; // 4 Bytes 文件数据长度char Format[4]; // 4 Bytes 文件格式类型char FMTChunkID[4]; // 4 Bytes 格式快标识long int FMTChunkSize; // 4 Bytes 格式快长度short int AudioFormat; // 2 Bytes 编码格式代码short int NumChannels; // 2 Bytes 声道个数long int SampleRate; // 4 Bytes 采样频率long int ByteRate; // 4 Bytes 数据传输速率short int BlockAlign; // 2 Bytes 数据块对齐位short int BitsPerSample; // 2 Bytes 采样位数char DataChunkID[4]; // 2 Byteslong int DataChunkSize;};
WAVHead.cpp
#include "pch.h"
#include "WAVHead.h"WAVHead::WAVHead()
{strcpy(RIFFChunkID, "RIFF");RIFFChunkSize = 0;strcpy(Format, "WAVE");strcpy(FMTChunkID, "fmt ");FMTChunkSize = 16;AudioFormat = 1;NumChannels = 2;SampleRate = 48000;ByteRate = 192000;BlockAlign = 4;BitsPerSample = 16;strcpy(DataChunkID, "data");DataChunkSize = 0;
}WAVHead::~WAVHead()
{
}void WAVHead::setSize(int size) {RIFFChunkSize = size + 30;DataChunkSize = size;
}
long int WAVHead::getsa() {return SampleRate;
}
long int WAVHead::getsize() {return DataChunkSize;
}
接下来修改 RealTek HD 音频管理器 里的设置为 16位 48000Hz
关于最后一行注释掉的代码:
CoTaskMemFree(pwfx);
官方文档 CoTaskMemFree function 中说道:
Frees a block of task memory previously allocated through a call to the CoTaskMemAlloc
or CoTaskMemRealloc function.
因为 pwfx 并不是由 CoTaskMemAlloc or CoTaskMemRealloc 分配的,所以也就不用调用 CoTaskMemFree 释放。
使用WASAPI捕获声卡音频相关推荐
- WASAPI 捕获指定设备的音频
#include "stdafx.h"#include <MMDeviceAPI.h> #include <AudioClient.h> #include ...
- 主板声卡坏了会不会有电流声_拯救无声电脑,还能升级音质,独立声卡音频转接头来解决...
生活中很多微小的数码配件,它们其貌不扬,但是功能却多种多样,如果你从未见过会对它们知之甚少,但是在需要的时候会解决很大的问题,比如这款内置了独立声卡的3.5mm音频转接头,就提供了USB供电的转音频与 ...
- java录制声音(采集声卡音频数据)
采用java官方API--TargetDataLine,从声卡中采集音频数据达到录音效果,采集的数据为PCM裸流需要转为wav格式的话参照--PCM转WAV . 示例代码: import java.i ...
- android 声卡音频策略小记
5.1 以前应该是在 hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp 5.1 的时候 Android5.1/framework ...
- windows音频声卡采集
作者: 使徒保罗 邮箱:297329588szh@163.com 声明: 欢迎交流学习,如有任何疑问,请通过邮箱联系本人 环境: win10 64位+qt5.7(MINGW) 参考:[微软还回录音文档 ...
- 音频编辑开发SDK Audio DJ Studio for .NET Crack
11.7版本--Audio DJ Studio for .NET是 MultiMedia Soft 开发的 .NET Windows Forms 自定义控件,可以轻松地向使用Microsoft Vis ...
- .NET NAudio音频录制方法 2021-02-13
.NET NAudio音频录制方法 写在前面 文章主要内容 说明 检测录音电平 调节录音电平 开始录音 调整音频 保存音频 关于作者 讨论 SomeONe Clint Nate Greenwood C ...
- WDM在不同Windows版本上的音频支持
"Windows音频驱动"翻译系列总目录: https://blog.csdn.net/danteLiujie/article/details/102530417 目录 1. 实现 ...
- FFMPEG常用的一些命令介绍:音频录制、视频录制
1.视频和音频单独抓取 如果指定输入格式和设备,则ffmpeg可以直接捕获视频和音频. Linux下捕获摄像头的数据保存成视频文件: # ffmpeg -f video4linux2 -s 1280x ...
最新文章
- 什么是okr,和kpi的区别在哪里
- 五分钟搞懂MySQL索引下推
- Bypass WAF实战总结
- 写在这个公众号关注者达到7000之际,Jerry有话对大家说
- java final const_Java 中的final 和C++ 中的const 有什么区别?
- 1-算法 排序 选择排序
- Windows 10如何强制删除多余的语言包
- mysql热块争用_Oracle 索引热块引起的latch争用实例分析(转)
- C+++之insert()
- LINUX 下安装git
- ENVI学习总结(二)——基于自带定位信息的几何校正
- NPOI2.0学习(三)
- 51单片机c语言烧录软件,51单片机烧写程序的方法
- (转)【JSON工具】一个JSON格式化查看工具——HIJSON
- Python tkinter库之Canvas 根据函数解析式或参数方程画出图像
- pktgen-dpdk 进行rfc2544测试
- 收集了一下WINDDOWS VISTA密码破解的方法
- 硬盘克隆 计算机更换硬盘,换硬盘数据怎么办 看一招本地磁盘对拷
- UNIAPP nvue 地图 markers 不显示
- 在Windows 7中使用AppLocker限制对程序的访问
热门文章
- 解决方案Solution
- Hadamard积的介绍
- 【Git配置技巧】01. 配置文件git config介绍
- 正则表达式验证IP地址合法性
- Linux下的文本编辑器和Windows的编辑器
- 愉快的舞会c++_项目经理和开发人员如何才能(愉快地!)给出实际的发货日期...
- H5页面保存base64图片到本地
- 计算机教师信息化大赛作品,全国“xx杯”计算机专业类说课大赛优秀作品:信息化色彩搭配训练说课课件.ppt...
- 清除bios密码的N种方法
- 搭建指标体系的底层逻辑