广州网站建设乛新科送推广,php网站开发实,临沂网站建设吧,微信网站名WebRTC音频01 - 设备管理 WebRTC音频 02 - Windows平台设备管理 WebRTC音频 03 - 实时通信框架 WebRTC音频 04 - 关键类(本文)
一、前言#xff1a;
在WebRTC音频代码阅读过程中#xff0c;我们发现有很多关键的类比较抽象#xff0c;搞不清楚会导致代码阅读一脸懵逼。比如…WebRTC音频01 - 设备管理 WebRTC音频 02 - Windows平台设备管理 WebRTC音频 03 - 实时通信框架 WebRTC音频 04 - 关键类(本文)
一、前言
在WebRTC音频代码阅读过程中我们发现有很多关键的类比较抽象搞不清楚会导致代码阅读一脸懵逼。比如PeerConnection、Call、AudioState、Channel、Stream本文就尽力介绍下。
二、关键类关系图 一个PeerConnection拥有一个Call来管理和对端的会话可以看出Call里面主要负责创建一些收发的Stream但是PeerConnectionFactory是全局唯一的;同时CompositeMediaEngine属于PeerConnectonFactory因此MediaEngine也是唯一的;因此WebRtcVoiceEngine也是唯一的里面的AudioState也是全局唯一来处理众多PeerConnection中的Call过来的收发流;
三、PeerConnection
1、职责
可以理解成一个Socket Plus比如我们有一个Mesh架构里面有三个终端C1\C2\C3他们互相之间都可以P2P通信。当同时加入一个会议中那么C1需要创建两个PeerConnection一个负责和C2通信另外一个负责和C3通信
由于PeerConnection位于核心层最上面需要和session层的API进行交互因此它首先得实现 PeerConnectionInterface API
PeerConnection单独负责的有 管理会话状态机信令状态。 创建和初始化较低级别的对象如 PortAllocator 和 BaseChannels 拥有和管理 RtpSender/RtpReceiver 和跟踪对象的生命周期 跟踪当前和待处理的本地/远程会话描述;
共同负责的有 解析和解释 SDP; 根据当前状态生成Offer和Answer; ICE 状态机; 成统计数据;
2、创建时机
开始呼叫的时候会要做最主要的三件事可以参考Conductor::InitializePeerConnection: CreatePeerConnectionFactory创建PeerConnection工厂对象; CreatePeerConnection就创建Peerconntion了; 最后AddTracks添加Track到PeerConnection中track后面会介绍理解成一条音频或者视频流即可 上面这些步骤在介绍音频架构的文章中都有出现。可以看看代码 bool Conductor::InitializePeerConnection() {// 这函数前四个参数如果你想使用自己定义的线程函数那么就传入否则就使用的是webrtc内部的默认函数peer_connection_factory_ webrtc::CreatePeerConnectionFactory(nullptr /* network_thread */, nullptr /* worker_thread */,nullptr /* signaling_thread */, nullptr /* default_adm */,webrtc::CreateBuiltinAudioEncoderFactory(),webrtc::CreateBuiltinAudioDecoderFactory(),webrtc::CreateBuiltinVideoEncoderFactory(),webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,nullptr /* audio_processing */);// 创建PeerConnection对象if (!CreatePeerConnection(/*dtls*/true)) {main_wnd_-MessageBox(Error, CreatePeerConnection failed, true);DeletePeerConnection();}// 添加track到PeerConnection中AddTracks();return peer_connection_ ! nullptr;
}上面的CreatePeerConnection就会创建出来PeerConnection
四、Call
1、职责
Call代表着和某一个终端的会话管理者通话的整体流程和状态一个Call对象可以包含多个发送/接收流且这些流对应同一个远端端点并共享码率估计。具体职责如下
在WebRtc内部职责
创建/销毁 AudioReceiveStream、AudioSendStream创建/销毁 VideoSendStream、VideoReceiveStream
开放给上层应用的功能通过PeerConnection开放
发送码率设置包含最大码率、最小码率、初始码率初始码率作为编码器的初始参数以及带宽估计的先验值提供获取传输统计数据途径包含估算的可用发送带宽、估算的可用接收带宽、平滑发送引入的延迟、RTT估计值、累计的最大填充bit提供获取所有发送的数据包回调另外其还持有PacketReceiver对象因此所有接收到RTP/RTCP数据包也将经过Call。
2、创建时机
Call的创建还是和大多数WebRtc模块一块通过工厂模式创建先创建工厂再创建自己
Factory创建
// 文件路径.\api\create_peerconnection_factory.cc
rtc::scoped_refptrPeerConnectionFactoryInterface CreatePeerConnectionFactory(//...) {// 具体参数都打包为了方便向下传递PeerConnectionFactoryDependencies dependencies;dependencies.call_factory CreateCallFactory(); // 创建了CallFactory// ...
}看到创建了call_factory并放入dependencies继续往下传给后续流程。
创建Call对象
在CreatePeerConnection - CreatePeerConnectionOrError 处创建
RTCErrorOrrtc::scoped_refptrPeerConnectionInterface
PeerConnectionFactory::CreatePeerConnectionOrError(const PeerConnectionInterface::RTCConfiguration configuration,PeerConnectionDependencies dependencies) {// ... std::unique_ptrCall call worker_thread()-Invokestd::unique_ptrCall(RTC_FROM_HERE,[this, event_log] { return CreateCall_w(event_log.get()); }); // 创建了Call// 创建PeerConnectionauto result PeerConnection::Create(context_, options_, std::move(event_log),std::move(call), configuration,std::move(dependencies));return result_proxy;
}可以看出在工作线程通过调用CreateCall_w创建了一个call对象并在PeerConnection创建的时候传给PeerConnection这样以后PeerConnecton就持有了Call
看看CreateCall_w
// 文件路径pc\peer_connection_factory.cc
std::unique_ptrCall PeerConnectionFactory::CreateCall_w(RtcEventLog* event_log) {// 前面主要是设置一些收发流相关的参数省略.// 调用工厂类创建具体Call对象return std::unique_ptrCall(context_-call_factory()-CreateCall(call_config));
}然后就是调用Factory创建Call
// 文件路径call\call_factory.cc
Call* CallFactory::CreateCall(const Call::Config config) {RTC_DCHECK_RUN_ON(call_thread_);absl::optionalwebrtc::BuiltInNetworkBehaviorConfig send_degradation_config ParseDegradationConfig(true);absl::optionalwebrtc::BuiltInNetworkBehaviorConfigreceive_degradation_config ParseDegradationConfig(false);if (send_degradation_config || receive_degradation_config) {return new DegradedCall(std::unique_ptrCall(Call::Create(config)),send_degradation_config, receive_degradation_config,config.task_queue_factory);}if (!module_thread_) {module_thread_ SharedModuleThread::Create(ProcessThread::Create(SharedModThread), [this]() {RTC_DCHECK_RUN_ON(call_thread_);module_thread_ nullptr;});}// 调用Call的静态Create方法创建return Call::Create(config, module_thread_);
}这样Call对象就被创建出来了。
五、AudioState
1、职责
前面的WebRtcVoiceEngine里面有个AudioState成员变量这个变量非常重要主要负责管理AudioTranport模块里面又有AudioMixer和AudioProcessing和Adm模块AudioState有两个Call模块有一个引擎模块AudioEngine里面也有一个Call模块里面的主要定义一些接口并且创建AudioEngine里面的Call。
小结一下
AudioState并不是管理音频状态实际可以理解成一个音频上下文AudioState主要管理两个模块Adm和AudioTransport其中adm主要管理音频硬件的其中AudioTransport主要通过Mixer和Processing模块来进行混音和3A处理
2、定义
// 文件路径audio\audio_state.h
class AudioState : public webrtc::AudioState {public:// ...AudioProcessing* audio_processing() override;AudioTransport* audio_transport() override;void SetPlayout(bool enabled) override;void SetRecording(bool enabled) override;void SetStereoChannelSwapping(bool enable) override;AudioDeviceModule* audio_device_module() {RTC_DCHECK(config_.audio_device_module);return config_.audio_device_module.get();}void AddReceivingStream(webrtc::AudioReceiveStream* stream);void RemoveReceivingStream(webrtc::AudioReceiveStream* stream);void AddSendingStream(webrtc::AudioSendStream* stream,int sample_rate_hz,size_t num_channels);void RemoveSendingStream(webrtc::AudioSendStream* stream);private:// Transports mixed audio from the mixer to the audio device and// recorded audio to the sending streams.AudioTransportImpl audio_transport_;// Null audio poller is used to continue polling the audio streams if audio// playout is disabled so that audio processing still happens and the audio// stats are still updated.std::unique_ptrNullAudioPoller null_audio_poller_;std::unordered_setwebrtc::AudioReceiveStream* receiving_streams_;struct StreamProperties {int sample_rate_hz 0;size_t num_channels 0;};std::mapwebrtc::AudioSendStream*, StreamProperties sending_streams_;
};看得出主要是对Stream做一些创建、删除等操作 AddReceiveingStream将要处理的音频接收流添加到AudioState中 AddSendingStream将要处理的音频发送流添加到AudioState中 AudioTransportImpl RecordedDataIsAvailable拿到录制后的数据NeedMorePlayData向扬声器喂更多的数据 发现WebRtcVoiceEngine持有AudioState并且还持有ADM、Mixer、AudioProcessing主要进行3A处理但是这哥仨的状态维护是AudioState来完成的WebRtcVoiceEngine是这哥仨它爹负责生了这仨AudioState是这哥仨部门经理负责管理派活 AudioState持有AudioDeviceModule就说明AudioState是底层硬件设备和上层应用之间的桥梁上层应用想控制底层设备的采集与播放必须通过AudioStateAudioState再控制AudioDeviceModule对硬件进行操作
3、创建时机
调用栈如下
WebRtcVoiceEngine::Init()
CompositeMediaEngine::Init()
ChannelManager::Init()
ConnectionContext::Create()
PeerConnectionFactory::Create()
CreateModularPeerConnectionFactory()
CreatePeerConnectionFactory()也就是说在音频引擎的初始化函数里面创建的看看源代码非关键代码已经删除
// 文件路径media\engine\webrtc_voice_engine.cc
void WebRtcVoiceEngine::Init() {// Set up AudioState.{webrtc::AudioState::Config config;if (audio_mixer_) {config.audio_mixer audio_mixer_;} else {config.audio_mixer webrtc::AudioMixerImpl::Create();}config.audio_processing apm_;config.audio_device_module adm_;if (audio_frame_processor_)config.async_audio_processing_factory new rtc::RefCountedObjectwebrtc::AsyncAudioProcessing::Factory(*audio_frame_processor_, *task_queue_factory_);audio_state_ webrtc::AudioState::Create(config);}
}// 文件路径audio\audio_state.cc
rtc::scoped_refptrAudioState AudioState::Create(const AudioState::Config config) {// 创建一个使用引用计数管理的AudioState对象return new rtc::RefCountedObjectinternal::AudioState(config);
}备注AudioState创建的对象使用智能指针管理的不明白WebRTC智能指针的可以看看我的另外一篇文章WebRTC基本类 - 智能指针RefCountedObject和scoped_refptr-CSDN博客
4、Call和AudioState的关系
前面介绍了Call代表一个通话管理整个通话的流程和状态。里面提供了Audio/Video的Send/Receive相关的Stream。但是刚才看到AudioState里面也有一些Add/Remove Stream相关操作他俩之间什么关系呢其实Call主要是建立连接、与远端通信、处理媒体数据流、处理通话状态等。但是自己并不能操作到硬件而AudioState又持有adm指针config_.audio_device_module因此Call需要调用AudioState的方法来完成具体的音频数据的采集、处理、播放等动作。
六、Stream和Channel
前面分析媒体协商的时候我说过WebRtc含有很多种Channel、Stream非常混乱搞不清楚会导致阅读代码n脸懵逼。因此我们必须要弄懂它
1、API层
我们从API层Web API和Native API都一样看到的有Stream和Track两个概念其中Track就表示一条媒体源比如音视频会议中一路音频是一个auidioTrack一路视频又是一个videoTrack。而Stream就是将音频Track和视频Track打包起来作为一路流MediaStream。
2、媒体引擎层
引擎层又有Stream和Channel两个概念比如WebRtcVoiceMediaChannel和WebRtcAudioSendStream。由于引擎层一个Channel其实就代表的和一个编解码器的连接因此需要分类管理Audio和Audio放一起Video和Video放一起。而这个Channel中包含的音频、视频它又叫做stream比如AudioSendStream、AudioReceiveStream打包起来叫做VoiceMediaChannel。
基本相当于引擎层的Channel对应API层的Track。
3、Call层
Call层作为PeerConnecton的得力干将主要负责将这个业务给拉起来。它里面也有Stream和Channel的概念和引擎层相反是Stream里面包含Channel我猜这么设计的原因是Call层偏重于业务的概念我一条业务流只能包含一个方向的一种媒体流这又要分为音频和视频了
音频 Stream是有方向的要么是Send要么是Receive方向Stream里面包含ChannelChannel也是有方向的 视频 只有Stream没有Channel的概念并且Stream也是有方向的。要么是Send要么是Receive
4、小结
引擎层是将audio和video分类管理一个Channel中包含多个stream可以是send也可以是recv。Call层的音频Stream中有Channel但是视频的Stream中并没有Channel。
关注公众号和你分享优质资源