WebRTC音频 03 - 实时通信框架

devtools/2024/10/23 19:25:15/

WebRTC音频01 - 设备管理
WebRTC音频 02 - Windows平台设备管理
WebRTC音频 03 - 实时通信框架(本文)
WebRTC音频 04 - 关键类
WebRTC音频 05 - 音频采集编码

一、前言:

前面介绍了音频设备管理,并且以windows平台为例子,介绍了ADM相关的类,以及必须用到的重要API,本文我们分析下,在一个音视频呼叫过程中,音频是如何参与其中的,都有哪些成员参与其中。

二、呼叫时序图:

先回顾下总体呼叫流程,由大到小分析,避免看半天代码不知道自己在哪儿!

在这里插入图片描述

可以看出,呼叫过程中,先要创建非常重要的类PeerConnection,接着进行媒体协商,最后选择进行p2p或者turn这条路;我们现在要分析,这个过程中音频要做哪些事,这件事分别是在上面总流程的哪个位置。

三、音频数据流转:

我们先猜想下,整个过程中应该做什么?是不是下图这样?

在这里插入图片描述

标注红色的就是我们关心的。

四、具体到每个音频模块

在这里插入图片描述

  • 初始化阶段(图中粉色线):

    1. 这个流程之前分析过,从Session层开始创建一个会话,就会创建一个PeerConnection,然后就是创建音频引擎,接着创建ADM;
    2. adm创建过程中会创建AudioDeviceModuleGeneric的具体对象(windows平台就是AudioDeviceWindowsCore,下文本人全都写AudioDeviceModuleGeneric,就代表AudioDeviceWindowsCore);
  • 数据发送阶段(图中绿色线):

    1. AudioDeviceModuleGeneric对象从麦克风采集到数据,并送给AudioDeviceBuffer,等待发送;
    2. 交给AudioTransport模块处理;(这里面主要是经过 AudioProcess 模块进行3A处理)
    3. 交给Call模块的 AudioSendStream;
    4. 交给ACM模块的Encoder进行编码;
    5. 交给网络模块Transport进行发送;
  • 数据接收阶段(图中蓝色线):

    1. 从网络模块接收数据,送给Call模块的队列Queue进行缓存;
    2. 慢慢交给AudioReceiveStream进行处理;
    3. 交给ACM模块的Decoder进行解码;
    4. 解码之后交给在AudioReceiveStream模块继续缓存起来;(因为音频播放有一个单独的线程,扬声器会定时来缓存里面取,而不是我们主动送)
  • 数据播放阶段(图中黑色线):

    1. AudioDeviceModuleGeneric对象调用AudioDeviceBuffer相关接口获取数据;
    2. 调用AudioTransport相关接口获取数据(这里面主要是混音模块Mixer,可能同时获得1路或者多路音频,混成1路);
    3. AudioTransport调用1个或者多个AudioReceiveStream中分别取出一定长度的PCM数据;(webrtc就是10ms)
    4. 上面三步完成了调用之后,数据就会按照AudioReceiveStream->AudioTransport(mixer)->AudioDeviceBuffer->AudioDeviceModuleGeneric对象,最终通过扬声器播放出来;

总结:

  1. Call模块是每个session一个;
  2. ADM和AudioTransport里面的AudioProcess、Mixer都是全局唯一的,因为Mixer这种是瞬间处理的,不保存数据,因此,所有的Call模块共用同一个;
  3. 使用AudioState(可以理解成引擎层的上下文)管理AudioTransport和ADM虽然增加了一层,但是对于上层使用媒体引擎的人来说就非常简单了,我只需要和AudioState打交道;

五、类图:

关键模块类图如下:

在这里插入图片描述

  • adm_:就是AudioDeviceModule,对音视频设备进行管理,比如,从麦克风采集音频,让扬声器播放数据;

  • encoder_factory_:音频编码器工厂,创建编码器时候使用;

  • decoder_factory_:音频解码器工厂;

  • audio_mixer_:音频混音器,比如将多路输入流混成一路,送给扬声器播放;

  • apm_:专门用来处理3A问题;

  • audio_state_:表面看是音频状态管理,实则为音频流的管理;

  • send_codecs:音频编码器管理;

  • recv_codecs:音频解码器管理;

  • channels:WebRtcMediaVoiceChannel的集合;一个对应SDP中一个m行;

六、关键类对象创建时机:

在我们开始呼叫音视频通话时候,点击PeerConnectionClient弹出的connect按钮时候,会调用Conductor::InitializePeerConnection(),先看看引擎的初始化时机:

在这里插入图片描述

然后再看看PeerConnectionFactory::Create再调用 ConnectionContext::Create,而ConnectionContext::Create之后主要干了下面几件事情:

在这里插入图片描述

备注:

  1. 发现扬声器和麦克风ADM这一层逻辑基本一致。

  2. 并且adm和AudioDeviceWindowsCore中间还有个传话筒AudioDeviceModuleImpl我没有画出来,就是转手调用AudioDeviceWindowsCore而已。

  3. 向adm注册一个回调 audio_state()->audio_transport,用于接收将来产生的音视频数据;

  4. 创建PeerConnectionFactory之前已经创建了四个编解码器的Factory;

  5. 构造Denpendenices的时候,就实例化了一个APM模块,并进行了初始化;

  6. 我们前面构造的MediaEngineDependencies是PeerConnectionFactoryDependencies的一个成员,使用media_engine保存;(里面主要是三大线程、call_factory、media_engine(看后面代码,这个主要是接收MediaDependecies的));

  7. 然后是创建音视频引擎;

  8. 引擎创建好之后,对引擎做一些必要的初始化CreateModularPeerConnectionFactory:

    1. 对pc_factory进行初始化;
      1. BasicNetworkManager:主要是管理网卡的;
      2. BasicPacketSocketFactory:也就是Socekt工厂,主要创建各种各样的socket;
      3. 创建ChannelManager(它是连接编解码器的),同时会调用Init,里面会调用media_engine->Init来初始化之前创建的媒体引擎;

七、总结:

本文主要是介绍了音频各个模块在整个呼叫过程中所处的角色,以及何时创建(创建时机)、创建的什么样(类图);主要从总体分析,如果要具体到每个类,后续会根据业务场景再做分析,比如:采集过程中用到哪几个类,具体调用哪个函数等等,关注我,不迷路!

扫描关注,最早拿到一手资源:
在这里插入图片描述


http://www.ppmy.cn/devtools/128225.html

相关文章

python3的基本数据类型:Number(数字)

一. 简介 本文简单学习一下 python3的一个数据类型:Number(数字)。 数字用于存储数值,python支持整型,浮点型,复数与分数。 二. python3基本数 据类型:Number(数字)…

word下宏命令添加右键菜单调用大语言模型

word开发者模式下,直接选visual basic,把代码粘贴进去,CrateSelectedTextWithAI()函数下把apikey换成你自己的密钥,我这个密钥不可用。这里调用的是月之暗面的模型(有一定免费额度),其他模型的没…

前端工具函数库

流行的前端工具函数库 lodashlodash-es:用lodash-es代替lodashes-toolkit:https://www.npmjs.com/package/es-toolkitradash:https://github.com/sodiray/radash 补充信息: antd-mobile 已不再依赖 lodash, 淘汰 lo…

前端性能优化之加载篇

前端页面加载的过程其实跟我们常常提起的浏览器页面渲染流程几乎一致: 网络请求,服务端返回 HTML 内容。 浏览器一边解析 HTML,一边进行页面渲染。 解析到外部资源,会发起 HTTP 请求获取,加载 Javascript 代码时会暂停页面渲染。 根据业务代码加载过程,会分别进入页面开始…

Golang | Leetcode Golang题解之第494题目标和

题目&#xff1a; 题解&#xff1a; func findTargetSumWays(nums []int, target int) int {sum : 0for _, v : range nums {sum v}diff : sum - targetif diff < 0 || diff%2 1 {return 0}neg : diff / 2dp : make([]int, neg1)dp[0] 1for _, num : range nums {for j …

【Next.js 项目实战系列】05-删除 Issue

原文链接 CSDN 的排版/样式可能有问题&#xff0c;去我的博客查看原文系列吧&#xff0c;觉得有用的话&#xff0c;给我的库点个star&#xff0c;关注一下吧 上一篇【Next.js 项目实战系列】04-修改 Issue 删除 Issue 添加删除 Button​ 本节代码链接 这里我们主要关注布局…

1.DBeaver连接hive数据库

1.hive开启远程服务&#xff0c;linux中直接输入&#xff1a;hiveserver2 2.解压dbeaver和hive-jdbc-2.1.1.zip 3.双击打开 4.数据库&#xff0c;新建连接 5.搜索hive 6.配置参数 7.编辑驱动设置 8.添加jar包 9.测试连接 10.右击&#xff0c;新建sql编辑器 11.执行sql 12.调整字…

Redis Search系列 - 第三讲 拼写检查

拼写检查 - Spellchecking & Dict Spellchecking为拼写错误的搜索词提供建议。例如&#xff0c;术语“reids”可能是“redis”的拼写错误版本。 从v1.4开始&#xff0c;Redis Search可以为拼写错误的查询术语&#xff08;term&#xff09;生成替代的方案。拼写错误的术语是…