怎么做服装外贸网站/珠海做网站的公司
开篇前瞎扯。很久没发技术文章了,此文一直放着草稿箱没有完成,感觉自己在家庭和工作中找到了拖延的借口,开始慢慢变得懒惰了,那是万万不行的。恰逢2023开年ChatGPT的爆火,更让我这些普通程序员危机感瞬间飙升,无限感受到自己的知识储备已经跟不上时代的节奏了。所以还是继续学习吧,活到老学到老。
还记得系列开篇的这张流程分析图嚒,不知不觉已经基本分析全了PeerConnectionFactory之上的内容。有兴趣需要补课的同学follow这个专栏。
现在把目光回归到PeerConnectionFactory这个关键节点,拆解中心环节继续向深进发。
从java层接口出发,很容易就找到源码.\sdk\android\src\jni\pc\peer_connection_factory.cc文件中的函数JNI_PeerConnectionFactory_CreatePeerConnectionFactory,最终调用CreatePeerConnectionFactoryForJava,一起看看代码内容。
// .\sdk\android\src\jni\pc\peer_connection_factory.cc文件中的
// 函数JNI_PeerConnectionFactory_CreatePeerConnectionFactory -> CreatePeerConnectionFactoryForJava
//为了节省篇幅,函数内部很多RTC_CHECK省去了。
ScopedJavaLocalRef<jobject> CreatePeerConnectionFactoryForJava(JNIEnv* jni,const JavaParamRef<jobject>& jcontext,const JavaParamRef<jobject>& joptions,// 节省篇幅,入参列表简化如下。// |audio_device_module|, |jencoder_factory|, |jdecoder_factory|,// |audio_processor|, |fec_controller_factory|,// |network_state_predictor_factory|, |neteq_factory|.) {// 1、创建三类工作线程,std::unique_ptr<rtc::Thread> network_thread =rtc::Thread::CreateWithSocketServer();network_thread->SetName("network_thread", nullptr);std::unique_ptr<rtc::Thread> worker_thread = rtc::Thread::Create();worker_thread->SetName("worker_thread", nullptr);std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();signaling_thread->SetName("signaling_thread", NULL);const absl::optional<PeerConnectionFactoryInterface::Options> options =JavaToNativePeerConnectionFactoryOptions(jni, joptions);// 2、创建PeerConnectionFactoryDependencies PeerConnectionFactoryDependencies dependencies;dependencies.network_thread = network_thread.get();dependencies.worker_thread = worker_thread.get();dependencies.signaling_thread = signaling_thread.get();dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();dependencies.call_factory = CreateCallFactory();dependencies.event_log_factory = std::make_unique<RtcEventLogFactory>(dependencies.task_queue_factory.get());dependencies.fec_controller_factory = std::move(fec_controller_factory);dependencies.network_controller_factory =std::move(network_controller_factory);dependencies.network_state_predictor_factory =std::move(network_state_predictor_factory);dependencies.neteq_factory = std::move(neteq_factory);if (!(options && options->disable_network_monitor)) {dependencies.network_monitor_factory =std::make_unique<AndroidNetworkMonitorFactory>();}// 3、创建PeerConnectionFactoryDependencies所需的MediaEngineDependencies cricket::MediaEngineDependencies media_dependencies;media_dependencies.task_queue_factory = dependencies.task_queue_factory.get();media_dependencies.adm = std::move(audio_device_module);media_dependencies.audio_encoder_factory = std::move(audio_encoder_factory);media_dependencies.audio_decoder_factory = std::move(audio_decoder_factory);media_dependencies.audio_processing = std::move(audio_processor);media_dependencies.video_encoder_factory =absl::WrapUnique(CreateVideoEncoderFactory(jni, jencoder_factory));media_dependencies.video_decoder_factory =absl::WrapUnique(CreateVideoDecoderFactory(jni, jdecoder_factory));dependencies.media_engine =cricket::CreateMediaEngine(std::move(media_dependencies));// 4、通过PeerConnectionFactoryDependencies创建CreateModularPeerConnectionFactoryrtc::scoped_refptr<PeerConnectionFactoryInterface> factory =CreateModularPeerConnectionFactory(std::move(dependencies));if (options)factory->SetOptions(*options);return NativeToScopedJavaPeerConnectionFactory(jni, factory, std::move(network_thread), std::move(worker_thread),std::move(signaling_thread));
}
函数内容有点多,不过总结起来其实就几个部分,
1、创建三类内部组件,network_thread/worker_thread/signaling_thread,虽然他们都是rtc::Thread,虽然命名是线程,但其实不是我们所了解的线程,反而有点类似Android Handler,包含着消息队列和内部执行循环。
2、创建PeerConnectionFactoryDependencies,其中需要关注几个关键量 call_factory(p2p链接) / fec_controller_factory(丢包纠错) / network_state_predictor_factory(网络带宽预测)/ media_dependencies(媒体相关) 以上几个都是webrtc的重点难点,都是需要开坑逐一分析学习。
3、创建PeerConnectionFactoryDependencies所依赖的MediaEngineDependencies,MediaEngineDependencies的入参就是之前分析过的几个video/audio-encoder/decoder factory
4、最后就是根据PeerConnectionFactoryDependencies,创建集大成的PeerConnectionFactory。
一图概述就是这样:
继续往下看看CreateModularPeerConnectionFactory的内容
rtc::scoped_refptr<PeerConnectionFactoryInterface>
CreateModularPeerConnectionFactory(PeerConnectionFactoryDependencies dependencies) {// The PeerConnectionFactory must be created on the signaling thread.if (dependencies.signaling_thread &&!dependencies.signaling_thread->IsCurrent()) {return dependencies.signaling_thread->Invoke<rtc::scoped_refptr<PeerConnectionFactoryInterface>>(RTC_FROM_HERE, [&dependencies] {return CreateModularPeerConnectionFactory(std::move(dependencies));});}auto pc_factory = PeerConnectionFactory::Create(std::move(dependencies));if (!pc_factory) {return nullptr;}// Verify that the invocation and the initialization ended up agreeing on the// thread.RTC_DCHECK_RUN_ON(pc_factory->signaling_thread());return PeerConnectionFactoryProxy::Create(pc_factory->signaling_thread(), pc_factory->worker_thread(), pc_factory);
}// Static
rtc::scoped_refptr<PeerConnectionFactory> PeerConnectionFactory::Create(PeerConnectionFactoryDependencies dependencies) {auto context = ConnectionContext::Create(&dependencies);if (!context) {return nullptr;}return rtc::make_ref_counted<PeerConnectionFactory>(context, &dependencies);
}
其中PeerConnectionFactory::Create就是真正创建PeerConnectionFactory的地方,其中还包含了一个ConnectionContext的创建,还有一个比较难明白的地方就是CreateModularPeerConnectionFactory函数的返回,PeerConnectionFactoryProxy,为啥不直接使用PeerConnectionFactory?
而且,用普通的阅读器是跟踪不到具体的实现文件。我是用VSCode带C++插件的才能跟踪到,跟踪进去会发现这是一个完全由宏定义去生成的代理类。大家有空可以自己去观摩,我这里就不贴代码了,位置在.\api\peer_connection_factory_proxy.h。
接下来直接看看PeerConnectionFactory的头定义,先大致了解其结构组成部分。
class PeerConnectionFactory : public PeerConnectionFactoryInterface {public:void SetOptions(const Options& options) override;RTCErrorOr<rtc::scoped_refptr<PeerConnectionInterface>>CreatePeerConnectionOrError(const PeerConnectionInterface::RTCConfiguration& configuration,PeerConnectionDependencies dependencies) override;RtpCapabilities GetRtpSenderCapabilities(cricket::MediaType kind) const override;RtpCapabilities GetRtpReceiverCapabilities(cricket::MediaType kind) const override;rtc::scoped_refptr<MediaStreamInterface> CreateLocalMediaStream(const std::string& stream_id) override;rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource(const cricket::AudioOptions& options) override;rtc::scoped_refptr<VideoTrackInterface> CreateVideoTrack(const std::string& id,VideoTrackSourceInterface* video_source) override;rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack(const std::string& id,AudioSourceInterface* audio_source) override;bool StartAecDump(FILE* file, int64_t max_size_bytes) override;void StopAecDump() override;SctpTransportFactoryInterface* sctp_transport_factory() {return context_->sctp_transport_factory();}virtual cricket::ChannelManager* channel_manager();rtc::Thread* signaling_thread() const {// This method can be called on a different thread when the factory is// created in CreatePeerConnectionFactory().return context_->signaling_thread();}rtc::Thread* worker_thread() const { return context_->worker_thread(); }const Options& options() const {RTC_DCHECK_RUN_ON(signaling_thread());return options_;}const WebRtcKeyValueConfig& trials() const { return context_->trials(); }protected:virtual ~PeerConnectionFactory();private:rtc::Thread* network_thread() const { return context_->network_thread(); }bool IsTrialEnabled(absl::string_view key) const;const cricket::ChannelManager* channel_manager() const {return context_->channel_manager();}std::unique_ptr<RtcEventLog> CreateRtcEventLog_w();std::unique_ptr<Call> CreateCall_w(RtcEventLog* event_log);rtc::scoped_refptr<ConnectionContext> context_;PeerConnectionFactoryInterface::Options options_RTC_GUARDED_BY(signaling_thread());std::unique_ptr<TaskQueueFactory> task_queue_factory_;std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory_;std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory_;std::unique_ptr<NetworkStatePredictorFactoryInterface>network_state_predictor_factory_;std::unique_ptr<NetworkControllerFactoryInterface>injected_network_controller_factory_;std::unique_ptr<NetEqFactory> neteq_factory_;
};
功能性方法先不急着深入,先大致拆分结构性组成部分。
1、CreatePeerConnectionOrError公开方法和CreateCall_w私有方法,应该和创建PeerConnection有着密切联系。这个留着下一篇文件 创建PeerConnection分析。
2、结合CreateModularPeerConnectionFactory方法和PeerConnectionFactory的头定义文件,大致可以看出ConnectionContext也是一个很重要的组成部分。
3、ChannelManager也是一个独立的组成部分。
其他也没啥了,接着在快速看看ConeectionContext的结构组成。
// This class contains resources needed by PeerConnection and associated
// objects. A reference to this object is passed to each PeerConnection. The
// methods on this object are assumed not to change the state in any way that
// interferes with the operation of other PeerConnections.
//
// This class must be created and destroyed on the signaling thread.
class ConnectionContext final: public rtc::RefCountedNonVirtual<ConnectionContext> {public:// Creates a ConnectionContext. May return null if initialization fails.// The Dependencies class allows simple management of all new dependencies// being added to the ConnectionContext.static rtc::scoped_refptr<ConnectionContext> Create(PeerConnectionFactoryDependencies* dependencies);// This class is not copyable or movable.ConnectionContext(const ConnectionContext&) = delete;ConnectionContext& operator=(const ConnectionContext&) = delete;// Functions called from PeerConnection and friendsSctpTransportFactoryInterface* sctp_transport_factory() const {return sctp_factory_.get();}cricket::ChannelManager* channel_manager() const;rtc::Thread* signaling_thread() { return signaling_thread_; }const rtc::Thread* signaling_thread() const { return signaling_thread_; }rtc::Thread* worker_thread() { return worker_thread_; }const rtc::Thread* worker_thread() const { return worker_thread_; }rtc::Thread* network_thread() { return network_thread_; }const rtc::Thread* network_thread() const { return network_thread_; }const WebRtcKeyValueConfig& trials() const { return *trials_.get(); }// Accessors only used from the PeerConnectionFactory classrtc::BasicNetworkManager* default_network_manager() {RTC_DCHECK_RUN_ON(signaling_thread_);return default_network_manager_.get();}rtc::BasicPacketSocketFactory* default_socket_factory() {RTC_DCHECK_RUN_ON(signaling_thread_);return default_socket_factory_.get();}CallFactoryInterface* call_factory() {RTC_DCHECK_RUN_ON(worker_thread_);return call_factory_.get();}private:rtc::Thread* const network_thread_;rtc::Thread* const worker_thread_;rtc::Thread* const signaling_thread_;// channel_manager is accessed both on signaling thread and worker thread.std::unique_ptr<cricket::ChannelManager> channel_manager_;std::unique_ptr<rtc::NetworkMonitorFactory> const network_monitor_factory_RTC_GUARDED_BY(signaling_thread_);std::unique_ptr<rtc::BasicNetworkManager> default_network_manager_RTC_GUARDED_BY(signaling_thread_);std::unique_ptr<webrtc::CallFactoryInterface> const call_factory_RTC_GUARDED_BY(worker_thread_);std::unique_ptr<rtc::BasicPacketSocketFactory> default_socket_factory_RTC_GUARDED_BY(signaling_thread_);std::unique_ptr<SctpTransportFactoryInterface> const sctp_factory_;// Accessed both on signaling thread and worker thread.std::unique_ptr<WebRtcKeyValueConfig> const trials_;
};
有备注看备注,翻译过来的意思:ConnectionContext此类包含PeerConnection和关联对象所需的资源。该对象的引用将传递给每个PeerConnection。且ConnectionContext此对象上的方法不会干扰其他操作的方式 去更改其PeerConnection对象的任何状态。
看方法可以知道PeerConnectionFactory很多方法是直接引用ConnectionContext的,甚至channel_manager / sctp_transport_factory / call_factory 也是直接引用ConnectionContext对象。
重要组成部分:ChannelManager、SctpTransportFactory、BasicNetworkManager、BasicPacketSocketFactory、CallFactory。一图总结概述(和上图的总结不冲突哈,其他更应该把这两图结合一起看。)
本篇主要介绍了PeerConnectionFactory的整体结构组成,简单揭开了其真正的面纱和其背后隐藏起来的关键部分(ConnectionContext)。之后会通过CreatePeerConnection-PeerConnection功能去继续分析WebRTC的整体脉络,力求全面、清晰、深入浅出。
That is all.
相关文章:

(Android-RTC-9)PeerConnectionFactory
开篇前瞎扯。很久没发技术文章了,此文一直放着草稿箱没有完成,感觉自己在家庭和工作中找到了拖延的借口,开始慢慢变得懒惰了,那是万万不行的。恰逢2023开年ChatGPT的爆火,更让我这些普通程序员危机感瞬间飙升ÿ…...

Vector - CAPL - 定时器函数和使用
定时器在C语言中的使用我想学习过C编程的都不会陌生,它能够提供延时,完成等待一定的时间;它也可以实现多线程的操作,并行实行某些软件功能。那在CAPL中,定时器又能做哪些工作呢?又是怎么使用的呢࿱…...

【嵌入式C】常见问题
1、goto的使用场景有哪些?并讨论其局限? (1)常用来跳出死循坏; (2)在linux开发中,常用于打印错误; (3)goto在某些使用场合会破坏程序的栈逻辑&…...
[神经网络]Transfomer架构
一、概述 Transfomer架构与传统CNN和RNN最大的区别在于其仅依赖自注意力机制,而没有卷积/循环操作。其相较于RNN,不需要进行时序运算,可以更好的进行并行;相较于CNN,其一次可以关注全图而不局限于感受野尺寸。 二、模…...

C++之多态 虚函数表
多态 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。 需要区分一下:1、菱形虚拟继承,是在继承方式前面加上virtual; class Person {}; class Student : virtual public Person {}; class Teacher…...

AI_Papers周刊:第四期
2023.02.28—2023.03.05 Top Papers Subjects: cs.CL 1.Language Is Not All You Need: Aligning Perception with Language Models 标题:KOSMOS-1:语言不是你所需要的全部:将感知与语言模型相结合 作者:Shaohan Huang, Li …...

A Simple Framework for Contrastive Learning of Visual Representations阅读笔记
论文地址:https://arxiv.org/pdf/2002.05709.pdf 目前流行的无监督学范式。通过训练,使模型拥有比较的能力。即,模型能够区别两个数据(instance)是否是相同的。这在 深度聚类 领域受到广泛的关注。(在有监…...

mac安装开发工具:clipy、iterm2、go、brew、mysql、redis、wget等
wget brew install wget clipy Releases Clipy/Clipy GitHub 环境变量 ~下有三个文件 .zshrc .zprofile .bash_profile > cat .zshrc export PATH$PATH:/usr/local/mysql/bin> cat .zprofile eval "$(/opt/homebrew/bin/brew shellenv)"> cat .bas…...

DJ1-1 计算机网络和因特网
目录 一、计算机网络 二、Interent 1. Internet 的介绍 2. Internet 的具体构成 3. Internet 提供的服务 4. Internet 的通信控制 一、计算机网络 定义:是指两台以上具有独立操作系统的计算机通过某些介质连接成的相互共享软硬件资源的集合体。 计算机网络向…...

[1.3.3]计算机系统概述——系统调用
文章目录第一章 计算机系统概述系统调用(一)什么是系统调用,有何作用(二)系统调用与库函数的区别(三)小例子:为什么系统调用是必须的(四)什么功能要用到系统调…...

【Java开发】JUC进阶 03:读写锁、阻塞队列、同步队列
1 读写锁(ReadWriteLock)📌 要点实现类:ReentrantReadWirteLock通过读写锁实现更细粒度的控制,当然通过Synchronized和Lock锁也能达到目的,不过他们会在写入和读取操作都给加锁,影响性能&#x…...

Fragment中获取Activity的一点点建议
平时的Android开发中,我们经常要在Fragment中去获取当前的Activity实例,刚开始的时候可能使用使用Fragment提供的getActivity方法来获取,但是这个方法可能返回null,为了让程序可以正常运行,项目中就出现大量下面这样的…...

Java Math类
Java Math 类是 Java 标准库中提供的一个数学计算类,它提供了很多数学函数,如三角函数、指数函数、对数函数等。在实际工作中,Java Math 类常常被用于处理数学计算问题,例如计算复杂的数学公式、实现数学算法等。本文将详细介绍 J…...

Javascript -- 加载时间线 正则表达式
js加载时间线 1、创建Document对象,开始解析web页面,解析html元素和他们的文本内容后添加Element对象和Text节点到文档中。这个阶段的document.readyState ‘loading’ 2、遇到link外部css,创建线程加载,并继续解析文档 3、遇到…...

gdb/git的基本使用
热爱编程的你,一定经常徘徊在写bug和改bug之间,调试器也一定是你随影而行的伙伴,离开了它你应该会寝食难安吧! 目录 gdb的使用 断点操作 运行调试 观察数据 Git的使用 仓库的创建和拉取 .gitignore “三板斧” 常用指令 gd…...

信息安全与数学基础-笔记-④二次同余方程
知识目录二次同余方程的解欧拉判别式Legendre (勒让德符号)二次同余方程的解 什么是二次同余方程的解 注意这里二次同余方程和一次同余方程是不一样的 在x2x^2x2 三 a (mod m) 方程中举例 ↓ 解即剩余类,因为是模m,所以我们在 [ 0, m-1 ]中逐个代入看是…...

Luogu P4447 [AHOI2018初中组]分组
题目链接:传送门 将nnn个可重复的整数分为mmm组,每组中的数必须连续且不重复,使人数最少的组人数最多。 两个最值肯定第一想到二分,每次二分出一个值,判断在这个值为答案的前提下能否完成分组。 在思考判别函数时发现…...

手把手创建flask项目
Flask 框架流程 什么是Flask: Flask诞生于2010年, 使用python语言基于Werkzeug工具箱编写的轻量级Web开发框架 Flask本身相当于一个内核, 其他几乎所有的功能都要用到扩展(邮件:Flask-Mail, 用户认证:Flask-Login, 数据库:Flask-SQLAlchemy). Flask的核心在于Werkz…...

SpringCloud-4_Eureka服务注册与发现
Eureka作为一个老牌经典的服务注册&发现技术,其设计和理念,也在影响后面的组件。目前主流的服务注册&发现的组件是Nacos当前项目架构问题分析-引出Eureka问题分析:1.在企业级项目中,服务消费访问请求会存在高并发2.如果只…...

【react全家桶】生命周期
文章目录04 【生命周期】1.简介2.初始化阶段2.1 constructor2.2 componentWillMount(即将废弃)2.3 static getDerivedStateFromProps(新钩子)2.4 render2.5 componentDidMount2.6 初始化阶段总结3.更新阶段3.1 componentWillRecei…...

虚拟机安装Windows 10
虚拟机安装Windows 10 镜像下载 方法一:下载我制作好的镜像文件->百度网盘链接 提取码:Chen 方法二:自己做一个 进入微软官网链接 下载"MediaCreationTool20H2" 运行该工具 点击下一步选择路径,等他下载好就欧克了…...

【CMU15-445数据库】bustub Project #2:B+ Tree(下)
Project 2 最后一篇,讲解 B 树并发控制的实现。说实话一开始博主以为这块内容不会很难(毕竟有 Project 1 一把大锁摆烂秒过的历史x),但实现起来才发现不用一把大锁真的极其痛苦,折腾了一周多才弄完。 本文分基础版算法…...

leetcode 困难 —— 外星文字典(拓扑排序)
题目: 现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。 给定一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。 请你根据该词典还原出此语言中已知的字…...

ubuntu server 18.04使用tensorflow进行ddqn训练全过程
0. 前言 需要使用ddqn完成某项任务,为了快速训练,使用带有GPU的服务器进行训练。记录下整个过程,以及遇到的坑。 1. 选择模板代码 参考代码来源 GitHub 该代码最后一次更新是Mar 24, 2020。 环境配置: python3.8 运行安装脚本…...

2023年全国最新二级建造师精选真题及答案14
百分百题库提供二级建造师考试试题、二建考试预测题、二级建造师考试真题、二建证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 二、多选题 61.已经取得下列资质的设计单位,可以直接申请相应类别施工总承包一级…...

mysql一条语句的写入原理
mysql写入原理 我们知道在mysql数据库最核心的大脑就是执行引擎; 其中的默认引擎Innodb在可靠执行和性能中做出来平衡; innodb支持在事务控制、读写效率,多用户并发,索引搜索方面都表现不俗; innodb如何进行数据写入…...

嵌入式Linux内核代码风格(二)
第九章:你已经把事情弄糟了 这没什么,我们都是这样。可能你的使用了很长时间Unix的朋友已经告诉你“GNU emacs”能 自动帮你格式化C源代码,而且你也注意到了,确实是这样,不过它所使用的默认值和我们 想要的相去甚远&a…...

Spring Boot @Aspect 切面编程实现访问请求日志记录
aop切面编程想必大家都不陌生了,aspect可以很方便开发人员对请求指定拦截层,一般是根据条件切入到controller控制层,做一些鉴权、分析注解、获取类名方法名参数、记录操作日志等。 在SpringBoot中使用aop首先是要导入依赖如下: …...

初学者的第一个Linux驱动
软件环境:Ubuntu20.04 Linux内核源码:3.4.39 硬件环境:GEC6818 什么是驱动?简单来说就是让硬件工作起来的程序代码。 Linux驱动模块加载有两种方式: 1、把写好的驱动代码直接编译进内核。 2、把写好的驱动代码编…...

7. 拼数
1 题目描述 拼数成绩10开启时间2021年09月24日 星期五 18:00折扣0.8折扣时间2021年11月15日 星期一 00:00允许迟交否关闭时间2021年11月23日 星期二 00:00 设有 n个正整数 a[1]…a[n],将它们联接成一排,相邻数字首尾相接,组成一个最大的整…...