Split ApplyRemoteDescription up into smaller functions.
This is a followup to [1] that moves parts of the SetRemoteDescription
operation into a subclass of SdpOfferAnswerHandler.
[1] https://webrtc-review.googlesource.com/c/src/+/244980/
Bug: webrtc:13540
Change-Id: Ic5d97f9bfd30763f3988f2f6832703ffb819a51d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/245641
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35714}
diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc
index 1721e41..4ab336c 100644
--- a/pc/sdp_offer_answer.cc
+++ b/pc/sdp_offer_answer.cc
@@ -20,6 +20,7 @@
#include "absl/algorithm/container.h"
#include "absl/memory/memory.h"
+#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "api/array_view.h"
#include "api/crypto/crypto_options.h"
@@ -194,7 +195,9 @@
const RTCError& error) {
rtc::StringBuilder oss;
oss << "Failed to set " << (source == cricket::CS_LOCAL ? "local" : "remote")
- << " " << SdpTypeToString(type) << " sdp: " << error.message();
+ << " " << SdpTypeToString(type) << " sdp: ";
+ RTC_DCHECK(!absl::StartsWith(error.message(), oss.str())) << error.message();
+ oss << error.message();
return oss.Release();
}
@@ -728,8 +731,10 @@
: handler_(handler),
desc_(std::move(desc)),
observer_(std::move(observer)),
- operations_chain_callback_(std::move(operations_chain_callback)) {
+ operations_chain_callback_(std::move(operations_chain_callback)),
+ unified_plan_(handler_->IsUnifiedPlan()) {
if (!desc_) {
+ type_ = static_cast<SdpType>(-1);
InvalidParam("SessionDescription is NULL.");
} else {
type_ = desc_->GetType();
@@ -747,20 +752,27 @@
// Notifies the observer that the operation is complete and releases the
// reference to the observer.
void SignalCompletion() {
- if (observer_) {
- observer_->OnSetRemoteDescriptionComplete(error_);
- observer_ = nullptr; // Only fire the notification once.
+ if (!observer_)
+ return;
+
+ if (!error_.ok() && type_ != static_cast<SdpType>(-1)) {
+ std::string error_message =
+ GetSetDescriptionErrorMessage(cricket::CS_REMOTE, type_, error_);
+ RTC_LOG(LS_ERROR) << error_message;
+ error_.set_message(std::move(error_message));
}
+
+ observer_->OnSetRemoteDescriptionComplete(error_);
+ observer_ = nullptr; // Only fire the notification once.
}
// If a session error has occurred the PeerConnection is in a possibly
// inconsistent state so fail right away.
bool HaveSessionError() {
RTC_DCHECK(ok());
- if (handler_->session_error() == SessionError::kNone)
- return false;
- SetError(RTCErrorType::INTERNAL_ERROR, handler_->GetSessionErrorMsg());
- return true;
+ if (handler_->session_error() != SessionError::kNone)
+ InternalError(handler_->GetSessionErrorMsg());
+ return !ok();
}
// Returns true if the operation was a rollback operation. If this function
@@ -771,7 +783,7 @@
RTC_DCHECK(ok());
if (type_ != SdpType::kRollback) {
// Check if we can do an implicit rollback.
- if (type_ == SdpType::kOffer && handler_->IsUnifiedPlan() &&
+ if (type_ == SdpType::kOffer && unified_plan_ &&
handler_->pc_->configuration()->enable_implicit_rollback &&
handler_->signaling_state() ==
PeerConnectionInterface::kHaveLocalOffer) {
@@ -780,7 +792,7 @@
return false;
}
- if (handler_->IsUnifiedPlan()) {
+ if (unified_plan_) {
error_ = handler_->Rollback(type_);
} else if (type_ == SdpType::kRollback) {
Unsupported("Rollback not supported in Plan B");
@@ -808,51 +820,99 @@
bundle_groups_by_mid_ = GetBundleGroupsByMid(description());
error_ = handler_->ValidateSessionDescription(
desc_.get(), cricket::CS_REMOTE, bundle_groups_by_mid_);
- if (!error_.ok()) {
- std::string error_message =
- GetSetDescriptionErrorMessage(cricket::CS_REMOTE, type_, error_);
- RTC_LOG(LS_ERROR) << error_message;
- error_.set_message(std::move(error_message));
- return false;
- }
-
- return true;
+ return ok();
}
- // TODO(tommi): Instead of calling `handler_->ApplyRemoteDescription` here,
- // pass the ownership of `this` to that method and break down the steps
- // currently implemented in that function into smaller methods implemented
- // by this class. Once we have all of this broken down, we can start avoiding
- // the embedded calls to Invoke() and apply the description asynchronously.
- bool ApplyRemoteDescription() {
+ // Transfers ownership of the session description object over to `handler_`.
+ bool ReplaceRemoteDescriptionAndCheckEror() {
RTC_DCHECK_RUN_ON(handler_->signaling_thread());
RTC_DCHECK(ok());
- // TODO(tommi): It's not ideal to move desc_ ownership.
- error_ = handler_->ApplyRemoteDescription(std::move(desc_),
- bundle_groups_by_mid());
- // `desc` may be destroyed at this point.
+ RTC_DCHECK(desc_);
+ RTC_DCHECK(!replaced_remote_description_);
+#if RTC_DCHECK_IS_ON
+ const auto* existing_remote_description = handler_->remote_description();
+#endif
- if (!error_.ok()) {
- // If ApplyRemoteDescription fails, the PeerConnection could be in an
- // inconsistent state, so act conservatively here and set the session
- // error so that future calls to SetLocalDescription/SetRemoteDescription
- // fail.
- handler_->SetSessionError(SessionError::kContent, error_.message());
- std::string error_message =
- GetSetDescriptionErrorMessage(cricket::CS_REMOTE, type_, error_);
- RTC_LOG(LS_ERROR) << error_message;
- error_.set_message(std::move(error_message));
- return false;
+ error_ = handler_->ReplaceRemoteDescription(std::move(desc_), type_,
+ &replaced_remote_description_);
+
+ if (ok()) {
+#if RTC_DCHECK_IS_ON
+ // Sanity check that our `old_remote_description()` method always returns
+ // the same value as `remote_description()` did before the call to
+ // ReplaceRemoteDescription.
+ RTC_DCHECK_EQ(existing_remote_description, old_remote_description());
+#endif
+ } else {
+ SetAsSessionError();
}
- return true;
+ return ok();
+ }
+
+ bool UpdateChannels() {
+ RTC_DCHECK(ok());
+ RTC_DCHECK(!desc_) << "ReplaceRemoteDescription hasn't been called";
+
+ const auto* remote_description = handler_->remote_description();
+
+ const cricket::SessionDescription* session_desc =
+ remote_description->description();
+
+ // Transport and Media channels will be created only when offer is set.
+ if (unified_plan_) {
+ error_ = handler_->UpdateTransceiversAndDataChannels(
+ cricket::CS_REMOTE, *remote_description,
+ handler_->local_description(), old_remote_description(),
+ bundle_groups_by_mid_);
+ } else {
+ // Media channels will be created only when offer is set. These may use
+ // new transports just created by PushdownTransportDescription.
+ if (type_ == SdpType::kOffer) {
+ // TODO(mallinath) - Handle CreateChannel failure, as new local
+ // description is applied. Restore back to old description.
+ error_ = handler_->CreateChannels(*session_desc);
+ }
+ // Remove unused channels if MediaContentDescription is rejected.
+ handler_->RemoveUnusedChannels(session_desc);
+ }
+
+ return ok();
+ }
+
+ bool UpdateSessionState() {
+ RTC_DCHECK(ok());
+ error_ = handler_->UpdateSessionState(
+ type_, cricket::CS_REMOTE,
+ handler_->remote_description()->description(), bundle_groups_by_mid_);
+ if (!ok())
+ SetAsSessionError();
+ return ok();
+ }
+
+ bool UseCandidatesInRemoteDescription() {
+ RTC_DCHECK(ok());
+ if (handler_->local_description() &&
+ !handler_->UseCandidatesInRemoteDescription()) {
+ InvalidParam(kInvalidCandidates);
+ }
+ return ok();
}
// Convenience getter for desc_->GetType().
SdpType type() const { return type_; }
-
+ bool unified_plan() const { return unified_plan_; }
cricket::SessionDescription* description() { return desc_->description(); }
+ const SessionDescriptionInterface* old_remote_description() const {
+ RTC_DCHECK(!desc_) << "Called before replacing the remote description";
+ if (type_ == SdpType::kAnswer)
+ return replaced_remote_description_.get();
+ return replaced_remote_description_
+ ? replaced_remote_description_.get()
+ : handler_->current_remote_description();
+ }
+
// Returns a reference to a cached map of bundle groups ordered by mid.
// Note that this will only be valid after a successful call to
// `IsDescriptionValid`.
@@ -872,18 +932,35 @@
SetError(RTCErrorType::INVALID_PARAMETER, std::move(message));
}
+ void InternalError(std::string message) {
+ SetError(RTCErrorType::INTERNAL_ERROR, std::move(message));
+ }
+
void SetError(RTCErrorType type, std::string message) {
RTC_DCHECK(ok()) << "Overwriting an existing error?";
error_ = RTCError(type, std::move(message));
}
+ // Called when the PeerConnection could be in an inconsistent state and we set
+ // the session error so that future calls to
+ // SetLocalDescription/SetRemoteDescription fail.
+ void SetAsSessionError() {
+ RTC_DCHECK(!ok());
+ handler_->SetSessionError(SessionError::kContent, error_.message());
+ }
+
SdpOfferAnswerHandler* const handler_;
std::unique_ptr<SessionDescriptionInterface> desc_;
+ // Keeps the replaced session description object alive while the operation
+ // is taking place since methods that depend on `old_remote_description()`
+ // for updating the state, need it.
+ std::unique_ptr<SessionDescriptionInterface> replaced_remote_description_;
rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer_;
std::function<void()> operations_chain_callback_;
RTCError error_ = RTCError::OK();
std::map<std::string, const cricket::ContentGroup*> bundle_groups_by_mid_;
SdpType type_;
+ const bool unified_plan_;
};
// Used by parameterless SetLocalDescription() to create an offer or answer.
// Upon completion of creating the session description, SetLocalDescription() is
@@ -1446,10 +1523,12 @@
}
if (IsUnifiedPlan()) {
- RTCError error = UpdateTransceiversAndDataChannels(
+ error = UpdateTransceiversAndDataChannels(
cricket::CS_LOCAL, *local_description(), old_local_description,
remote_description(), bundle_groups_by_mid);
if (!error.ok()) {
+ RTC_LOG(LS_ERROR) << error.message() << " (" << SdpTypeToString(type)
+ << ")";
return error;
}
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list;
@@ -1510,6 +1589,8 @@
// description is applied. Restore back to old description.
RTCError error = CreateChannels(*local_description()->description());
if (!error.ok()) {
+ RTC_LOG(LS_ERROR) << error.message() << " (" << SdpTypeToString(type)
+ << ")";
return error;
}
}
@@ -1521,13 +1602,13 @@
local_description()->description(),
bundle_groups_by_mid);
if (!error.ok()) {
+ RTC_LOG(LS_ERROR) << error.message() << " (" << SdpTypeToString(type)
+ << ")";
return error;
}
- if (remote_description()) {
- // Now that we have a local description, we can push down remote candidates.
- UseCandidatesInSessionDescription(remote_description());
- }
+ // Now that we have a local description, we can push down remote candidates.
+ UseCandidatesInRemoteDescription();
pending_ice_restarts_.clear();
if (session_error() != SessionError::kNone) {
@@ -1680,102 +1761,72 @@
});
}
-RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
+RTCError SdpOfferAnswerHandler::ReplaceRemoteDescription(
std::unique_ptr<SessionDescriptionInterface> desc,
- const std::map<std::string, const cricket::ContentGroup*>&
- bundle_groups_by_mid) {
+ SdpType sdp_type,
+ std::unique_ptr<SessionDescriptionInterface>* replaced_description) {
+ RTC_DCHECK(replaced_description);
+ if (sdp_type == SdpType::kAnswer) {
+ *replaced_description = pending_remote_description_
+ ? std::move(pending_remote_description_)
+ : std::move(current_remote_description_);
+ current_remote_description_ = std::move(desc);
+ pending_remote_description_ = nullptr;
+ current_local_description_ = std::move(pending_local_description_);
+ } else {
+ *replaced_description = std::move(pending_remote_description_);
+ pending_remote_description_ = std::move(desc);
+ }
+
+ // The session description to apply now must be accessed by
+ // `remote_description()`.
+ const cricket::SessionDescription* session_desc =
+ remote_description()->description();
+
+ // Report statistics about any use of simulcast.
+ ReportSimulcastApiVersion(kSimulcastVersionApplyRemoteDescription,
+ *session_desc);
+
+ // NOTE: This will perform an Invoke() to the network thread.
+ return transport_controller()->SetRemoteDescription(sdp_type, session_desc);
+}
+
+void SdpOfferAnswerHandler::ApplyRemoteDescription(
+ std::unique_ptr<RemoteDescriptionOperation> operation) {
TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::ApplyRemoteDescription");
RTC_DCHECK_RUN_ON(signaling_thread());
- RTC_DCHECK(desc);
+ RTC_DCHECK(operation->description());
// Invalidate the [legacy] stats cache to make sure that it gets updated next
// time getStats() gets called, as updating the session description affects
// the stats.
pc_->stats()->InvalidateCache();
- // Take a reference to the old remote description since it's used below to
- // compare against the new remote description. When setting the new remote
- // description, grab ownership of the replaced session description in case it
- // is the same as `old_remote_description`, to keep it alive for the duration
- // of the method.
- const SessionDescriptionInterface* old_remote_description =
- remote_description();
- std::unique_ptr<SessionDescriptionInterface> replaced_remote_description;
- SdpType type = desc->GetType();
- if (type == SdpType::kAnswer) {
- replaced_remote_description = pending_remote_description_
- ? std::move(pending_remote_description_)
- : std::move(current_remote_description_);
- current_remote_description_ = std::move(desc);
- pending_remote_description_ = nullptr;
- current_local_description_ = std::move(pending_local_description_);
- } else {
- replaced_remote_description = std::move(pending_remote_description_);
- pending_remote_description_ = std::move(desc);
- }
- // The session description to apply now must be accessed by
- // `remote_description()`.
- RTC_DCHECK(remote_description());
+ if (!operation->ReplaceRemoteDescriptionAndCheckEror())
+ return;
- // Report statistics about any use of simulcast.
- ReportSimulcastApiVersion(kSimulcastVersionApplyRemoteDescription,
- *remote_description()->description());
-
- RTCError error = PushdownTransportDescription(cricket::CS_REMOTE, type);
- if (!error.ok()) {
- return error;
- }
-
- const bool is_unified_plan = IsUnifiedPlan();
-
- // Transport and Media channels will be created only when offer is set.
- if (is_unified_plan) {
- RTCError error = UpdateTransceiversAndDataChannels(
- cricket::CS_REMOTE, *remote_description(), local_description(),
- old_remote_description, bundle_groups_by_mid);
- if (!error.ok()) {
- return error;
- }
- } else {
- // Media channels will be created only when offer is set. These may use new
- // transports just created by PushdownTransportDescription.
- if (type == SdpType::kOffer) {
- // TODO(mallinath) - Handle CreateChannel failure, as new local
- // description is applied. Restore back to old description.
- RTCError error = CreateChannels(*remote_description()->description());
- if (!error.ok()) {
- return error;
- }
- }
- // Remove unused channels if MediaContentDescription is rejected.
- RemoveUnusedChannels(remote_description()->description());
- }
+ if (!operation->UpdateChannels())
+ return;
// NOTE: Candidates allocation will be initiated only when
// SetLocalDescription is called.
- error = UpdateSessionState(type, cricket::CS_REMOTE,
- remote_description()->description(),
- bundle_groups_by_mid);
- if (!error.ok()) {
- return error;
- }
+ if (!operation->UpdateSessionState())
+ return;
- if (local_description() &&
- !UseCandidatesInSessionDescription(remote_description())) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, kInvalidCandidates);
- }
+ if (!operation->UseCandidatesInRemoteDescription())
+ return;
- if (old_remote_description) {
+ if (operation->old_remote_description()) {
for (const cricket::ContentInfo& content :
- old_remote_description->description()->contents()) {
+ operation->old_remote_description()->description()->contents()) {
// Check if this new SessionDescription contains new ICE ufrag and
// password that indicates the remote peer requests an ICE restart.
// TODO(deadbeef): When we start storing both the current and pending
// remote description, this should reset pending_ice_restarts and compare
// against the current description.
- if (CheckForRemoteIceRestart(old_remote_description, remote_description(),
- content.name)) {
- if (type == SdpType::kOffer) {
+ if (CheckForRemoteIceRestart(operation->old_remote_description(),
+ remote_description(), content.name)) {
+ if (operation->type() == SdpType::kOffer) {
pending_ice_restarts_.insert(content.name);
}
} else {
@@ -1787,14 +1838,14 @@
// description plus any candidates added since then. We should remove
// this once we're sure it won't break anything.
WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
- old_remote_description, content.name, mutable_remote_description());
+ operation->old_remote_description(), content.name,
+ mutable_remote_description());
}
}
}
- if (session_error() != SessionError::kNone) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, GetSessionErrorMsg());
- }
+ if (operation->HaveSessionError())
+ return;
// Set the the ICE connection state to connecting since the connection may
// become writable with peer reflexive candidates before any remote candidate
@@ -1818,8 +1869,8 @@
data_channel_controller()->AllocateSctpSids(role);
}
- if (is_unified_plan) {
- ApplyRemoteDescriptionUpdateTransceiverState(type);
+ if (operation->unified_plan()) {
+ ApplyRemoteDescriptionUpdateTransceiverState(operation->type());
}
const cricket::AudioContentDescription* audio_desc =
@@ -1835,13 +1886,13 @@
remote_peer_supports_msid_ = true;
}
- if (!is_unified_plan) {
+ if (!operation->unified_plan()) {
PlanBUpdateSendersAndReceivers(
GetFirstAudioContent(remote_description()->description()), audio_desc,
GetFirstVideoContent(remote_description()->description()), video_desc);
}
- if (type == SdpType::kAnswer) {
+ if (operation->type() == SdpType::kAnswer) {
if (local_ice_credentials_to_replace_->SatisfiesIceRestart(
*current_local_description_)) {
local_ice_credentials_to_replace_->ClearIceCredentials();
@@ -1850,7 +1901,10 @@
RemoveStoppedTransceivers();
}
- return RTCError::OK();
+ // Consider the operation complete at this point.
+ operation->SignalCompletion();
+
+ SetRemoteDescriptionPostProcess(operation->type() == SdpType::kAnswer);
}
void SdpOfferAnswerHandler::ApplyRemoteDescriptionUpdateTransceiverState(
@@ -2294,13 +2348,7 @@
if (!operation->IsDescriptionValid())
return;
- if (!operation->ApplyRemoteDescription())
- return;
-
- // Consider the operation complete at this point.
- operation->SignalCompletion();
-
- SetRemoteDescriptionPostProcess(operation->type() == SdpType::kAnswer);
+ ApplyRemoteDescription(std::move(operation));
}
// Called after a DoSetRemoteDescription operation completes.
@@ -3138,17 +3186,16 @@
RTC_DCHECK_EQ(SessionError::kNone, session_error());
if (!sdesc || !sdesc->description()) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, kInvalidSdp);
+ return RTCError(RTCErrorType::INVALID_PARAMETER, kInvalidSdp);
}
SdpType type = sdesc->GetType();
if ((source == cricket::CS_LOCAL && !ExpectSetLocalDescription(type)) ||
(source == cricket::CS_REMOTE && !ExpectSetRemoteDescription(type))) {
- LOG_AND_RETURN_ERROR(
- RTCErrorType::INVALID_STATE,
- (rtc::StringBuilder("Called in wrong state: ")
- << PeerConnectionInterface::AsString(signaling_state()))
- .Release());
+ return RTCError(RTCErrorType::INVALID_STATE,
+ (rtc::StringBuilder("Called in wrong state: ")
+ << PeerConnectionInterface::AsString(signaling_state()))
+ .Release());
}
RTCError error = ValidateMids(*sdesc->description());
@@ -3169,14 +3216,12 @@
// Verify ice-ufrag and ice-pwd.
if (!VerifyIceUfragPwdPresent(sdesc->description(), bundle_groups_by_mid)) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
- kSdpWithoutIceUfragPwd);
+ return RTCError(RTCErrorType::INVALID_PARAMETER, kSdpWithoutIceUfragPwd);
}
if (!pc_->ValidateBundleSettings(sdesc->description(),
bundle_groups_by_mid)) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
- kBundleWithoutRtcpMux);
+ return RTCError(RTCErrorType::INVALID_PARAMETER, kBundleWithoutRtcpMux);
}
// TODO(skvlad): When the local rtcp-mux policy is Require, reject any
@@ -3192,8 +3237,7 @@
if (!MediaSectionsHaveSameCount(*offer_desc, *sdesc->description()) ||
!MediaSectionsInSameOrder(*offer_desc, nullptr, *sdesc->description(),
type)) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
- kMlineMismatchInAnswer);
+ return RTCError(RTCErrorType::INVALID_PARAMETER, kMlineMismatchInAnswer);
}
} else {
// The re-offers should respect the order of m= sections in current
@@ -3217,8 +3261,8 @@
if (current_desc &&
!MediaSectionsInSameOrder(*current_desc, secondary_current_desc,
*sdesc->description(), type)) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
- kMlineMismatchInSubsequentOffer);
+ return RTCError(RTCErrorType::INVALID_PARAMETER,
+ kMlineMismatchInSubsequentOffer);
}
}
@@ -3233,10 +3277,10 @@
if ((desc.type() == cricket::MEDIA_TYPE_AUDIO ||
desc.type() == cricket::MEDIA_TYPE_VIDEO) &&
desc.streams().size() > 1u) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
- "Media section has more than one track specified "
- "with a=ssrc lines which is not supported with "
- "Unified Plan.");
+ return RTCError(
+ RTCErrorType::INVALID_PARAMETER,
+ "Media section has more than one track specified with a=ssrc lines "
+ "which is not supported with Unified Plan.");
}
}
}
@@ -3264,9 +3308,9 @@
if (pc_->configuration()->bundle_policy ==
PeerConnectionInterface::kBundlePolicyMaxBundle &&
bundle_groups_by_mid.empty()) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
- "max-bundle configured but session description "
- "has no BUNDLE group");
+ return RTCError(
+ RTCErrorType::INVALID_PARAMETER,
+ "max-bundle configured but session description has no BUNDLE group");
}
}
@@ -3324,8 +3368,7 @@
} else if (media_type == cricket::MEDIA_TYPE_UNSUPPORTED) {
RTC_LOG(LS_INFO) << "Ignoring unsupported media type";
} else {
- LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
- "Unknown section type.");
+ return RTCError(RTCErrorType::INTERNAL_ERROR, "Unknown section type.");
}
}
@@ -3370,8 +3413,8 @@
}
if (!transceiver) {
// This may happen normally when media sections are rejected.
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
- "Transceiver not found based on m-line index");
+ return RTCError(RTCErrorType::INVALID_PARAMETER,
+ "Transceiver not found based on m-line index");
}
} else {
RTC_DCHECK_EQ(source, cricket::CS_REMOTE);
@@ -3431,9 +3474,8 @@
}
if (transceiver->media_type() != media_desc->type()) {
- LOG_AND_RETURN_ERROR(
- RTCErrorType::INVALID_PARAMETER,
- "Transceiver type does not match media description type.");
+ return RTCError(RTCErrorType::INVALID_PARAMETER,
+ "Transceiver type does not match media description type.");
}
if (media_desc->HasSimulcast()) {
@@ -3492,9 +3534,8 @@
channel = CreateVideoChannel(content.name);
}
if (!channel) {
- LOG_AND_RETURN_ERROR(
- RTCErrorType::INTERNAL_ERROR,
- "Failed to create channel for mid=" + content.name);
+ return RTCError(RTCErrorType::INTERNAL_ERROR,
+ "Failed to create channel for mid=" + content.name);
}
transceiver->internal()->SetChannel(channel);
}
@@ -3519,8 +3560,8 @@
if (!data_channel_controller()->data_channel_transport()) {
RTC_LOG(LS_INFO) << "Creating data channel, mid=" << content.mid();
if (!CreateDataChannel(content.name)) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
- "Failed to create data channel.");
+ return RTCError(RTCErrorType::INTERNAL_ERROR,
+ "Failed to create data channel.");
}
}
}
@@ -4330,12 +4371,14 @@
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(sdesc);
+ // Note: This will perform an Invoke over to the worker thread, which we'll
+ // also do in a loop below.
if (!UpdatePayloadTypeDemuxingState(source, bundle_groups_by_mid)) {
// Note that this is never expected to fail, since RtpDemuxer doesn't return
// an error when changing payload type demux criteria, which is all this
// does.
- LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
- "Failed to update payload type demuxing state.");
+ return RTCError(RTCErrorType::INTERNAL_ERROR,
+ "Failed to update payload type demuxing state.");
}
// Push down the new SDP media section for each audio/video transceiver.
@@ -4370,20 +4413,14 @@
// - crbug.com/1157227
// - crbug.com/1187289
for (const auto& entry : channels) {
- RTCError error =
- pc_->worker_thread()->Invoke<RTCError>(RTC_FROM_HERE, [&]() {
- std::string error;
- bool success =
- (source == cricket::CS_LOCAL)
- ? entry.first->SetLocalContent(entry.second, type, error)
- : entry.first->SetRemoteContent(entry.second, type, error);
- if (!success) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
- }
- return RTCError::OK();
- });
- if (!error.ok()) {
- return error;
+ std::string error;
+ bool success = pc_->worker_thread()->Invoke<bool>(RTC_FROM_HERE, [&]() {
+ return (source == cricket::CS_LOCAL)
+ ? entry.first->SetLocalContent(entry.second, type, error)
+ : entry.first->SetRemoteContent(entry.second, type, error);
+ });
+ if (!success) {
+ return RTCError(RTCErrorType::INVALID_PARAMETER, error);
}
}
@@ -4543,9 +4580,9 @@
}
}
-bool SdpOfferAnswerHandler::UseCandidatesInSessionDescription(
- const SessionDescriptionInterface* remote_desc) {
+bool SdpOfferAnswerHandler::UseCandidatesInRemoteDescription() {
RTC_DCHECK_RUN_ON(signaling_thread());
+ auto* remote_desc = remote_description();
if (!remote_desc) {
return true;
}
@@ -4559,7 +4596,7 @@
if (!ReadyToUseRemoteCandidate(candidate, remote_desc, &valid)) {
if (valid) {
RTC_LOG(LS_INFO)
- << "UseCandidatesInSessionDescription: Not ready to use "
+ << "UseCandidatesInRemoteDescription: Not ready to use "
"candidate.";
}
continue;
@@ -4674,8 +4711,8 @@
!rtp_manager()->GetAudioTransceiver()->internal()->channel()) {
cricket::VoiceChannel* voice_channel = CreateVoiceChannel(voice->name);
if (!voice_channel) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
- "Failed to create voice channel.");
+ return RTCError(RTCErrorType::INTERNAL_ERROR,
+ "Failed to create voice channel.");
}
rtp_manager()->GetAudioTransceiver()->internal()->SetChannel(voice_channel);
}
@@ -4685,8 +4722,8 @@
!rtp_manager()->GetVideoTransceiver()->internal()->channel()) {
cricket::VideoChannel* video_channel = CreateVideoChannel(video->name);
if (!video_channel) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
- "Failed to create video channel.");
+ return RTCError(RTCErrorType::INTERNAL_ERROR,
+ "Failed to create video channel.");
}
rtp_manager()->GetVideoTransceiver()->internal()->SetChannel(video_channel);
}
@@ -4695,8 +4732,8 @@
if (data && !data->rejected &&
!data_channel_controller()->data_channel_transport()) {
if (!CreateDataChannel(data->name)) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
- "Failed to create data channel.");
+ return RTCError(RTCErrorType::INTERNAL_ERROR,
+ "Failed to create data channel.");
}
}
diff --git a/pc/sdp_offer_answer.h b/pc/sdp_offer_answer.h
index 3318a4f..7349999 100644
--- a/pc/sdp_offer_answer.h
+++ b/pc/sdp_offer_answer.h
@@ -232,10 +232,14 @@
std::unique_ptr<SessionDescriptionInterface> desc,
const std::map<std::string, const cricket::ContentGroup*>&
bundle_groups_by_mid);
- RTCError ApplyRemoteDescription(
+ void ApplyRemoteDescription(
+ std::unique_ptr<RemoteDescriptionOperation> operation);
+
+ RTCError ReplaceRemoteDescription(
std::unique_ptr<SessionDescriptionInterface> desc,
- const std::map<std::string, const cricket::ContentGroup*>&
- bundle_groups_by_mid);
+ SdpType sdp_type,
+ std::unique_ptr<SessionDescriptionInterface>* replaced_description)
+ RTC_RUN_ON(signaling_thread());
// Part of ApplyRemoteDescription steps specific to Unified Plan.
void ApplyRemoteDescriptionUpdateTransceiverState(SdpType sdp_type);
@@ -496,9 +500,11 @@
// exist.
void UpdateEndedRemoteMediaStreams();
- // Uses all remote candidates in `remote_desc` in this session.
- bool UseCandidatesInSessionDescription(
- const SessionDescriptionInterface* remote_desc);
+ // Uses all remote candidates in the currently set remote_description().
+ // If no remote description is currently set (nullptr), the return value will
+ // be true. If `UseCandidate()` fails for any candidate in the remote
+ // description, the return value will be false.
+ bool UseCandidatesInRemoteDescription();
// Uses `candidate` in this session.
bool UseCandidate(const IceCandidateInterface* candidate);
// Returns true if we are ready to push down the remote candidate.