WebRTC源码分析-呼叫建立过程之五(创建Offer,CreateOffer,上篇)

深入解析WebRTC中创建SDP Offer的过程,包括参数处理、状态检查、信息收集及最终Offer的构建。覆盖关键步骤如CreateOffer声明、参数解析、状态验证、信息收集、Offer构建及结果通知。

1. 引言

创建完PeerConnectionFactory 和 PeerConnection这两个API层的操盘对象之后;紧接着需要初始化本地的媒体,也即创建本地的音频轨、视频轨、数据通道,并将这些本地的媒体轨道添加到PeerConnection对象中。然后即可调用PeerConnection::CreateOffer()创建本地SDP对象。

本文将详细描述PeerConnection::CreateOffer()过程,相关的知识点。如下图在这里插入图片描述

2 CreateOffer声明 && 两个参数

2.1 CreateOffer声明

  void CreateOffer(CreateSessionDescriptionObserver* observer,
                   const RTCOfferAnswerOptions& options) override;

2.2 参数CreateSessionDescriptionObserver

class RTC_EXPORT CreateSessionDescriptionObserver
    : public rtc::RefCountInterface {
   
   
 public:
  virtual void OnSuccess(SessionDescriptionInterface* desc) = 0;
  virtual void OnFailure(RTCError error);
  virtual void OnFailure(const std::string& error);

 protected:
  ~CreateSessionDescriptionObserver() override = default;
};

注意:CreateSessionDescriptionObserver只是一个接口,没有具体实现。一般用户层需要继承,并实现CreateSessionDescriptionObserver的方法,以便用户侧感知CreateOffer状态。

另外,WebRTC内部提供了两个实现了CreateSessionDescriptionObserver接口的类,ImplicitCreateSessionDescriptionObserver && CreateSessionDescriptionObserverOperationWrapper。在后续分析过程中再来聊聊这两个实现所起的作用。

2.3 参数RTCOfferAnswerOptions

RTCOfferAnswerOptions源码如下(省略了构造函数):

  struct RTCOfferAnswerOptions {
   
   
    static const int kUndefined = -1;
    static const int kMaxOfferToReceiveMedia = 1;
    // The default value for constraint offerToReceiveX:true.
    static const int kOfferToReceiveMediaTrue = 1;

    // These options are left as backwards compatibility for clients who need
    // "Plan B" semantics. Clients who have switched to "Unified Plan" semantics
    // should use the RtpTransceiver API (AddTransceiver) instead.
    //
    // offer_to_receive_X set to 1 will cause a media description to be
    // generated in the offer, even if no tracks of that type have been added.
    // Values greater than 1 are treated the same.
    //
    // If set to 0, the generated directional attribute will not include the
    // "recv" direction (meaning it will be "sendonly" or "inactive".
    int offer_to_receive_video = kUndefined;
    int offer_to_receive_audio = kUndefined;

    bool voice_activity_detection = true;
    bool ice_restart = false;

    // If true, will offer to BUNDLE audio/video/data together. Not to be
    // confused with RTCP mux (multiplexing RTP and RTCP together).
    bool use_rtp_mux = true;

    // If true, "a=packetization:<payload_type> raw" attribute will be offered
    // in the SDP for all video payload and accepted in the answer if offered.
    bool raw_packetization_for_video = false;

    // This will apply to all video tracks with a Plan B SDP offer/answer.
    int num_simulcast_layers = 1;

    // If true: Use SDP format from draft-ietf-mmusic-scdp-sdp-03
    // If false: Use SDP format from draft-ietf-mmusic-sdp-sdp-26 or later
    bool use_obsolete_sctp_sdp = false;
  };

RTCOfferAnswerOptions提供的参数,英文注释写得非常清楚,此处就不多赘述。特别值得注意的是use_rtp_mux 默认为真,使得所有媒体都集合到一个Bundle group,复用底层的同一个传输通道DTLS Transport。

3 PeerConnection::CreateOffer

接下来,我们来抽丝剥茧,一步步分析CreateOffer的整个流程。

void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
                                 const RTCOfferAnswerOptions& options) {
   
   
  // 1. 信令线程执行                               
  RTC_DCHECK_RUN_ON(signaling_thread());

  // 2. 排队执行
  // Chain this operation. If asynchronous operations are pending on the chain,
  // this operation will be queued to be invoked, otherwise the contents of the
  // lambda will execute immediately.
  operations_chain_->ChainOperation(
      [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
       observer_refptr =
           rtc::scoped_refptr<CreateSessionDescriptionObserver>(observer),
       options](std::function<void()> operations_chain_callback) {
   
   
        // 2.1 如果this_weak_ptr为空,意味着当前PC已经不存在,会话被关闭
        // Abort early if |this_weak_ptr| is no longer valid.
        if (!this_weak_ptr) {
   
   
          // 2.1.1 通知用户侧CreateOffer失败及失败原因
          observer_refptr->OnFailure(
              RTCError(RTCErrorType::INTERNAL_ERROR,
                       "CreateOffer failed because the session was shut down"));
          // 2.1.2 执行操作结束的回调,通知执行下一个Operation
          operations_chain_callback();
          return;
        }
        
        // 2.2 执行真正的DoCreateOffer
        // The operation completes asynchronously when the wrapper is invoked.
        // 2.2.1 创建入参Observer的一个Wrapper对象,该对象还封装了操作回调函数的指针,
        //     使得CreatOffer结束后,能够调用回调函数,通知执行下一个Operation,同时能够通知
        //     用户侧本次CreatOffer的结果。
        rtc::scoped_refptr<CreateSessionDescriptionObserverOperationWrapper>
            observer_wrapper(new rtc::RefCountedObject<
                             CreateSessionDescriptionObserverOperationWrapper>(
                std::move(observer_refptr),
                std::move(operations_chain_callback)));
        // 2.2.2 调用DoCreateOffer进一步去创建Offer
        this_weak_ptr->DoCreateOffer(options, observer_wrapper);
      });
}

CreateOffer方法执行过程是比较明朗的,也有必要将涉及的基本观念、设计方式交代下:

  • WebRTC中将CreateOffer、CreateAnswer、SetLocalDescription、SetRemoteDescription、AddIceCandidate这5个与SDP会话相关的API认为是一个Operation,这些Operation必须是挨个执行,不能乱序,不能同时有两个交互执行。因此,设计了一套操作链的接口,由OperationsChain类提供此功能。当链入一个操作时,如果队列中没有其他操作,那么该操作会被立马执行;若是操作链中存在操作,那么本操作就入队操作链,等待上一个操作执行完成之后,以回调的形式(即上述代码中的operations_chain_callback回调方法)来告知执行下一步操作。具体实现可见文章:WebRTC源码分析——操作链实现OperationsChain
  • CreateSessionDescriptionObserverOperationWrapper相当于一个封装了 "Offer操作结果回调 + 操作链操作完成回调"的一个对象,一直沿着CreateOffer调用链往下传,直到能够判断是否能成功创建Offer的地方,创建Offer这个操作完成的地方,然后去触发其承载的回调函数,以便告知上层操作结果,然后触发下一个操作。具体见源码
```cpp
// Wraps a CreateSessionDescriptionObserver and an OperationsChain operation
// complete callback. When the observer is invoked, the wrapped observer is
// invoked followed by invoking the completion callback.
class CreateSessionDescriptionObserverOperationWrapper
   : public CreateSessionDescriptionObserver {
   
   
public:
 CreateSessionDescriptionObserverOperationWrapper(
     rtc::scoped_refptr<CreateSessionDescriptionObserver> observer,
     std::function<void()> operation_complete_callback)
     : observer_(std::move(observer)),
       operation_complete_callback_(std::move(operation_complete_callback)) {
   
   
   RTC_DCHECK(observer_);
 }
 ~CreateSessionDescriptionObserverOperationWrapper() override {
   
   
   RTC_DCHECK(was_called_);
 }

 void OnSuccess(SessionDescriptionInterface* desc) override {
   
   
   RTC_DCHECK(!was_called_);
#ifdef RTC_DCHECK_IS_ON
   was_called_ = true;
#endif  // RTC_DCHECK_IS_ON
   // Completing the operation before invoking the observer allows the observer
   // to execute SetLocalDescription() without delay.
   operation_complete_callback_();
   observer_->OnSuccess(desc);
 }

 void OnFailure(RTCError error) override {
   
   
   RTC_DCHECK(!was_called_);
#ifdef RTC_DCHECK_IS_ON
   was_called_ = true;
#endif  // RTC_DCHECK_IS_ON
   operation_complete_callback_();
   observer_->OnFailure(std::move(error));
 }

private:
#ifdef RTC_DCHECK_IS_ON
 bool was_called_ = false;
#endif  // RTC_DCHECK_IS_ON
 rtc::scoped_refptr<CreateSessionDescriptionObserver> observer_;
 std::function<void()> operation_complete_callback_;
};
  • rtc::WeakPtrFactory<PeerConnection> weak_ptr_factory_:在构造PeerConnection时,传入了this指针。当从weak_ptr_factory_获取弱指针this_weak_ptr不存在时,意味着PC已经不存在了,也即当前会话已被关闭。这样的功能是由rtc::WeakPtrFactory && WeakPtr带来的,详见 WebRTC源码分析——弱指针WeakPtrFactory && WeakPtr。要注意的是weak_ptr_factory_必须声明在PC的最后,这样是为了:
  // |weak_ptr_factory_| must be declared last to make sure all WeakPtr's are
 // invalidated before any other members are destroyed.

3.1 PeerConnection::DoCreateOffer

void PeerConnection::DoCreateOffer(
    const RTCOfferAnswerOptions& options,
    rtc::scoped_refptr<CreateSessionDescriptionObserver> observer) {
   
   
  // 1. 状态判断
  // 1.1 运行在信令线程
  RTC_DCHECK_RUN_ON(signaling_thread());
  TRACE_EVENT0("webrtc", "PeerConnection::DoCreateOffer");
  // 1.2 观察者不能为空
  if (!observer) {
   
   
    RTC_LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
    return;
  }
  // 1.3 PC的信令状态不能是已关闭状态——kClose
  //     信令状态:  enum SignalingState {
   
   
  //                   kStable,
  //                   kHaveLocalOffer,
  //                   kHaveLocalPrAnswer,
  //                   kHaveRemoteOffer,
  //                   kHaveRemotePrAnswer,
  //                   kClosed,};
  //    PC创建时默认为kStable状态,只有PC调用Close方法时,会使得其处于kClosed状态               
  if (IsClosed()) {
   
   
    std::string error = "CreateOffer called when PeerConnection is closed.";
    RTC_LOG(LS_ERROR) << error;
    PostCreateSessionDescriptionFailure(
        observer, RTCError(RTCErrorType::INVALID_STATE, std::move(error)));
    return;
  }
  // 1.4 会话状态判断
  // If a session error has occurred the PeerConnection is in a possibly
  // inconsistent state so fail right away.
  if (session_error() != SessionError::kNone) {
   
   
    std::string error_message = GetSessionErrorMsg(
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值