应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

技术宝典WebRTCADM源码流程分析

  1、ADM基本架构1。1ADM的架构分析
  WebRTC中,ADM(AudioDeviceManager)的行为由AudioDeviceModule来定义,具体由AudioDeviceModuleImpl来实现。
  从上面的架构图可以看出AudioDeviceModule定义了ADM相关的所有行为(上图只列出了部分核心,更详细的请参考源码中的完整定义)。从AudioDeviceModule的定义可以看出AudioDeviceModule的主要职责如下:
  初始化音频播放采集设备;
  启动音频播放采集设备;
  停止音频播放采集设备;
  在音频播放采集设备工作时,对其进行操作(例如:Mute,AdjustVolume);
  平台内置3A开关的调整(主要是针对Android平台);
  获取当前音频播放采集设备各种与此相关的状态(类图中未完全体现,详情参考源码)
  AudioDeviceModule具体由AudioDeviceModuleImpl实现,二者之间还有一个AudioDeviceModuleForTest,主要是添加了一些测试接口,对本文的分析无影响,可直接忽略。AudioDeviceModuleImpl中有两个非常重要的成员变量,一个是audiodevice,它的具体类型是std::uniqueptr,另一个是audiodevicebuffer,它的具体类型是AudioDeviceBuffer。
  其中audiodevice是AudioDeviceGeneric类型,AudioDeviceGeneric是各个平台具体音频采集和播放设备的一个抽象,由它承担AudioDeviceModuleImpl对具体设备的操作。涉及到具体设备的操作,AudioDeviceModuleImpl除了做一些状态的判断具体的操作设备工作都由AudioDeviceGeneric来完成。AudioDeviceGeneric的具体实现由各个平台自己实现,例如对于iOS平台具体实现是AudioDeviceIOS,Android平台具体实现是AudioDeviceTemplate。至于各个平台的具体实现,有兴趣的可以单个分析。这里说一下最重要的共同点,从各个平台具体实现的定义中可以发现,他们都有一个audiodevicebuffer成员变量,而这个变量与前面提到的AudioDeviceModuleImpl中的另一个重要成员变量audiodevicebuffer,其实二者是同一个。AudioDeviceModuleImpl通过AttachAudioBuffer()方法,将自己的audiodevicebuffer对象传给具体的平台实现对象。
  audiodevicebuffer的具体类型是AudioDeviceBuffer,AudioDeviceBuffer中的playbuffer、recbuffer是int16t类型的buffer,前者做为向下获取播放PCM数据的Buffer,后者做为向下传递采集PCM数据的Buffer,具体的PCM数据流向在后面的数据流向章节具体分析,而另一个成员变量audiotransportcb,类型为AudioTransport,从AudioTransport接口定义的中的两个核心方法不难看出他的作用,一是向下获取播放PCM数据存储在playbuffer,另一个把采集存储在recbuffer中的PCM数据向下传递,后续具体流程参考数据流向章节。1。2关于ADM扩展的思考
  从WebRTCADM的实现来看,WebRTC只实现对应了各个平台具体的硬件设备,并没什么虚拟设备。但是在实际的项目,往往需要支持外部音频输入输出,就是由业务上层pushpull音频数据(PCM。。。),而不是直接启动平台硬件进行采集播放。在这种情况下,虽然原生的WebRTC不支持,但是要改造也是非常的简单,由于虚拟设备与平台无关,所以可以直接在AudioDeviceModuleImpl中增加一个与真实设备audiodevice对应的VirtualDevice(变量名暂定为virtualdevice),virtualdevice也跟audiodevice一样,实现AudioDeviceGeneric相关接口,然后参考audiodevice的实现去实现数据的采集(push)与播放(pull),无须对接具体平台的硬件设备,唯一需要处理的就是物理设备audiodevice与虚拟设备virtualdevice之间的切换或协同工作。
  【免费分享】音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(CC,Linux,FFmpegwebRTCrtmphlsrtspffplaysrs等等)有需要的可以后台私信扣1免费领取
  2、ADM设备的启动2。1启动时机
  ADM设备的启动时机并无什么特殊要求,只要ADM创建后即可,不过WebRTC的Native源码中会在SDP协商好后去检查一下是否需要启动相关的ADM设备,如果需要就会启动相关的ADM设备,采集与播放设备的启动二者是完全独立的,但流程大同小异,相关触发代码如下,自上而下阅读即可。
  以下是采集设备启动的触发源码(前面几步还有其他触发入口,但后面是一样的,这里只做核心流程展示):cricket::VoiceChannelvoidVoiceChannel::UpdateMediaSendRecvStatew(){boolsendIsReadyToSendMediaw();mediachannel()SetSend(send);}cricket::WebRtcVoiceMediaChannelvoidWebRtcVoiceMediaChannel::SetSend(boolsend){for(autokv:sendstreams){kv。secondSetSend(send);}}cricket::WebRtcVoiceMediaChannel::WebRtcAudioSendStreamvoidSetSend(boolsend){UpdateSendState();}cricket::WebRtcVoiceMediaChannel::WebRtcAudioSendStreamvoidUpdateSendState(){if(sendsource!nullptrrtpparameters。encodings〔0〕。active){streamStart();}else{!sendsourcenullptrstreamStop();}}webrtc::internal::WebRtcAudioSendStreamvoidAudioSendStream::Start(){audiostate()AddSendingStream(this,encodersampleratehz,encodernumchannels);}webrtc::internal::AudioStatevoidAudioState::AddSendingStream(webrtc::AudioSendStreamstream,intsampleratehz,sizetnumchannels){检查下采集设备是否已经启动,如果没有,那么在这启动autoadmconfig。audiodevicemodule。get();if(!admRecording()){if(admInitRecording()0){if(recordingenabled){admStartRecording();}}else{RTCDLOGF(LSERROR)Failedtoinitializerecording。;}}}
  从上面采集设备启动的触发源码可以看出,如果需要发送音频,不管前面采集设备是否启动,在SDP协商好后,一定会启动采集设备。如果我们想把采集设备的启动时机掌握在上层业务手中,那么只要注释上面AddSendingStream方法中启动设备那几行代码即可,然后在需要的时候自行通过ADM启动采集设备。
  以下是播放设备启动的触发源码(前面几步还有其他触发入口,但后面是一样的,这里只做核心流程展示):cricket::VoiceChannelvoidVoiceChannel::UpdateMediaSendRecvStatew(){boolrecvIsReadyToReceiveMediaw();mediachannel()SetPlayout(recv);}cricket::WebRtcVoiceMediaChannelvoidWebRtcVoiceMediaChannel::SetPlayout(boolplayout){returnChangePlayout(desiredplayout);}cricket::WebRtcVoiceMediaChannelvoidWebRtcVoiceMediaChannel::ChangePlayout(boolplayout){for(constautokv:recvstreams){kv。secondSetPlayout(playout);}}cricket::WebRtcVoiceMediaChannel::WebRtcAudioReceiveStreamvoidSetPlayout(boolplayout){if(playout){streamStart();}else{streamStop();}}webrtc::internal::AudioReceiveStreamvoidAudioReceiveStream::Start(){audiostate()AddReceivingStream(this);}webrtc::internal::AudioStatevoidAudioState::AddReceivingStream(webrtc::AudioReceiveStreamstream){检查下播放设备是否已经启动,如果没有,那么在这启动autoadmconfig。audiodevicemodule。get();if(!admPlaying()){if(admInitPlayout()0){if(playoutenabled){admStartPlayout();}}else{RTCDLOGF(LSERROR)Failedtoinitializeplayout。;}}}
  从上面播放设备启动的触发源码可以看出,如果需要播放音频,不管前面播放设备是否启动,在SDP协商好后,一定会启动播放设备。如果我们想把播放设备的启动时机掌握在上层业务手中,那么只要注释上面AddReceivingStream方法中启动设备那几行代码即可,然后在需要的时候自行通过ADM启动播放设备。2。2启动流程
  当需要启动ADM设备时,先调用ADM的InitXXX,接着是ADM的StartXXX,当然最终是透过上面的架构层层调用具体平台相应的实现,详细流程如下图:
  关于设备的停止
  了解了ADM设备的启动,那么与之对应的停止动作,就无需多言。如果大家看了源码,会发现其实停止的动作及流程与启动基本上是一一对应的。3、ADM音频数据流向3。1音频数据的发送
  上图是音频数据发送的核心流程,主要是核心函数的调用及线程的切换。PCM数据从硬件设备中被采集出来,在采集线程做些简单的数据封装会很快进入APM模块做相应的3A处理,从流程上看APM模块很靠近原始PCM数据,这一点对APM的处理效果有非常大的帮助,感兴趣的同学可以深入研究下APM相关的知识。之后数据就会被封装成一个Task,投递到一个叫rtpsendcontroller的线程中,到此采集线程的工作就完成了,采集线程也能尽快开始下一轮数据的读取,这样能最大限度的减小对采集的影响,尽快读取新的PCM数据,防止PCM数据丢失或带来不必要的延时。
  接着数据就到了rtpsendcontroller线程,rtpsendcontroller线程的在此的作用主要有三个,一是做rtp发送的拥塞控制,二是做PCM数据的编码,三是将编码后的数据打包成RtpPacketToSend(RtpPacket)格式。最终的RtpPacket数据会被投递到一个叫RoundRobinPacketQueue的队列中,至此rtpsendcontroller线程的工作完成。
  后面的RtpPacket数据将会在SendControllerThread中被处理,SendControllerThread主要用于发送状态及窗口拥塞的控制,最后数据通过消息的形式(type:MSGSENDRTPPACKET)发送到Webrtc三大线程之一的网络线程(NetworkThread),再往后就是发送给网络。到此整个发送过程结束。3。2数据的接收与播放
  上图是音频数据接收及播放的核心流程。网络线程(NetworkThread)负责从网络接收RTP数据,随后异步给工作线程(WorkThread)进行解包及分发。如果接收多路音频,那么就有多个ChannelReceive,每个的处理流程都一样,最后未解码的音频数据存放在NetEq模块的packetbuffer中。与此同时播放设备线程不断的从当前所有音频ChannelReceive获取音频数据(10ms长度),进而触发NetEq请求解码器进行音频解码。对于音频解码,WebRTC提供了统一的接口,具体的解码器只需要实现相应的接口即可,比如WebRTC默认的音频解码器opus就是如此。当遍历并解码完所有ChannelReceive中的数据,后面就是通过AudioMixer混音,混完后交给APM模块处理,处理完最后是给设备播放。
  原文链接:技术宝典WebRTCADM源码流程分析

1岁女娃吃松子摔倒卡进气管!预防婴幼儿异物梗塞,5类食物要当年节将至,家裡开始准备上瓜果类、零食及点心,大人聚在一起开心聊天之馀有时也会随手喂孩子吃,但这对咀嚼功能仍未发育完全的孩子却并不安全,尤其1岁以上的孩子已经具备行走、跑跳能力,……明年3月,铁血社区将永久关闭拥有近二十年历史的铁血社区将永久关闭。12月20日,铁血社区发布声明称,网站将于2021年12月20日停止用户发帖、回帖功能,2022年3月1日起,铁血社区将正式永久关闭……孕期护肤跟我这样做,孕期护肤4步走,黄脸婆逆袭成牛奶肌我一直坚信:当护肤遇上女神,见识的是成长,当护肤遇上村姑,见证的是黄脸婆!合理的护肤,皮肤又白又嫩,哪怕30也不会蜡黄、无气色。但如果孕期不好好护肤,随便应付,那么还到生……散文青春,是一道让人羡慕不已的美好前景青春,是一道让人羡慕不已的美好前景。那年,我还是大学毕业,经过业余的各种青春里,我也算是一个有些叛逆,却依然喜欢回顾校园。所以,我特别留恋这座城市。所以,我从不记得曾经的何时何……来点儿新闻06。14北京暂停举办线下体育赛事活动北京暂停举办线下体育赛事活动6月13日,北京市体育局发布通知,受涉酒吧关联聚集性疫情影响,为了减少人员流动和聚集给疫情防控带来的风险,切实保障人民身体健康和生命安全,经研……球员身价排行榜维尼修斯飙升至一亿欧,梅西C罗无缘前十德国转会市场更新了足球运动员最新身价,变化还比较大,我们来看看。最值得注意的是,身价世界前三都是二十来岁,很出人意料,梅西C罗时代过去了,年轻人站起来了。具体排名如……荣耀magicV茅台套装版科技界茅台又是割韭菜盒子荣耀第一款折叠机就蹭第一国酒:茅台深谙中国老百姓洗好一直以来国内手机电脑厂商有科技含量??1??用罗永浩的话说:都是方案厂商提供的技术支持品……绝杀!准绝杀!反绝杀!三分王入库的次日,大家都在各种秀历史三分王正式入库,各路球星为庆祝这一伟大时刻,今天纷纷在三分线外花式整活。谁能想到,最刺激的花活,竟是西部的一场菜鸡互啄鹈鹕客场挑战雷霆,……吕德华认清自我,看到战绩后承认自己菜,看到结果给粉丝整不会了要说王者荣耀中最嘴硬的主播莫过于吕德华了,在吕德华的直播中经常看到吕德华操作失误怪队友的场面,赛后也是各种甩锅,三木木的经典采访就是这么来的,不过最近吕德华看到自己巅峰赛战绩之……贵州酒席太奇葩,血拌生猪肉排名第三,红肉排第二,你敢吃吗?说到贵州这个地方,山清水秀,景美人更美,在这里生活着不同的少数民族,大家也纷纷带来了本地的特色美食,去过本地的朋友都知道,一些特殊的美食有的让人口水直流,有的却让人望而却步。……看!南京亮灯啦秦淮灯彩,是南京人永远不会错过的新年盛景。前天,秦淮灯彩掀开神秘面纱。帅气十足的生肖福兔、喜庆满满的荷满秦淮、趣味盎然的瑞兔贺岁各类造型精美……黄瓜片敷脸有什么效果?点击上方关注广州云云诊所与你分享皮肤美容抗衰年轻化许多人喜欢在脸上涂黄瓜。他们认为保湿可以美白皮肤。真的是这样吗?图片来源:视觉中国乾隆在线皮肤分为表皮……
网易发布致暴雪国服玩家的告别信感谢相伴14年,期待所有暴雪玩网易微信公众号1月23日发布致暴雪国服玩家的告别信,全文如下。亲爱的暴雪游戏玩家:2023年1月24日0时,由网之易代理的《魔兽世界》、《炉石传说》、《守望先锋》、……癸卯春节怎么玩?博物馆里过大年金福迎春,大展宏兔。在春节假期,不少市民群众在走亲访友之余,选择走进广西博物馆,或参加有趣的新春活动,或欣赏展览追溯历史,让假期增添文化味。走进广西博物馆服务大厅,新年氛……新民快评进化成更好的自己岁末,总是恨不能把一分钟掰成两半来用。前几日,无意中被一条关乎人类新基因的新闻吸引了注意力。国际学术期刊发表的最新研究论文披露,科学家在人类谱系中发现了155个从零开始的新基因……三年老平台换新13代酷睿i7体验瞬间拉满2020年初,因为工作原因笔者斥资近万元,收了一套成色还不错的X299平台。以当时的多核旗舰i910980XEX299主板为核心,搭配416GBDDR4内存以及1TB英特尔76……发不了大财的人,都是低估了人性和欲望的人,却自以为是,很悲哀人性和欲望,都是与生俱来的,而你发不了大财,就是不理解或者是低估了人性和欲望,也不会利用人性和欲望去挣钱。特别是下面的人性,如果你理解的比较透彻,大概率就能发大财。……有一种快乐叫村BA村BA总决赛现场图新华社厉苒苒下雨也浇不灭的热情,让村BA又一次火出圈了。伴随着苗迪的节奏,昨天下午,因降雨延期一天的贵州省首届美丽乡村篮球联赛总决赛冠军争夺……学会这16道下饭菜,轻松拿捏女友和朋友的胃!自己就是大厨奶油虾球原料净虾仁500克,淀粉200克,吉士粉10克。调料奶油、炼乳、白糖、植物油各适量。制作方法1将虾仁用开水汆熟加吉士粉、淀粉抓匀。……电脑密码忘了怎么办如果您忘记了电脑密码,可以尝试以下步骤重新设置:使用密码提示:在设置密码时,您可能已经设置了密码提示。如果是这样,请尝试记住提示,看看它是否能唤起您的记忆。使用另一……老用户的无奈,红米K60半个月两次降价!网友都是被一加逼的!从发布之初踌躇满志要成为中端市场的焊门员,到现如今被迫降价求生,红米K60的遭遇多少有点让人心疼。可以说,在面对一加Ace2和真我GTNeo5这样的极具性价比的竞争对手时,红米……鲍尔吉原野幻想无用吗?或许它是珍稀的资源《翡翠地》是鲁迅文学奖获得者鲍尔吉原野历时三年,在儿童文学幻想题材上的首部作品。如果可以回到童年,我情愿生活在这本书的幻想世界里。翡翠地有绿色的天空,飘着蓝云彩、紫云彩和……还在穿碎花裙吗?这3种裙子才是春天的正确打开方式春天,如何把日系半裙穿出高级?天气也肉眼可见地暖和起来,是到了穿漂亮裙子的季节,各种好看的小裙子也该提上日程了!所以,今天我们就来聊一聊有哪些裙子值得买,话不多说让……老来瘦可能是患了肌少症,得治!俗话都说:千金难买老来瘦!但老年人有一种瘦,即使没有三高,也会让老年人觉得浑身没劲,走不动。这就是肌少症!今天,通过一篇文章来瞧瞧是怎么回事。什么是肌少……
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网