webrtc-m79-peerconnection_client-创建offer

//
// 关于创建  offer 
//

void Conductor::ConnectToPeer(int peer_id) {
  RTC_DCHECK(peer_id_ == -1);
  RTC_DCHECK(peer_id != -1);

  if (peer_connection_.get()) {
    main_wnd_->MessageBox(
        "Error", "We only support connecting to one peer at a time", true);
    return;
  }

  if (InitializePeerConnection()) {  见上面的分析
    peer_id_ = peer_id;
    peer_connection_->CreateOffer( //
        this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());  这里传递进去了 Conductor 的 this 指针
  } else {
    main_wnd_->MessageBox("Error", "Failed to initialize PeerConnection", true);
  }
}

void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
                                 const RTCOfferAnswerOptions& options) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  // 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(), / weak_ptr_factory_ 的初始化是在 PeerConnection 的构造函数中 weak_ptr_factory_(this)
       observer_refptr =
           rtc::scoped_refptr<CreateSessionDescriptionObserver>(observer),  这里的 observer 就是 Conductor 的 this 指针
       options](std::function<void()> operations_chain_callback) { / 将 Conductor 的 this 指针包裹到 CreateSessionDescriptionObserver 类型的 observer_refptr 中
        // Abort early if |this_weak_ptr| is no longer valid.
        if (!this_weak_ptr) {
          observer_refptr->OnFailure(
              RTCError(RTCErrorType::INTERNAL_ERROR,
                       "CreateOffer failed because the session was shut down"));
          operations_chain_callback();
          return;
        }
        // The operation completes asynchronously when the wrapper is invoked.
        rtc::scoped_refptr<CreateSessionDescriptionObserverOperationWrapper>
            observer_wrapper(new rtc::RefCountedObject<
                             CreateSessionDescriptionObserverOperationWrapper>(
                std::move(observer_refptr), /// 又将 observer_refptr 包裹进 CreateSessionDescriptionObserverOperationWrapper 类型的 observer_wrapper
                std::move(operations_chain_callback)));
        this_weak_ptr->DoCreateOffer(options, observer_wrapper); //
      });
}

void PeerConnection::DoCreateOffer(
    const RTCOfferAnswerOptions& options,
    rtc::scoped_refptr<CreateSessionDescriptionObserver> observer) {  CreateSessionDescriptionObserverOperationWrapper 的父类是 CreateSessionDescriptionObserver
  RTC_DCHECK_RUN_ON(signaling_thread());
  TRACE_EVENT0("webrtc", "PeerConnection::DoCreateOffer");

  if (!observer) {
    RTC_LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
    return;
  }

  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;
  }

  // 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();
    RTC_LOG(LS_ERROR) << "CreateOffer: " << error_message;
    PostCreateSessionDescriptionFailure(
        observer,
        RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
    return;
  }

  if (!ValidateOfferAnswerOptions(options)) {
    std::string error = "CreateOffer called with invalid options.";
    RTC_LOG(LS_ERROR) << error;
    PostCreateSessionDescriptionFailure(
        observer, RTCError(RTCErrorType::INVALID_PARAMETER, std::move(error)));
    return;
  }

  // Legacy handling for offer_to_receive_audio and offer_to_receive_video.
  // Specified in WebRTC section 4.4.3.2 "Legacy configuration extensions".
  if (IsUnifiedPlan()) {
    RTCError error = HandleLegacyOfferOptions(options);
    if (!error.ok()) {
      PostCreateSessionDescriptionFailure(observer, std::move(error));
      return;
    }
  }

  cricket::MediaSessionOptions session_options;
  GetOptionsForOffer(options, &session_options);
  webrtc_session_desc_factory_->CreateOffer(observer, options, session_options);  webrtc_session_desc_factory_ 在 PeerConnection::Initialize 中初始化
}  这里的 observer 就是包裹了多个参数的 CreateSessionDescriptionObserverOperationWrapper 观察器


void WebRtcSessionDescriptionFactory::CreateOffer(
    CreateSessionDescriptionObserver* observer,  CreateSessionDescriptionObserverOperationWrapper 的父类是 CreateSessionDescriptionObserver
    const PeerConnectionInterface::RTCOfferAnswerOptions& options,
    const cricket::MediaSessionOptions& session_options) {
  std::string error = "CreateOffer";
  if (certificate_request_state_ == CERTIFICATE_FAILED) {
    error += kFailedDueToIdentityFailed;
    RTC_LOG(LS_ERROR) << error;
    PostCreateSessionDescriptionFailed(observer, error);
    return;
  }

  if (!ValidMediaSessionOptions(session_options)) {
    error += " called with invalid session options";
    RTC_LOG(LS_ERROR) << error;
    PostCreateSessionDescriptionFailed(observer, error);
    return;
  }

  CreateSessionDescriptionRequest request(
      CreateSessionDescriptionRequest::kOffer, observer, session_options); //将 CreateSessionDescriptionObserverOperationWrapper 类型的 observer 传递到 request 中
  if (certificate_request_state_ == CERTIFICATE_WAITING) {
    create_session_description_requests_.push(request); /
  } else {
    RTC_DCHECK(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
               certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
    InternalCreateOffer(request); /
  }
}


void WebRtcSessionDescriptionFactory::InternalCreateOffer(
    CreateSessionDescriptionRequest request) {
  if (pc_->local_description()) { / PeerConnection::local_description // 这里有些疑问,后面补充 ???????
    // If the needs-ice-restart flag is set as described by JSEP, we should
    // generate an offer with a new ufrag/password to trigger an ICE restart.
    for (cricket::MediaDescriptionOptions& options :
         request.options.media_description_options) {
      if (pc_->NeedsIceRestart(options.mid)) {
        options.transport_options.ice_restart = true;
      }
    }
  }

  std::unique_ptr<cricket::SessionDescription> desc =
      session_desc_factory_.CreateOffer( // session_desc_factory_ 在 WebRtcSessionDescriptionFactory 构造函数中初始化
          request.options, pc_->local_description()  就是 MediaSessionDescriptionFactory::CreateOffer 
                               ? pc_->local_description()->description()
                               : nullptr);
  if (!desc) {
    PostCreateSessionDescriptionFailed(request.observer,
                                       "Failed to initialize the offer.");
    return;
  }

  // RFC 3264
  // When issuing an offer that modifies the session,
  // the "o=" line of the new SDP MUST be identical to that in the
  // previous SDP, except that the version in the origin field MUST
  // increment by one from the previous SDP.

  // Just increase the version number by one each time when a new offer
  // is created regardless if it's identical to the previous one or not.
  // The |session_version_| is a uint64_t, the wrap around should not happen.
  RTC_DCHECK(session_version_ + 1 > session_version_);
  auto offer = std::make_unique<JsepSessionDescription>( / 创建 SdpType::kOffer 类型的 JsepSessionDescription
      SdpType::kOffer, std::move(desc), session_id_,
      rtc::ToString(session_version_++));
  if (pc_->local_description()) {
    for (const cricket::MediaDescriptionOptions& options :
         request.options.media_description_options) {
      if (!options.transport_options.ice_restart) {
        CopyCandidatesFromSessionDescription(pc_->local_description(),
                                             options.mid, offer.get());
      }
    }
  }
  PostCreateSessionDescriptionSucceeded(request.observer, std::move(offer)); / request.observer 就是 CreateSessionDescriptionObserverOperationWrapper
}

                                                        const SessionDescriptionInterface* PeerConnection::local_description() const {
                                                          RTC_DCHECK_RUN_ON(signaling_thread());
                                                          return pending_local_description_ ? pending_local_description_.get()
                                                                                            : current_local_description_.get();
                                                        }


                                                        std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
                                                            const MediaSessionOptions& session_options,
                                                            const SessionDescription* current_description) const {
                                                          // Must have options for each existing section.
                                                          if (current_description) {
                                                            RTC_DCHECK_LE(current_description->contents().size(),
                                                                          session_options.media_description_options.size());
                                                          }
                                                        
                                                          IceCredentialsIterator ice_credentials(
                                                              session_options.pooled_ice_credentials);
                                                        
                                                          std::vector<const ContentInfo*> current_active_contents;
                                                          if (current_description) {
                                                            current_active_contents =
                                                                GetActiveContents(*current_description, session_options);
                                                          }
                                                        
                                                          StreamParamsVec current_streams =
                                                              GetCurrentStreamParams(current_active_contents);
                                                        
                                                          AudioCodecs offer_audio_codecs;
                                                          VideoCodecs offer_video_codecs;
                                                          RtpDataCodecs offer_rtp_data_codecs;
                                                          GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
                                                                            &offer_video_codecs, &offer_rtp_data_codecs);
                                                          if (!session_options.vad_enabled) {
                                                            // If application doesn't want CN codecs in offer.
                                                            StripCNCodecs(&offer_audio_codecs);
                                                          }
                                                          AudioVideoRtpHeaderExtensions extensions_with_ids =
                                                              GetOfferedRtpHeaderExtensionsWithIds(
                                                                  current_active_contents, session_options.offer_extmap_allow_mixed,
                                                                  session_options.media_description_options);
                                                        
                                                          auto offer = std::make_unique<SessionDescription>(); // 创建一个 offer
                                                        
                                                          // Iterate through the media description options, matching with existing media
                                                          // descriptions in |current_description|.
                                                          size_t msection_index = 0;
                                                          for (const MediaDescriptionOptions& media_description_options :
                                                               session_options.media_description_options) {
                                                            const ContentInfo* current_content = nullptr;
                                                            if (current_description &&
                                                                msection_index < current_description->contents().size()) {
                                                              current_content = &current_description->contents()[msection_index];
                                                              // Media type must match unless this media section is being recycled.
                                                              RTC_DCHECK(current_content->name != media_description_options.mid ||
                                                                         IsMediaContentOfType(current_content,
                                                                                              media_description_options.type));
                                                            }
                                                            switch (media_description_options.type) {
                                                              case MEDIA_TYPE_AUDIO:
                                                                if (!AddAudioContentForOffer(media_description_options, session_options,
                                                                                             current_content, current_description,
                                                                                             extensions_with_ids.audio,
                                                                                             offer_audio_codecs, &current_streams,
                                                                                             offer.get(), &ice_credentials)) {
                                                                  return nullptr;
                                                                }
                                                                break;
                                                              case MEDIA_TYPE_VIDEO:
                                                                if (!AddVideoContentForOffer(media_description_options, session_options,
                                                                                             current_content, current_description,
                                                                                             extensions_with_ids.video,
                                                                                             offer_video_codecs, &current_streams,
                                                                                             offer.get(), &ice_credentials)) {
                                                                  return nullptr;
                                                                }
                                                                break;
                                                              case MEDIA_TYPE_DATA:
                                                                if (!AddDataContentForOffer(media_description_options, session_options,
                                                                                            current_content, current_description,
                                                                                            offer_rtp_data_codecs, &current_streams,
                                                                                            offer.get(), &ice_credentials)) {
                                                                  return nullptr;
                                                                }
                                                                break;
                                                              default:
                                                                RTC_NOTREACHED();
                                                            }
                                                            ++msection_index;
                                                          }
                                                        
                                                          // Bundle the contents together, if we've been asked to do so, and update any
                                                          // parameters that need to be tweaked for BUNDLE.
                                                          if (session_options.bundle_enabled) {
                                                            ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
                                                            for (const ContentInfo& content : offer->contents()) {
                                                              if (content.rejected) {
                                                                continue;
                                                              }
                                                              // TODO(deadbeef): There are conditions that make bundling two media
                                                              // descriptions together illegal. For example, they use the same payload
                                                              // type to represent different codecs, or same IDs for different header
                                                              // extensions. We need to detect this and not try to bundle those media
                                                              // descriptions together.
                                                              offer_bundle.AddContentName(content.name);
                                                            }
                                                            if (!offer_bundle.content_names().empty()) {
                                                              offer->AddGroup(offer_bundle);
                                                              if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
                                                                RTC_LOG(LS_ERROR)
                                                                    << "CreateOffer failed to UpdateTransportInfoForBundle.";
                                                                return nullptr;
                                                              }
                                                              if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
                                                                RTC_LOG(LS_ERROR)
                                                                    << "CreateOffer failed to UpdateCryptoParamsForBundle.";
                                                                return nullptr;
                                                              }
                                                            }
                                                          }
                                                        
                                                          // The following determines how to signal MSIDs to ensure compatibility with
                                                          // older endpoints (in particular, older Plan B endpoints).
                                                          if (is_unified_plan_) {
                                                            // Be conservative and signal using both a=msid and a=ssrc lines. Unified
                                                            // Plan answerers will look at a=msid and Plan B answerers will look at the
                                                            // a=ssrc MSID line.
                                                            offer->set_msid_signaling(cricket::kMsidSignalingMediaSection |
                                                                                      cricket::kMsidSignalingSsrcAttribute);
                                                          } else {
                                                            // Plan B always signals MSID using a=ssrc lines.
                                                            offer->set_msid_signaling(cricket::kMsidSignalingSsrcAttribute);
                                                          }
                                                        
                                                          offer->set_extmap_allow_mixed(session_options.offer_extmap_allow_mixed);
                                                        
                                                          return offer;  这里就是创建好的 offer
                                                        }


void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded(
    CreateSessionDescriptionObserver* observer,  CreateSessionDescriptionObserverOperationWrapper 的父类是 CreateSessionDescriptionObserver 
    std::unique_ptr<SessionDescriptionInterface> description) { 这里的 observer 就是 CreateSessionDescriptionObserverOperationWrapper 的指针
  CreateSessionDescriptionMsg* msg =
      new CreateSessionDescriptionMsg(observer, RTCError::OK()); ///这里的 observer 就是 CreateSessionDescriptionObserverOperationWrapper 的指针
  msg->description = std::move(description); /// 重新包裹 SDP
  signaling_thread_->Post(RTC_FROM_HERE, this, // 在信号线程进行发送,会在信号线程里面执行 WebRtcSessionDescriptionFactory::OnMessage
                          MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, msg);
}


void WebRtcSessionDescriptionFactory::OnMessage(rtc::Message* msg) {
  switch (msg->message_id) {
    case MSG_CREATE_SESSIONDESCRIPTION_SUCCESS: {
      CreateSessionDescriptionMsg* param =
          static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
      param->observer->OnSuccess(param->description.release()); / 就是 CreateSessionDescriptionObserverOperationWrapper::OnSucess
      delete param;      // 不过 OnSuccess 是在 CreateSessionDescriptionObserverOperationWrapper 的声明中定义的
      break;
    }
    case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
      CreateSessionDescriptionMsg* param =
          static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
      param->observer->OnFailure(std::move(param->error));
      delete param;
      break;
    }
    case MSG_USE_CONSTRUCTOR_CERTIFICATE: {
      rtc::ScopedRefMessageData<rtc::RTCCertificate>* param =
          static_cast<rtc::ScopedRefMessageData<rtc::RTCCertificate>*>(
              msg->pdata);
      RTC_LOG(LS_INFO) << "Using certificate supplied to the constructor.";
      SetCertificate(param->data());
      delete param;
      break;
    }
    default:
      RTC_NOTREACHED();
      break;
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值