webrtc音频模块(三) windows Core Audio API及声音的播放

在前面介绍了ADM(Audio Device Module),它用于抽象音频设备管理和音频数据采集/播放接口。windows的实现是AudioDeviceWinowCode,它封装了Core Audio APIs实现了对音频设备的操作。

Core Audio APIs

windows提供了多种音频操作API,比如最常用的是 waveXxx系列API,DirectSound等。而Core Audio APIs是这些API的基础,这些API使用Core Audio APIs提供了更通用的功能。

如下图是Core Audio APIs的架构图:

  • Core Audio APIs是一些高阶API(例如MME,DirectSound等)的基础。
  • 箭头的方向表示了音频数据的流向。
  • 它有两种工作模式,共享模式和独占模式。共享模式就是大家(多个应用程序)同时播放声音(声音被混音),独占模式就是只能有一个程序播放,我一播,就没其他程序的声音了。
  • 共享模式下,会有一个Audio Service进行协调各应用程序间的音频数据处理。这个很容易理解,多路声音,总该需要一个大管家来协调使用设备。
  • 独占模式下,音频数据就直接到内核的驱动了。

Core Audio APIs特点是音频处理更高效,延时更低。对webrtc 这种RTC系统来说,正是需要其低延时的保证。

它四类子API

从上图中可以看到Core Audio APIs是一系列API的集合,它包括四类子API。

  • MMDevice API(用于检索播放采集设备)

用于应用程序检索音频终端设备,枚举出所有可使用的音频设备属性及确定其功能,并为这些设备创建驱动程序实例,是最基本的Core Audio API,服务于其它3个APIs。


  • WASAPI(控制播放和采集流)

应用程序可以通过它管理程序和音频终端设备之间音频数据的流。比如采集,回放音频。


  • DeviceTopology API(webrtc中没用到)

应用程序可以遍历音频适配器设备和音频终端设备的内部拓扑,并单步执行将设备链接到另一台设备的连接。通过 DeviceTopology API 中的接口和方法,客户端程序可直接沿着音频适配器 (audio adapters) 的硬件设备里的数据通道进入布局特征(例如,沿着音频终端设备的数据路径上进行音量控制) 。

  • EndpointVolume API(控制音量)

应用程序可以控制和监视音频终端设备的音量。

它们都以COM组件的方式提供,应用程序需要创建对应COM组件的实例,获取接口对象,再使用它们提供的方法。

AudioDeviceWindowCore

在webrtc中使用Core Audio APIs以下四个功能:

  1. 检索音频回放设备。
  2. 检索音频采集设备。
  3. 使用指定的音频设备回放声音。
  4. 使用指定的音频设备采集声音。
  5. 音频回放。
  6. 音频采集。

类图如下:

它直接管理Core Audio APIs的COM对象

**I**开头的都是对象接口类:

  • IMMDevice代表一个音频设备。
  • IMMDeviceCollection音频设备集。
  • IMMDeviceEnumerator用于枚举音频设备。
  • IMMEndpoint代表一个音频终端设备。

功能实现

检索音频设备

如下图,系统中一般都会有扬声器和麦克风,在声音设置中可以看到它们。

AudioDeviceWindowCore::Init方法中实现检索回放和采集设备,需要使用的接口对象是IMMDeviceEnumerator,检索出来的结果保存在 IMMDeviceCollection对象中。

音频设备有名字,音频参数(如:声道数,采样率等)等属性,这些都会一并获取到。

IMMDeviceCollection* pCollection = NULL;
hr = _ptrEnumerator->EnumAudioEndpoints(dataFlow,  // data-flow direction (input parameter)DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_UNPLUGGED,&pCollection);
hr = pCollection->GetCount(&count);
for (ULONG i = 0; i < count; i++)  {//遍历每个设备,获取对应的属性
}

调用EnumAudioEndpoints方法检索指定状态的设备,通过GetCount获取数量,再遍历设备获取属性。

播放声音
指定回放设备

首先要指定要使用的回放设备,通过序号指定,在IMMDeviceCollection中检索,通过index获取到IMMDevice对象,它就代表了一个音频设备。

回放声音需要使用WASAPI模块的IAudioClient接口,它通过IMMDevice获取

hr = _ptrDeviceOut->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL,(void**)&_ptrClientOut);
根据设备支持的音频参数,确定一个输出格式。

音频,有采样率,声道,位率这些参数,不同的值决定了声音的质量及数据大小。WASAPI中用这个结构体来描述

在回放声音时,要指定这些参数,就是告诉WASAPI怎么去播放声音,但是首先要知道的是,音频设备支持怎样的播放参数。

hr = _ptrClientOut->GetMixFormat(&pWfxOut);

获取到的信息如下:

[017:755][95740] (audio_device_core_win.cc:1851): Audio Engine’s current rendering mix format:

[017:755][95740] (audio_device_core_win.cc:1853): wFormatTag : 0xfffe (65534)

[017:755][95740] (audio_device_core_win.cc:1857): nChannels : 2

[017:755][95740] (audio_device_core_win.cc:1859): nSamplesPerSec : 48000

[017:755][95740] (audio_device_core_win.cc:1861): nAvgBytesPerSec: 384000

[017:755][95740] (audio_device_core_win.cc:1863): nBlockAlign : 8

[017:755][95740] (audio_device_core_win.cc:1865): wBitsPerSample : 32

[017:755][95740] (audio_device_core_win.cc:1866): cbSize : 22

在webrtc中以采用率及声道数为标准现找一个与需求最贴合的参数,如下信息:

[017:802][95740] >>>>

[017:802][95740] (audio_device_core_win.cc:1927): VoE selected this rendering format:

[017:802][95740] (audio_device_core_win.cc:1928): wFormatTag : 0x1 (1)

[017:802][95740] (audio_device_core_win.cc:1931): nChannels : 2

[017:802][95740] (audio_device_core_win.cc:1932): nSamplesPerSec : 48000

[017:802][95740] (audio_device_core_win.cc:1933): nAvgBytesPerSec : 192000

[017:802][95740] (audio_device_core_win.cc:1934): nBlockAlign : 4

[017:802][95740] (audio_device_core_win.cc:1935): wBitsPerSample : 16

[017:802][95740] (audio_device_core_win.cc:1936): cbSize : 0

[017:802][95740] (audio_device_core_win.cc:1937): Additional settings:

[017:802][95740] (audio_device_core_win.cc:1938): _playAudioFrameSize: 4

[017:802][95740] (audio_device_core_win.cc:1939): _playBlockSize : 480

[017:802][95740] (audio_device_core_win.cc:1940): _playChannels : 2

确定了这些参数,就可以确定喂入设备的音频数据量大小。

获取流输出控制接口IAudioRenderClient

通过IAudioClient获取IAudioRenderClient,它就是控制音频流的接口。

hr = _ptrClientOut->GetService(__uuidof(IAudioRenderClient),(void**)&_ptrRenderClient);

相关代码在AudioDeviceWindowsCore::InitPlayout方法中。

播放

在webrtc使用的Core Audio API的共享模式,在共享模式下将会有一个Audio Service(在上面的图中可以看出来),应用程序将通过Enpoint Buffer与Service交互。

播放声音,就是往这个buffer中写入音频数据,应用程序写入数据,Audio Service读取数据。

一端写,一端读,就需要判断buffer的空间,所以需要程如下几步:

  • 先通过IAudioClientGetBufferSize接口获取buffer大小。
  • 再通过IAudioClientGetCurrentPadding接口,获取buffer待Audio Service的处理的数据。
  • 计算可用空间:buffer size - padding data size 就是buffer中可用的空间。
  • 通过IAudioRenderClientGetBuffer接口获取buffer的地址。
  • 往buffer中写数据。

完整的流程可以看看AudioDeviceWindowsCore::DoRenderThread()方法。

需要注意一点,这里的buffer size不是以字节为单位,而是以audio frame为单位,通过API获取的是buffer可存放的audio frame数,及可用的frame空间。

audio frame的大小由采样率和采样时长决定,在webrtc中以10ms作为采样时长,那么48000HZ的采样率,一个audio frame的大小就是480采样点(换算成字节数:每个采样点2个字节,10ms的数据960个字节)。

播放线程

音频数据是不停的往Audio Service的buffer中写入,webrtc通过一个线程实现取应用层音频数据到写入buffer流程,如下流程图:

播放线程不会停,会持续不断的取数据,写入Audio Service Buffer,线程对应的方法为 AudioDeviceWindowsCore::DoRenderThread()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/494928.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在linux系统的docker中安装GitLab

一、安装GitLab&#xff1a; 在安装了docker之后就是下载安装GitLab了&#xff0c;在linux系统中输入命令&#xff1a;docker search gitlab就可以看到很多项目&#xff0c;一般安装第一个&#xff0c;它是英文版的&#xff0c;如果英文不好可以安装twang2218/gitlab-ce-zh。 …

uniapp跨平台开发---webview调用app方法

1.app端实现 注意:为了实现实时通信,app端页面是.nvue 代码实现 <template><view class"content"><view class"web-view"><web-view class"web-view" :src"url" ref"webview" onPostMessage"o…

LeetCode 343.整数拆分

1.题目要求: 2.题目代码: class Solution { public:int integerBreak(int n) {//先确定dp数组vector<int> dp;//1.确定dp数组的含义//2.确定dp的递推公式//3.初始化dp数组//4.遍历顺序dp.resize(n 1);dp[0] 0;dp[1] 0;dp[2] 1;for(int i 3;i < n;i){for(int j …

【Linux探索学习】第二十三弹——理解文件系统:认识硬件、探索文件在硬件上的存储问题

Linux学习笔记&#xff1a;https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 我们前面讲过了文件的组成是由文件内容和文件属性两者组成的&#xff0c;但是我们前面接触的文件都是系统中的文件&#xff0c;都是已经在进…

Flask中@app.route()的methods参数详解

诸神缄默不语-个人CSDN博文目录 在 Flask 中&#xff0c;app.route 是用于定义路由的核心装饰器&#xff0c;开发者可以通过它为应用指定 URL 映射及相应的处理函数。在处理 HTTP 请求时&#xff0c;不同的业务场景需要支持不同的 HTTP 方法&#xff0c;而 app.route 的 metho…

工业相机镜头选型知识详解

工业相机在机器视觉、自动化生产和检测等领域扮演着重要角色&#xff0c;而镜头作为工业相机的关键组件&#xff0c;其选型直接影响到成像效果和系统的整体性能。在本篇博客中&#xff0c;我们将详细讲解工业相机镜头选型的相关知识&#xff0c;帮助您在实际应用中选择最合适的…

羊城杯2020 easycon

打开是这样一个页面&#xff0c;这样情况一般先想到的就是目录扫描了 好吧&#xff0c;不知道为什么gobuster扫不出来 dirsearch扫出个index.php和index.php/login&#xff0c;都访问一下 提醒我这个文件有一句话木马 怪怪的&#xff0c;不知道为什么weevely连接不上 蚁剑吧&am…

顶顶通呼叫中心中间件mod_cti模块安全增强,预防盗打风险(mod_cti基于FreeSWITCH)

文章目录 前言联系我们mod_cti版本支持安全加强说明 前言 FreeSWITCH暴露在公网最大的风险就是被不法之人盗打 出现盗打的主要原因以下几点&#xff1a; 分机密码太简单或者密码泄露了拨号方案配置不合理sofia配置错误 所以我们给顶顶通呼叫中心中间件添加了安全加强功能&am…

面试基础篇---迭代器,yield, tcp, 等

1.谈谈python的装饰器&#xff0c;迭代器&#xff0c;yield&#xff1f; 迭代器在内存中通常是一次性遍历的&#xff0c;也就是说&#xff0c;一旦遍历完所有元素&#xff0c;它就会停止工作&#xff0c;不可再用。 惰性计算&#xff1a;生成器按需生成数据&#xff0c;即只有在…

软件测试之测试用例

文章目录 测试用例测试用例的编写总结 测试用例 测试用例:描述测试点执行的文档(测试输入、执行条件、预期结果等) 作用 1.测试点能被精准执行 2.便于团队合作测试用例核心内容 用例编号、用例标题、所属模块、优先级、前置条件、测试步骤、测试数据、预期结果 测试用例的编写…

微机接口课设——基于Proteus和8086的打地鼠设计(8255、8253、8259)

原理图设计 汇编代码 ; I/O 端口地址定义 IOY0 EQU 0600H IOY1 EQU 0640H IOY2 EQU 0680HMY8255_A EQU IOY000H*2 ; 8255 A 口端口地址 MY8255_B EQU IOY001H*2 ; 8255 B 口端口地址 MY8255_C EQU IOY002H*2 ; 8255 C 口端口地址 MY8255_MODE EQU IOY003H*2 ; …

I.MX6U 启动方式详解

一、启动方式选择 BOOT 的处理过程是发生在 I.MX6U 芯片上电以后,芯片会根据 BOOT_MODE[1:0]的设置 来选择 BOOT 方式。 BOOT_MODE[1:0]的值是可以改变的,有两种方式,一种是改写 eFUSE(熔 丝),一种是修改相应的 GPIO 高低电平。第一种修改 eFUSE 的方式只能修改一次,后面就…

下载运行Vue开源项目vue-pure-admin

git地址&#xff1a;GitHub - pure-admin/vue-pure-admin: 全面ESMVue3ViteElement-PlusTypeScript编写的一款后台管理系统&#xff08;兼容移动端&#xff09; 安装pnpm npm install -g pnpm # 国内 淘宝 镜像源 pnpm config set registry https://registry.npmmirror.com/…

springboot-starter版本升级es版本问题

一、背景说明 版本漏洞处理&#xff0c;springboot版本升级&#xff0c;es版本暂不升级&#xff0c;但是pom引用中es版本一直为7.17.15高版本&#xff0c;不想显示声明版本&#xff0c;定位具体问题&#xff0c;最后还是重新定义了版本进行处理。 二、异常情况 这里看4.4.18是…

模型优化之知识蒸馏

文章目录 知识蒸馏优点工作原理示例代码 知识蒸馏优点 把老师模型中的规律迁移到学生模型中&#xff0c;相比从头训练&#xff0c;加快了训练速度。另一方面&#xff0c;如果学生模型的训练精度和老师模型差不多&#xff0c;相当于得到了规模更小的学生模型&#xff0c;起到模…

Hadoop集群(HDFS集群、YARN集群、MapReduce​计算框架)

一、 简介 Hadoop主要在分布式环境下集群机器&#xff0c;获取海量数据的处理能力&#xff0c;实现分布式集群下的大数据存储和计算。 其中三大核心组件: HDFS存储分布式文件存储、YARN分布式资源管理、MapReduce分布式计算。 二、工作原理 2.1 HDFS集群 Web访问地址&…

使用 acme.sh 申请域名 SSL/TLS 证书完整指南

使用 acme.sh 申请域名 SSL/TLS 证书完整指南 简介为什么选择 acme.sh 和 ZeroSSL&#xff1f;前置要求安装过程 步骤一&#xff1a;安装 acme.sh步骤二&#xff1a;配置 ZeroSSL 证书申请 方法一&#xff1a;手动 DNS 验证&#xff08;推荐新手使用&#xff09;方法二&#xf…

# 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)

↑ 上方下载文档 (大小374KB) 接口文档预览 (超过50个接口) 一、数据库25张表er-关系清晰构图&#xff01;(tip: 鼠标右键图片 > 放大图像) 二、难点/经验 详细说明 热门评论排序评论点赞列表|DTO封装经验分享|精华接口文档说明 组员都说喜欢分档对应枚举码 如果这篇文章…

掌握 Ansys ACP 中的参考方向:简化复杂的复合材料设计

概括 在复合材料分析领域&#xff0c;精度至关重要&#xff0c;尤其是在定义纤维方向和铺层时。Ansys ACP&#xff08;Ansys Composite PrepPost&#xff09;提供了强大的工具来建立参考方向&#xff0c;这是实现精确结构模拟的关键步骤。在本博客中&#xff0c;我们将揭开在 …

牵手红娘:牵手App红娘助力“牵手”,脱单精准更便捷

随着互联网的普及&#xff0c;现代青年的社交圈层加速扩大&#xff0c;他们的恋爱观也正经历着前所未有的转变。在繁忙的工作之余&#xff0c;人们希望能够找到一种既高效又真诚的交友方式。于是&#xff0c;线上交友平台成为了他们寻找爱情的新选择。让不同文化背景、不同工作…