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

[WASAPI]音频API:从Qt MultipleMedia走到WASAPI,相似与不同

[WASAPI] 从Qt MultipleMedia 来看WASAPI

最近在学习有关Windows上的音频驱动相关的知识,在正式开始说WASAPI之前,我想先说一说Qt的Multiple Media,为什么呢?因为Qt的MultipleMedia实际上是WASAPI的一层封装,它在是线上替我做了很多事,就好像在Microsoft的文档上会推荐你先学习Windows.Media.Capture,然后再看low level的WASAPI。

我这篇文章中,一方面是我Qt MultipleMedia用的比较多,另一方面,Qt MultiMedia也比较简单,为音频相关的API做了很多封装,这样就不需要你自己一个个HRESULT的去调试和测试了。

Qt MultiMedia Audio Recorder

由于Qt在5进6之后对Qt MultiMedia进行了大范围重构,所以这里Qt的项目我做了两个版本,分别为
audio-record-qt

audio-record-qt6

在调用上,Qt6和Qt5没有本质区别,所以这里我将着重聊一聊qt5上的录音机

在Qt5中,录音机的数据流如图所示:

在这里插入图片描述

流程大概如下:

  1. 获取所有设备的信息
  2. 根据名称匹配,获取我们需要的那个设备的QAudioDeviceInfo
  3. 使用QAudioDeviceInfo,获取到QAudioInput(输入)和QAudioOutput(输出)设备
  4. 重写一个QIODevice类,修改其writeData方法,并在其中完成你想要做的事情,包括但不限于:保存为文件,获得耳返数据,进行算法的处理等等。
  5. 将你继承了QIODevice的类的成员变量,放进QAudioInput和QAudioOutput的start中,这样一个完整的流就完成了。

其实WASAPI实际上也就是沿着这个Qt的MultiMedia的思路进行开发就可以了,但是在WASAPI中,没有Qt的封装,接口上会更加复杂一点而已。但是总的流程并没有本质区别。

还有需要注意的一点,就是QIODevice和QByteArray对数据流的封装做的很好,在纯C++中只能自己手动管理,所以这个地方可能会出现内存泄漏的风险,在开发的时候需要多多注意内存泄漏的问题。

WASAPI Audio Recorder

工程地址:
LeventureQys/Windows_Audio_Driver/WASAPI_Testbench

在WASAPI中,和Qt的MultiMedia中大的流程是一样的,但是在接口上来说往往更加复杂,简单的来说,流程大致如下:

在这里插入图片描述

其中和QtMultiMedia中最重要的区别就是没有一个专门的QIODevice去帮我处理线程和数据的关系,而是需要自己单开一个线程,然后从Capture/Render实例中去GetBuffer,然后从中获取数据或者往里面写入数据,再手动释放。

这个过程非常自由,同样也非常容易出现意外,所以在操作WASAPI的过程中需要谨慎谨慎再谨慎。

具体的代码详情见Github链接 LeventureQys/Windows_Audio_Driver/WASAPI_Testbench 我这里只简单说说我在工程中遇到的几个小问题。

  1. 输入设备的IAudioClient Initialize方法失败

我的调用函数如下:

hr = this->ptr_audio_client->Initialize(AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,AUDCLNT_STREAMFLAGS_EVENTCALLBACK,hnsDefaultDevicePeriod,hnsDefaultDevicePeriod,format_wav,NULL);

在这个函数中,第二个参数我设置的是AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK 这个地方具体要取决于设备是否允许进行回环录制和是否允许回调,并不是所有麦克风都支持这俩。

  1. 录制后的声音播放出来有很强的噪音,但我能确定声音是从麦克风传来的。

这种情况大概率是两边的声音没有对齐,这个根据wav的编码方式来的。简单地说,就是两边的channel和bitrate不匹配,导致声音无法对齐。具体你需要比对这两个format,然后再根据实际情况在音频处理处做应对和调整

WAVEFORMATEX* format_wav = NULL;
hr = ptr_audio_client->GetMixFormat(&format_wav);
if (FAILED(hr)) throw std::exception("Cant Get Mix Format!");WAVEFORMATEX* format_wav_output = NULL;
hr = ptr_output_audio_client->GetMixFormat(&format_wav_output);
if (FAILED(hr)) throw std::exception("Cant Get Mix Format Output!");

具体怎么调整详情可以看

[音视频学习笔记]二、什么是PCM音频?一些常见的PCM处理

比如我这里,我的麦克风的channels是1,但是耳机的channels是2,所以这里在播放的时候需要调整一下,将每一个bit都复制一份,放到输出的音频流中,如代码所示:

BYTE* pRenderData;
hr = ptr_output_audio_client_render->GetBuffer(numFramesAvailable, &pRenderData);
if (FAILED(hr)) {std::cerr << "GetBuffer (render) failed: " << hr << std::endl;return hr;
}
float* inputData = reinterpret_cast<float*>(pData);
float* outputData = reinterpret_cast<float*>(pRenderData);for (UINT32 i = 0; i < numFramesAvailable; i++) {// 将单声道复制到立体声的两个通道outputData[i * 2] = inputData[i];outputData[i * 2 + 1] = inputData[i];
}
到立体声的两个通道outputData[i * 2] = inputData[i];outputData[i * 2 + 1] = inputData[i];
}

相关文章:

[WASAPI]音频API:从Qt MultipleMedia走到WASAPI,相似与不同

[WASAPI] 从Qt MultipleMedia 来看WASAPI 最近在学习有关Windows上的音频驱动相关的知识&#xff0c;在正式开始说WASAPI之前&#xff0c;我想先说一说Qt的Multiple Media&#xff0c;为什么呢&#xff1f;因为Qt的MultipleMedia实际上是WASAPI的一层封装&#xff0c;它在是线…...

【畅购商城】微信支付之支付模块

目录 支付页面 接口 后端实现 前端实现​​​​​​​ ​​​​​​​支付页面 步骤一&#xff1a;创建 flow3.vue组件 步骤二&#xff1a;引入第三方资源&#xff08;js、css&#xff09; <script> import TopNav from ../components/TopNav import Footer from …...

网络安全专有名词详解_2

57.Webshell 就是以ASP、php、jsp、cgi等网页文件形式存在的一种命令执行环境&#xff0c;也叫做网页的后门&#xff0c;可以上传下载文件&#xff0c;查看数据库和执行任意的程序命令等。 58.跨站攻击 XSS&#xff0c;是指攻击者利用网站程序对用户输入过滤不足&#xff0c;输…...

【传感器技术与应用】第2章 基本电量传感器,电位器式传感器,电感式传感器,电容式传感器

注作者了解更多 我的其他CSDN专栏 毕业设计 求职面试 大学英语 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数…...

【day20】集合深入探讨

模块19回顾 在深入探讨模块20之前&#xff0c;让我们回顾一下day19中的关键内容&#xff1a; Collection集合&#xff1a;单列集合的顶级接口&#xff0c;提供了add、addAll、clear、size、isEmpty、remove、toArray、contains等方法。迭代器&#xff08;Iterator&#xff09…...

【英语语法】用must表对过去推测时,要用完成时must have been / must have done(不能直接用过去时)

文章目录 疑问解释1. 表达过去的推测2. 与时态一致3. 语法结构的限制4. 例子对比总结 疑问 This must have been a year-round activity as no structures have been found which would have been used to shelter animals in the winter. 为什么must表示对过去推测要用完成时&…...

数值计算期末考试重点(一)(黄云清版教材)

1.误差的分类 2.绝对误差和绝对误差限 3.绝对误差和绝对误差限 例题&#xff08;课后习题1.2&#xff09; 4.有效数字 例题&#xff08;课后习题1.6&#xff09; 5.算法的数值稳定性 例题&#xff08;课后习题1.9&#xff09; 这个手算比较艰难&#xff0c;还是给计算机算吧&am…...

使用 pushy 热更新后 sentry 不能正常显示源码

问题 使用 Android Studio 打包后&#xff0c;上传使用 sentry 官网命令打包的 sourcemap 文件&#xff0c;sentry能正常显示异常位置源码。 使用 pushy 热更新之后&#xff0c;sentry 不能正常显示异常位置的源代码。 如下图&#xff1a; 问题原因&#xff1a; 使用 pushy …...

IntelliJ IDEA 远程调试

IntelliJ IDEA 远程调试 在平时开发 JAVA 程序时&#xff0c;在遇到比较棘手的 Bug 或者是线上线下结果不一致的情况下&#xff0c;我们会通过打 Log 或者 Debug 的方式去定位并解决问题&#xff0c;两种方式各有利弊&#xff0c;今天就简要介绍下如何通过远程 Debug 的情况下…...

Java实现简单爬虫——爬取疫情数据

1.项目准备 在项目中使用到了jsoup和fastjson jsoup用于创建一个连接(绘画) 用于获取和解析HTML页面 而fastjson对数据进行一个格式化 在pom.xml导入坐标 <dependencies><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</a…...

大数据技术-Hadoop(一)Hadoop集群的安装与配置

目录 一、准备工作 1、安装jdk&#xff08;每个节点都执行&#xff09; 2、修改主机配置 &#xff08;每个节点都执行&#xff09; 3、配置ssh无密登录 &#xff08;每个节点都执行&#xff09; 二、安装Hadoop&#xff08;每个节点都执行&#xff09; 三、集群启动配置&a…...

04.HTTPS的实现原理-HTTPS的混合加密流程

04.HTTPS的实现原理-HTTPS的混合加密流程 简介1. 非对称加密与对称加密2. 非对称加密的工作流程3. 对称加密的工作流程4. HTTPS的加密流程总结 简介 主要讲述了HTTPS的加密流程&#xff0c;包括非对称加密和对称加密两个阶段。首先&#xff0c;客户端向服务器发送请求&#xf…...

flutter插件开发-ios

flutter插件开发是一个重要的技能&#xff0c;拓展flutter与原生的通信&#xff0c;将一些公用的东西封装&#xff0c;给不同的项目使用。 阅读前置&#xff1a; flutter基本通道调用 objective-c基础语法 ios项目基础知识 目录 1、创建一个插件项目2、项目结构3、编写原生代码…...

【AI日记】24.12.29 kaggle 比赛 2-17

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 工作 参加&#xff1a;kaggle 比赛 Regression with an Insurance Dataset时间&#xff1a;6 小时 读书 书名&#xff1a;教育的本质时间&#xff1a;1 小时 律己 工作时间&#xff1a;优作息&#xff1a…...

设计模式-创建型-工厂方法模式

什么是工厂方法模式&#xff1f; 工厂方法模式&#xff08;Factory Method Pattern&#xff09;是 创建型设计模式之一&#xff0c;目的是通过定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪个类。简而言之&#xff0c;工厂方法模式通过延迟对象的创建过程到子类来…...

解决opencv在windows环境下读取中文图片名问题

在Windows系统下&#xff0c;cv2读取中文图片名时可能会报错&#xff0c;主要是因为OpenCV的imread函数在处理文件路径时&#xff0c;默认使用的是系统的编码格式&#xff0c;而Windows的默认编码可能与文件名的编码不匹配。具体原因包括&#xff1a; 编码不匹配&#xff1a;Wi…...

Apache Commons Pool :介绍与使用

Apache Commons Pool &#xff1a;介绍与使用 什么是 commons-pool2&#xff1f; commons-pool2 是 Apache Commons 提供的一个开源对象池实现框架。它旨在为应用程序提供通用的对象池支持&#xff0c;方便开发者管理资源&#xff08;如数据库连接、网络连接等&#xff09;复…...

sentinel-请求限流、线程隔离、本地回调、熔断

请求限流&#xff1a;控制QPS来达到限流的目的 线程隔离&#xff1a;控制线程数量来达到限流的目录 本地回调&#xff1a;当线程被限流、隔离、熔断之后、就不会发起远程调用、而是使用本地已经准备好的回调去提醒用户 熔断&#xff1a;熔断也叫断路器&#xff0c;当失败、或者…...

微信小程序 app.json 配置文件解析与应用

目录 一、什么是 app.json&#xff1f; 二、app.json 文件的基本结构 三、详细解析 app.json 配置项 1. pages&#xff1a;小程序页面路径配置 2. window&#xff1a;窗口样式配置 3. tabBar&#xff1a;底部标签栏配置 4. networkTimeout&#xff1a;网络请求超时配置 …...

C语言-共用体(联合体)

1.共用体(联合体) 1.共用体union是一个能在同一个存储空间存储不同类型数据的类型 2.共用体所占的内存长度等于其最长成员的长度。 3.同一内存段可以用来存放几种不同类型的成员&#xff0c;但每一瞬时只有一种起作用 4.共用体变量中起作用的成员是最后一次存放的成员&#xff…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...