前言

注意这个需要对端发起呼叫,调试的这端作为被呼叫方。
image.png
SetCertificate里面是个不断循环的,直到有answer请求的时候,才会继续往下走。
image.png
最终生成的就是jsepSessionDescription对象,有了这个信息再转为sdp,传回给呼叫方。呼叫方收到后调用SetRemoteDescription就完成了媒体协商。
image.png
PeerConnection::Create
PeerConnection::Initialize
SdpOfferAnswerHandler::Create
SdpOfferAnswerHandler::Initialize
-》
std::makeunique(
signaling_thread(), channel_manager(), this, pc
->sessionid(),
pc
->dtlsenabled(), std::move(dependencies.cert_generator),
certificate, &ssrc_generator
,
this {
transport_controller()->SetLocalCertificate(certificate);
})

WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory

  1. WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
  2. rtc::Thread* signaling_thread,
  3. cricket::ChannelManager* channel_manager,
  4. const SdpStateProvider* sdp_info,
  5. const std::string& session_id,
  6. bool dtls_enabled,
  7. std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
  8. const rtc::scoped_refptr<rtc::RTCCertificate>& certificate,
  9. UniqueRandomIdGenerator* ssrc_generator,
  10. std::function<void(const rtc::scoped_refptr<rtc::RTCCertificate>&)>
  11. on_certificate_ready)
  12. : signaling_thread_(signaling_thread),
  13. session_desc_factory_(channel_manager,
  14. &transport_desc_factory_,
  15. ssrc_generator),
  16. // RFC 4566 suggested a Network Time Protocol (NTP) format timestamp
  17. // as the session id and session version. To simplify, it should be fine
  18. // to just use a random number as session id and start version from
  19. // |kInitSessionVersion|.
  20. session_version_(kInitSessionVersion),
  21. cert_generator_(dtls_enabled ? std::move(cert_generator) : nullptr),
  22. sdp_info_(sdp_info),
  23. session_id_(session_id),
  24. certificate_request_state_(CERTIFICATE_NOT_NEEDED),
  25. on_certificate_ready_(on_certificate_ready) {
  26. RTC_DCHECK(signaling_thread_);
  27. if (!dtls_enabled) {
  28. SetSdesPolicy(cricket::SEC_REQUIRED);
  29. RTC_LOG(LS_VERBOSE) << "DTLS-SRTP disabled.";
  30. return;
  31. }
  32. // SRTP-SDES is disabled if DTLS is on.
  33. SetSdesPolicy(cricket::SEC_DISABLED);
  34. if (certificate) {
  35. // Use |certificate|.
  36. certificate_request_state_ = CERTIFICATE_WAITING;
  37. RTC_LOG(LS_VERBOSE) << "DTLS-SRTP enabled; has certificate parameter.";
  38. // We already have a certificate but we wait to do |SetIdentity|; if we do
  39. // it in the constructor then the caller has not had a chance to connect to
  40. // |SignalCertificateReady|.
  41. signaling_thread_->Post(
  42. RTC_FROM_HERE, this, MSG_USE_CONSTRUCTOR_CERTIFICATE,
  43. new rtc::ScopedRefMessageData<rtc::RTCCertificate>(certificate));
  44. } else { //创建证书
  45. // Generate certificate.
  46. certificate_request_state_ = CERTIFICATE_WAITING; //设置状态
  47. //创建回调绑定
  48. rtc::scoped_refptr<WebRtcCertificateGeneratorCallback> callback(
  49. new rtc::RefCountedObject<WebRtcCertificateGeneratorCallback>());
  50. callback->SignalRequestFailed.connect(
  51. this, &WebRtcSessionDescriptionFactory::OnCertificateRequestFailed);
  52. callback->SignalCertificateReady.connect(
  53. this, &WebRtcSessionDescriptionFactory::SetCertificate);
  54. rtc::KeyParams key_params = rtc::KeyParams();
  55. RTC_LOG(LS_VERBOSE)
  56. << "DTLS-SRTP enabled; sending DTLS identity request (key type: "
  57. << key_params.type() << ").";
  58. // 异步创建证书
  59. // Request certificate. This happens asynchronously, so that the caller gets
  60. // a chance to connect to |SignalCertificateReady|.
  61. cert_generator_->GenerateCertificateAsync(key_params, absl::nullopt,
  62. callback);
  63. }
  64. }
  1. cert_generator_->GenerateCertificateAsync(key_params, absl::nullopt,<br /> callback);

RTCCertificateGenerator::GenerateCertificateAsync

  1. void RTCCertificateGenerator::GenerateCertificateAsync(
  2. const KeyParams& key_params,
  3. const absl::optional<uint64_t>& expires_ms,
  4. const scoped_refptr<RTCCertificateGeneratorCallback>& callback) {
  5. RTC_DCHECK(signaling_thread_->IsCurrent());
  6. RTC_DCHECK(callback);
  7. // Create a new |RTCCertificateGenerationTask| for this generation request. It
  8. // is reference counted and referenced by the message data, ensuring it lives
  9. // until the task has completed (independent of |RTCCertificateGenerator|).
  10. worker_thread_->PostTask(RTC_FROM_HERE, [key_params, expires_ms,
  11. signaling_thread = signaling_thread_,
  12. cb = callback]() {
  13. scoped_refptr<RTCCertificate> certificate =
  14. RTCCertificateGenerator::GenerateCertificate(key_params, expires_ms);
  15. signaling_thread->PostTask(
  16. RTC_FROM_HERE, [cert = std::move(certificate), cb = std::move(cb)]() {
  17. cert ? cb->OnSuccess(cert) : cb->OnFailure();
  18. });
  19. });
  20. }

异步去创建证书,里面主要是workerthread->PostTask,向工作线程发送创建任务

SdpOfferAnswerHandler::CreateAnswer

image.png

  1. void SdpOfferAnswerHandler::CreateAnswer(
  2. CreateSessionDescriptionObserver* observer,
  3. const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
  4. RTC_DCHECK_RUN_ON(signaling_thread());
  5. // Chain this operation. If asynchronous operations are pending on the chain,
  6. // this operation will be queued to be invoked, otherwise the contents of the
  7. // lambda will execute immediately.
  8. operations_chain_->ChainOperation(
  9. [this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
  10. observer_refptr =
  11. rtc::scoped_refptr<CreateSessionDescriptionObserver>(observer),
  12. options](std::function<void()> operations_chain_callback) {
  13. // Abort early if |this_weak_ptr| is no longer valid.
  14. if (!this_weak_ptr) {
  15. observer_refptr->OnFailure(RTCError(
  16. RTCErrorType::INTERNAL_ERROR,
  17. "CreateAnswer failed because the session was shut down"));
  18. operations_chain_callback();
  19. return;
  20. }
  21. // The operation completes asynchronously when the wrapper is invoked.
  22. rtc::scoped_refptr<CreateSessionDescriptionObserverOperationWrapper>
  23. observer_wrapper(new rtc::RefCountedObject<
  24. CreateSessionDescriptionObserverOperationWrapper>(
  25. std::move(observer_refptr),
  26. std::move(operations_chain_callback)));
  27. this_weak_ptr->DoCreateAnswer(options, observer_wrapper);
  28. });
  29. }

后面主要调用DoCreateAnswer

SdpOfferAnswerHandler::DoCreateAnswer

  1. void SdpOfferAnswerHandler::DoCreateAnswer(
  2. const PeerConnectionInterface::RTCOfferAnswerOptions& options,
  3. rtc::scoped_refptr<CreateSessionDescriptionObserver> observer) {
  4. RTC_DCHECK_RUN_ON(signaling_thread());
  5. TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::DoCreateAnswer");
  6. if (!observer) {
  7. RTC_LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
  8. return;
  9. }
  10. // If a session error has occurred the PeerConnection is in a possibly
  11. // inconsistent state so fail right away.
  12. if (session_error() != SessionError::kNone) {
  13. std::string error_message = GetSessionErrorMsg();
  14. RTC_LOG(LS_ERROR) << "CreateAnswer: " << error_message;
  15. pc_->message_handler()->PostCreateSessionDescriptionFailure(
  16. observer,
  17. RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
  18. return;
  19. }
  20. if (!(signaling_state_ == PeerConnectionInterface::kHaveRemoteOffer ||
  21. signaling_state_ == PeerConnectionInterface::kHaveLocalPrAnswer)) {
  22. std::string error =
  23. "PeerConnection cannot create an answer in a state other than "
  24. "have-remote-offer or have-local-pranswer.";
  25. RTC_LOG(LS_ERROR) << error;
  26. pc_->message_handler()->PostCreateSessionDescriptionFailure(
  27. observer, RTCError(RTCErrorType::INVALID_STATE, std::move(error)));
  28. return;
  29. }
  30. // The remote description should be set if we're in the right state.
  31. RTC_DCHECK(remote_description());
  32. if (IsUnifiedPlan()) {
  33. if (options.offer_to_receive_audio !=
  34. PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) {
  35. RTC_LOG(LS_WARNING) << "CreateAnswer: offer_to_receive_audio is not "
  36. "supported with Unified Plan semantics. Use the "
  37. "RtpTransceiver API instead.";
  38. }
  39. if (options.offer_to_receive_video !=
  40. PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) {
  41. RTC_LOG(LS_WARNING) << "CreateAnswer: offer_to_receive_video is not "
  42. "supported with Unified Plan semantics. Use the "
  43. "RtpTransceiver API instead.";
  44. }
  45. }
  46. cricket::MediaSessionOptions session_options;
  47. GetOptionsForAnswer(options, &session_options);
  48. webrtc_session_desc_factory_->CreateAnswer(observer, session_options);
  49. }

里面也是主要是后面的 webrtcsession_desc_factory->CreateAnswer(observer, session_options);

WebRtcSessionDescriptionFactory::CreateAnswer

  1. void WebRtcSessionDescriptionFactory::CreateAnswer(
  2. CreateSessionDescriptionObserver* observer,
  3. const cricket::MediaSessionOptions& session_options) {
  4. std::string error = "CreateAnswer";
  5. if (certificate_request_state_ == CERTIFICATE_FAILED) {
  6. error += kFailedDueToIdentityFailed;
  7. RTC_LOG(LS_ERROR) << error;
  8. PostCreateSessionDescriptionFailed(observer, error);
  9. return;
  10. }
  11. if (!sdp_info_->remote_description()) {
  12. error += " can't be called before SetRemoteDescription.";
  13. RTC_LOG(LS_ERROR) << error;
  14. PostCreateSessionDescriptionFailed(observer, error);
  15. return;
  16. }
  17. if (sdp_info_->remote_description()->GetType() != SdpType::kOffer) {
  18. error += " failed because remote_description is not an offer.";
  19. RTC_LOG(LS_ERROR) << error;
  20. PostCreateSessionDescriptionFailed(observer, error);
  21. return;
  22. }
  23. if (!ValidMediaSessionOptions(session_options)) {
  24. error += " called with invalid session options.";
  25. RTC_LOG(LS_ERROR) << error;
  26. PostCreateSessionDescriptionFailed(observer, error);
  27. return;
  28. }
  29. //创建请求
  30. CreateSessionDescriptionRequest request(
  31. CreateSessionDescriptionRequest::kAnswer, observer, session_options);
  32. if (certificate_request_state_ == CERTIFICATE_WAITING) {
  33. create_session_description_requests_.push(request);
  34. } else {
  35. RTC_DCHECK(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
  36. certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
  37. InternalCreateAnswer(request);
  38. }
  39. }

image.png
请求完成后,就调用 WebRtcCertificateGeneratorCallback::OnSuccess

WebRtcCertificateGeneratorCallback::OnSuccess

image.png
这时候就会进来WebRtcSessionDescriptionFactory::SetCertificate

WebRtcSessionDescriptionFactory::SetCertificate

image.png

  1. void WebRtcSessionDescriptionFactory::SetCertificate(
  2. const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
  3. RTC_DCHECK(certificate);
  4. RTC_LOG(LS_VERBOSE) << "Setting new certificate.";
  5. certificate_request_state_ = CERTIFICATE_SUCCEEDED;
  6. //设置信号
  7. on_certificate_ready_(certificate);
  8. transport_desc_factory_.set_certificate(certificate);
  9. transport_desc_factory_.set_secure(cricket::SEC_ENABLED);
  10. while (!create_session_description_requests_.empty()) {
  11. if (create_session_description_requests_.front().type ==
  12. CreateSessionDescriptionRequest::kOffer) {
  13. InternalCreateOffer(create_session_description_requests_.front());
  14. } else {
  15. InternalCreateAnswer(create_session_description_requests_.front());
  16. }
  17. create_session_description_requests_.pop();
  18. }
  19. }

这里现在就会进去到WebRtcSessionDescriptionFactory::InternalCreateAnswer
注意该函数SetCertificate会一直执行,直到有个answer请求才会真正的去创建一个answer。

WebRtcSessionDescriptionFactory::InternalCreateAnswer

  1. void WebRtcSessionDescriptionFactory::InternalCreateAnswer(
  2. CreateSessionDescriptionRequest request) {
  3. if (sdp_info_->remote_description()) {
  4. for (cricket::MediaDescriptionOptions& options :
  5. request.options.media_description_options) {
  6. // According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1
  7. // an answer should also contain new ICE ufrag and password if an offer
  8. // has been received with new ufrag and password.
  9. options.transport_options.ice_restart =
  10. sdp_info_->IceRestartPending(options.mid);
  11. // We should pass the current DTLS role to the transport description
  12. // factory, if there is already an existing ongoing session.
  13. absl::optional<rtc::SSLRole> dtls_role =
  14. sdp_info_->GetDtlsRole(options.mid);
  15. if (dtls_role) {
  16. options.transport_options.prefer_passive_role =
  17. (rtc::SSL_SERVER == *dtls_role);
  18. }
  19. }
  20. }
  21. std::unique_ptr<cricket::SessionDescription> desc =
  22. session_desc_factory_.CreateAnswer(
  23. sdp_info_->remote_description()
  24. ? sdp_info_->remote_description()->description()
  25. : nullptr,
  26. request.options,
  27. sdp_info_->local_description()
  28. ? sdp_info_->local_description()->description()
  29. : nullptr);
  30. if (!desc) {
  31. PostCreateSessionDescriptionFailed(request.observer,
  32. "Failed to initialize the answer.");
  33. return;
  34. }
  35. // RFC 3264
  36. // If the answer is different from the offer in any way (different IP
  37. // addresses, ports, etc.), the origin line MUST be different in the answer.
  38. // In that case, the version number in the "o=" line of the answer is
  39. // unrelated to the version number in the o line of the offer.
  40. // Get a new version number by increasing the |session_version_answer_|.
  41. // The |session_version_| is a uint64_t, the wrap around should not happen.
  42. RTC_DCHECK(session_version_ + 1 > session_version_);
  43. auto answer = std::make_unique<JsepSessionDescription>(
  44. SdpType::kAnswer, std::move(desc), session_id_,
  45. rtc::ToString(session_version_++));
  46. if (sdp_info_->local_description()) {
  47. // Include all local ICE candidates in the SessionDescription unless
  48. // the remote peer has requested an ICE restart.
  49. for (const cricket::MediaDescriptionOptions& options :
  50. request.options.media_description_options) {
  51. if (!options.transport_options.ice_restart) {
  52. CopyCandidatesFromSessionDescription(sdp_info_->local_description(),
  53. options.mid, answer.get());
  54. }
  55. }
  56. }
  57. PostCreateSessionDescriptionSucceeded(request.observer, std::move(answer));
  58. }

主要是
auto answer = std::makeunique(
SdpType::kAnswer, std::move(desc), session_id
,
rtc::ToString(sessionversion++));
最终我们要获得就是这个answer。

前面调用了
std::uniqueptr desc =
session_desc_factory
.CreateAnswer(
sdpinfo->remotedescription()
? sdp_info
->remotedescription()->description()
: nullptr,
request.options,
sdp_info
->localdescription()
? sdp_info
->local_description()->description()
: nullptr);

MediaSessionDescriptionFactory::CreateAnswer

  1. std::unique_ptr<SessionDescription>
  2. MediaSessionDescriptionFactory::CreateAnswer(
  3. const SessionDescription* offer,
  4. const MediaSessionOptions& session_options,
  5. const SessionDescription* current_description) const {
  6. **
  7. ****
  8. // 创建了answer,后面的内容都是往里面填东西
  9. auto answer = std::make_unique<SessionDescription>();
  10. // If the offer supports BUNDLE, and we want to use it too, create a BUNDLE
  11. // group in the answer with the appropriate content names.
  12. const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE);
  13. ContentGroup answer_bundle(GROUP_TYPE_BUNDLE);
  14. // Transport info shared by the bundle group.
  15. std::unique_ptr<TransportInfo> bundle_transport;
  16. answer->set_extmap_allow_mixed(offer->extmap_allow_mixed());
  17. // Iterate through the media description options, matching with existing
  18. // media descriptions in |current_description|.
  19. size_t msection_index = 0;
  20. for (const MediaDescriptionOptions& media_description_options :
  21. session_options.media_description_options) {
  22. const ContentInfo* offer_content = &offer->contents()[msection_index];
  23. // Media types and MIDs must match between the remote offer and the
  24. // MediaDescriptionOptions.
  25. RTC_DCHECK(
  26. IsMediaContentOfType(offer_content, media_description_options.type));
  27. RTC_DCHECK(media_description_options.mid == offer_content->name);
  28. const ContentInfo* current_content = nullptr;
  29. if (current_description &&
  30. msection_index < current_description->contents().size()) {
  31. current_content = &current_description->contents()[msection_index];
  32. }
  33. RtpHeaderExtensions header_extensions = RtpHeaderExtensionsFromCapabilities(
  34. UnstoppedRtpHeaderExtensionCapabilities(
  35. media_description_options.header_extensions));
  36. // 根据类型来添加内容
  37. switch (media_description_options.type) {
  38. case MEDIA_TYPE_AUDIO:
  39. if (!AddAudioContentForAnswer(
  40. **
  41. }
  42. break;
  43. case MEDIA_TYPE_VIDEO:
  44. if (!AddVideoContentForAnswer(
  45. **
  46. }
  47. break;
  48. case MEDIA_TYPE_DATA:
  49. if (!AddDataContentForAnswer(
  50. **
  51. }
  52. break;
  53. case MEDIA_TYPE_UNSUPPORTED:
  54. if (!AddUnsupportedContentForAnswer(
  55. **
  56. default:
  57. RTC_NOTREACHED();
  58. }
  59. ++msection_index;
  60. // See if we can add the newly generated m= section to the BUNDLE group in
  61. // the answer.
  62. ContentInfo& added = answer->contents().back();
  63. if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
  64. offer_bundle->HasContentName(added.name)) {
  65. answer_bundle.AddContentName(added.name);
  66. bundle_transport.reset(
  67. new TransportInfo(*answer->GetTransportInfoByName(added.name)));
  68. }
  69. }
  70. ***
  71. return answer;
  72. }

image.png
这里以调用音频的AddAudioContentForAnswer为例子

MediaSessionDescriptionFactory::AddAudioContentForAnswer

  1. // |audio_codecs| = set of all possible codecs that can be used, with correct
  2. // payload type mappings
  3. //
  4. // |supported_audio_codecs| = set of codecs that are supported for the direction
  5. // of this m= section
  6. //
  7. // acd->codecs() = set of previously negotiated codecs for this m= section
  8. //
  9. // The payload types should come from audio_codecs, but the order should come
  10. // from acd->codecs() and then supported_codecs, to ensure that re-offers don't
  11. // change existing codec priority, and that new codecs are added with the right
  12. // priority.
  13. bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
  14. const MediaDescriptionOptions& media_description_options,
  15. const MediaSessionOptions& session_options,
  16. const ContentInfo* offer_content,
  17. const SessionDescription* offer_description,
  18. const ContentInfo* current_content,
  19. const SessionDescription* current_description,
  20. const TransportInfo* bundle_transport,
  21. const AudioCodecs& audio_codecs,
  22. const RtpHeaderExtensions& default_audio_rtp_header_extensions,
  23. StreamParamsVec* current_streams,
  24. SessionDescription* answer,
  25. IceCredentialsIterator* ice_credentials) const {
  26. RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
  27. const AudioContentDescription* offer_audio_description =
  28. offer_content->media_description()->as_audio();
  29. // 创建音频的CreateTransportAnswer
  30. std::unique_ptr<TransportDescription> audio_transport = CreateTransportAnswer(
  31. media_description_options.mid, offer_description,
  32. media_description_options.transport_options, current_description,
  33. bundle_transport != nullptr, ice_credentials);
  34. if (!audio_transport) {
  35. return false;
  36. }
  37. // Pick codecs based on the requested communications direction in the offer
  38. // and the selected direction in the answer.
  39. // Note these will be filtered one final time in CreateMediaContentAnswer.
  40. auto wants_rtd = media_description_options.direction;
  41. auto offer_rtd = offer_audio_description->direction();
  42. auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
  43. AudioCodecs supported_audio_codecs =
  44. GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
  45. AudioCodecs filtered_codecs;
  46. // 过滤音频编码器
  47. if (!media_description_options.codec_preferences.empty()) {
  48. filtered_codecs = MatchCodecPreference(
  49. media_description_options.codec_preferences, supported_audio_codecs);
  50. } else {
  51. // Add the codecs from current content if it exists and is not rejected nor
  52. // recycled.
  53. if (current_content && !current_content->rejected &&
  54. current_content->name == media_description_options.mid) {
  55. RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
  56. const AudioContentDescription* acd =
  57. current_content->media_description()->as_audio();
  58. for (const AudioCodec& codec : acd->codecs()) {
  59. if (FindMatchingCodec<AudioCodec>(acd->codecs(), audio_codecs, codec,
  60. nullptr)) {
  61. filtered_codecs.push_back(codec);
  62. }
  63. }
  64. }
  65. // Add other supported audio codecs.
  66. for (const AudioCodec& codec : supported_audio_codecs) {
  67. if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
  68. codec, nullptr) &&
  69. !FindMatchingCodec<AudioCodec>(supported_audio_codecs,
  70. filtered_codecs, codec, nullptr)) {
  71. // We should use the local codec with local parameters and the codec id
  72. // would be correctly mapped in |NegotiateCodecs|.
  73. filtered_codecs.push_back(codec);
  74. }
  75. }
  76. }
  77. bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
  78. session_options.bundle_enabled;
  79. auto audio_answer = std::make_unique<AudioContentDescription>();
  80. // Do not require or create SDES cryptos if DTLS is used.
  81. cricket::SecurePolicy sdes_policy =
  82. audio_transport->secure() ? cricket::SEC_DISABLED : secure();
  83. if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
  84. media_description_options, session_options,
  85. ssrc_generator_, current_streams,
  86. audio_answer.get())) {
  87. return false;
  88. }
  89. // 构建音频的MediaContent
  90. if (!CreateMediaContentAnswer(
  91. offer_audio_description, media_description_options, session_options,
  92. sdes_policy, GetCryptos(current_content),
  93. filtered_rtp_header_extensions(default_audio_rtp_header_extensions),
  94. ssrc_generator_, enable_encrypted_rtp_header_extensions_,
  95. current_streams, bundle_enabled, audio_answer.get())) {
  96. return false; // Fails the session setup.
  97. }
  98. bool secure = bundle_transport ? bundle_transport->description.secure()
  99. : audio_transport->secure();
  100. bool rejected = media_description_options.stopped ||
  101. offer_content->rejected ||
  102. !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
  103. audio_answer->protocol(), secure);
  104. if (!AddTransportAnswer(media_description_options.mid,
  105. *(audio_transport.get()), answer)) {
  106. return false;
  107. }
  108. if (rejected) {
  109. RTC_LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
  110. << "' being rejected in answer.";
  111. }
  112. answer->AddContent(media_description_options.mid, offer_content->type,
  113. rejected, std::move(audio_answer));
  114. return true;
  115. }

首先调用CreateTransportAnswer,然后过滤获得音频编解码器filtered_codecs,并传入到SetCodecsInAnswer。然后调用CreateMediaContentAnswer构建音频的MediaContent。
调用AddContent传入到音频audio_answer,然后返回。
image.png