Move more functions called only in sdp_offer_answer into that file.

After this CL, sdp_offer_answer is bigger than peer_connection.

Bug: webrtc:11995
Change-Id: Ie923fabf836de46fa939fe6fd7b3d936bbc85dab
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186380
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32301}
This commit is contained in:
Harald Alvestrand
2020-10-01 16:47:23 +00:00
committed by Commit Bot
parent bd9c33ad59
commit a474fbf413
4 changed files with 661 additions and 654 deletions

View File

@ -82,17 +82,12 @@ using cricket::STUN_PORT_TYPE;
namespace webrtc {
// Error messages
const char kSessionError[] = "Session error code: ";
const char kSessionErrorDesc[] = "Session error description: ";
namespace {
// UMA metric names.
const char kSimulcastNumberOfEncodings[] =
"WebRTC.PeerConnection.Simulcast.NumberOfSendEncodings";
static const char kDefaultStreamId[] = "default";
static const char kDefaultAudioSenderId[] = "defaulta0";
static const char kDefaultVideoSenderId[] = "defaultv0";
@ -1076,6 +1071,7 @@ PeerConnection::AddTransceiver(
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const RtpTransceiverInit& init,
bool update_negotiation_needed) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK((media_type == cricket::MEDIA_TYPE_AUDIO ||
media_type == cricket::MEDIA_TYPE_VIDEO));
if (track) {
@ -1545,81 +1541,6 @@ void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer,
sdp_handler_.CreateAnswer(observer, options);
}
RTCError PeerConnection::HandleLegacyOfferOptions(
const RTCOfferAnswerOptions& options) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(IsUnifiedPlan());
if (options.offer_to_receive_audio == 0) {
RemoveRecvDirectionFromReceivingTransceiversOfType(
cricket::MEDIA_TYPE_AUDIO);
} else if (options.offer_to_receive_audio == 1) {
AddUpToOneReceivingTransceiverOfType(cricket::MEDIA_TYPE_AUDIO);
} else if (options.offer_to_receive_audio > 1) {
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER,
"offer_to_receive_audio > 1 is not supported.");
}
if (options.offer_to_receive_video == 0) {
RemoveRecvDirectionFromReceivingTransceiversOfType(
cricket::MEDIA_TYPE_VIDEO);
} else if (options.offer_to_receive_video == 1) {
AddUpToOneReceivingTransceiverOfType(cricket::MEDIA_TYPE_VIDEO);
} else if (options.offer_to_receive_video > 1) {
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER,
"offer_to_receive_video > 1 is not supported.");
}
return RTCError::OK();
}
void PeerConnection::RemoveRecvDirectionFromReceivingTransceiversOfType(
cricket::MediaType media_type) {
for (const auto& transceiver : GetReceivingTransceiversOfType(media_type)) {
RtpTransceiverDirection new_direction =
RtpTransceiverDirectionWithRecvSet(transceiver->direction(), false);
if (new_direction != transceiver->direction()) {
RTC_LOG(LS_INFO) << "Changing " << cricket::MediaTypeToString(media_type)
<< " transceiver (MID="
<< transceiver->mid().value_or("<not set>") << ") from "
<< RtpTransceiverDirectionToString(
transceiver->direction())
<< " to "
<< RtpTransceiverDirectionToString(new_direction)
<< " since CreateOffer specified offer_to_receive=0";
transceiver->internal()->set_direction(new_direction);
}
}
}
void PeerConnection::AddUpToOneReceivingTransceiverOfType(
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
if (GetReceivingTransceiversOfType(media_type).empty()) {
RTC_LOG(LS_INFO)
<< "Adding one recvonly " << cricket::MediaTypeToString(media_type)
<< " transceiver since CreateOffer specified offer_to_receive=1";
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kRecvOnly;
AddTransceiver(media_type, nullptr, init,
/*update_negotiation_needed=*/false);
}
}
std::vector<rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
PeerConnection::GetReceivingTransceiversOfType(cricket::MediaType media_type) {
std::vector<
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
receiving_transceivers;
for (const auto& transceiver : transceivers_.List()) {
if (!transceiver->stopped() && transceiver->media_type() == media_type &&
RtpTransceiverDirectionHasRecv(transceiver->direction())) {
receiving_transceivers.push_back(transceiver);
}
}
return receiving_transceivers;
}
void PeerConnection::SetLocalDescription(
SetSessionDescriptionObserver* observer,
SessionDescriptionInterface* desc_ptr) {
@ -1646,49 +1567,6 @@ void PeerConnection::SetLocalDescription(
sdp_handler_.SetLocalDescription(observer);
}
void PeerConnection::RemoveStoppedTransceivers() {
RTC_DCHECK_RUN_ON(signaling_thread());
// 3.2.10.1: For each transceiver in the connection's set of transceivers
// run the following steps:
if (!IsUnifiedPlan())
return;
// Traverse a copy of the transceiver list.
auto transceiver_list = transceivers_.List();
for (auto transceiver : transceiver_list) {
// 3.2.10.1.1: If transceiver is stopped, associated with an m= section
// and the associated m= section is rejected in
// connection.[[CurrentLocalDescription]] or
// connection.[[CurrentRemoteDescription]], remove the
// transceiver from the connection's set of transceivers.
if (!transceiver->stopped()) {
continue;
}
const ContentInfo* local_content =
sdp_handler_.FindMediaSectionForTransceiver(transceiver,
local_description());
const ContentInfo* remote_content =
sdp_handler_.FindMediaSectionForTransceiver(transceiver,
remote_description());
if ((local_content && local_content->rejected) ||
(remote_content && remote_content->rejected)) {
RTC_LOG(LS_INFO) << "Dissociating transceiver"
<< " since the media section is being recycled.";
transceiver->internal()->set_mid(absl::nullopt);
transceiver->internal()->set_mline_index(absl::nullopt);
transceivers_.Remove(transceiver);
continue;
}
if (!local_content && !remote_content) {
// TODO(bugs.webrtc.org/11973): Consider if this should be removed already
// See https://github.com/w3c/webrtc-pc/issues/2576
RTC_LOG(LS_INFO)
<< "Dropping stopped transceiver that was never associated";
transceivers_.Remove(transceiver);
continue;
}
}
}
void PeerConnection::SetRemoteDescription(
SetSessionDescriptionObserver* observer,
SessionDescriptionInterface* desc_ptr) {
@ -1703,38 +1581,6 @@ void PeerConnection::SetRemoteDescription(
sdp_handler_.SetRemoteDescription(std::move(desc), observer);
}
void PeerConnection::ProcessRemovalOfRemoteTrack(
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
transceiver,
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>* remove_list,
std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
RTC_DCHECK(transceiver->mid());
RTC_LOG(LS_INFO) << "Processing the removal of a track for MID="
<< *transceiver->mid();
std::vector<rtc::scoped_refptr<MediaStreamInterface>> previous_streams =
transceiver->internal()->receiver_internal()->streams();
// This will remove the remote track from the streams.
transceiver->internal()->receiver_internal()->set_stream_ids({});
remove_list->push_back(transceiver);
RemoveRemoteStreamsIfEmpty(previous_streams, removed_streams);
}
void PeerConnection::RemoveRemoteStreamsIfEmpty(
const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& remote_streams,
std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
RTC_DCHECK_RUN_ON(signaling_thread());
// TODO(https://crbug.com/webrtc/9480): When we use stream IDs instead of
// streams, see if the stream was removed by checking if this was the last
// receiver with that stream ID.
for (const auto& remote_stream : remote_streams) {
if (remote_stream->GetAudioTracks().empty() &&
remote_stream->GetVideoTracks().empty()) {
remote_streams_->RemoveStream(remote_stream);
removed_streams->push_back(remote_stream);
}
}
}
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
PeerConnection::GetAssociatedTransceiver(const std::string& mid) const {
RTC_DCHECK_RUN_ON(signaling_thread());
@ -2657,115 +2503,9 @@ absl::optional<std::string> PeerConnection::GetDataMid() const {
}
}
void PeerConnection::RemoveSenders(cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
UpdateLocalSenders(std::vector<cricket::StreamParams>(), media_type);
UpdateRemoteSendersList(std::vector<cricket::StreamParams>(), false,
media_type, nullptr);
}
void PeerConnection::UpdateRemoteSendersList(
const cricket::StreamParamsVec& streams,
bool default_sender_needed,
cricket::MediaType media_type,
StreamCollection* new_streams) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(!IsUnifiedPlan());
std::vector<RtpSenderInfo>* current_senders =
GetRemoteSenderInfos(media_type);
// Find removed senders. I.e., senders where the sender id or ssrc don't match
// the new StreamParam.
for (auto sender_it = current_senders->begin();
sender_it != current_senders->end();
/* incremented manually */) {
const RtpSenderInfo& info = *sender_it;
const cricket::StreamParams* params =
cricket::GetStreamBySsrc(streams, info.first_ssrc);
std::string params_stream_id;
if (params) {
params_stream_id =
(!params->first_stream_id().empty() ? params->first_stream_id()
: kDefaultStreamId);
}
bool sender_exists = params && params->id == info.sender_id &&
params_stream_id == info.stream_id;
// If this is a default track, and we still need it, don't remove it.
if ((info.stream_id == kDefaultStreamId && default_sender_needed) ||
sender_exists) {
++sender_it;
} else {
OnRemoteSenderRemoved(info, media_type);
sender_it = current_senders->erase(sender_it);
}
}
// Find new and active senders.
for (const cricket::StreamParams& params : streams) {
if (!params.has_ssrcs()) {
// The remote endpoint has streams, but didn't signal ssrcs. For an active
// sender, this means it is coming from a Unified Plan endpoint,so we just
// create a default.
default_sender_needed = true;
break;
}
// |params.id| is the sender id and the stream id uses the first of
// |params.stream_ids|. The remote description could come from a Unified
// Plan endpoint, with multiple or no stream_ids() signaled. Since this is
// not supported in Plan B, we just take the first here and create the
// default stream ID if none is specified.
const std::string& stream_id =
(!params.first_stream_id().empty() ? params.first_stream_id()
: kDefaultStreamId);
const std::string& sender_id = params.id;
uint32_t ssrc = params.first_ssrc();
rtc::scoped_refptr<MediaStreamInterface> stream =
remote_streams_->find(stream_id);
if (!stream) {
// This is a new MediaStream. Create a new remote MediaStream.
stream = MediaStreamProxy::Create(rtc::Thread::Current(),
MediaStream::Create(stream_id));
remote_streams_->AddStream(stream);
new_streams->AddStream(stream);
}
const RtpSenderInfo* sender_info =
FindSenderInfo(*current_senders, stream_id, sender_id);
if (!sender_info) {
current_senders->push_back(RtpSenderInfo(stream_id, sender_id, ssrc));
OnRemoteSenderAdded(current_senders->back(), media_type);
}
}
// Add default sender if necessary.
if (default_sender_needed) {
rtc::scoped_refptr<MediaStreamInterface> default_stream =
remote_streams_->find(kDefaultStreamId);
if (!default_stream) {
// Create the new default MediaStream.
default_stream = MediaStreamProxy::Create(
rtc::Thread::Current(), MediaStream::Create(kDefaultStreamId));
remote_streams_->AddStream(default_stream);
new_streams->AddStream(default_stream);
}
std::string default_sender_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
? kDefaultAudioSenderId
: kDefaultVideoSenderId;
const RtpSenderInfo* default_sender_info =
FindSenderInfo(*current_senders, kDefaultStreamId, default_sender_id);
if (!default_sender_info) {
current_senders->push_back(
RtpSenderInfo(kDefaultStreamId, default_sender_id, /*ssrc=*/0));
OnRemoteSenderAdded(current_senders->back(), media_type);
}
}
}
void PeerConnection::OnRemoteSenderAdded(const RtpSenderInfo& sender_info,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_LOG(LS_INFO) << "Creating " << cricket::MediaTypeToString(media_type)
<< " receiver for track_id=" << sender_info.sender_id
<< " and stream_id=" << sender_info.stream_id;
@ -2782,6 +2522,7 @@ void PeerConnection::OnRemoteSenderAdded(const RtpSenderInfo& sender_info,
void PeerConnection::OnRemoteSenderRemoved(const RtpSenderInfo& sender_info,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_LOG(LS_INFO) << "Removing " << cricket::MediaTypeToString(media_type)
<< " receiver for track_id=" << sender_info.sender_id
<< " and stream_id=" << sender_info.stream_id;
@ -2833,47 +2574,9 @@ void PeerConnection::UpdateEndedRemoteMediaStreams() {
}
}
void PeerConnection::UpdateLocalSenders(
const std::vector<cricket::StreamParams>& streams,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
std::vector<RtpSenderInfo>* current_senders = GetLocalSenderInfos(media_type);
// Find removed tracks. I.e., tracks where the track id, stream id or ssrc
// don't match the new StreamParam.
for (auto sender_it = current_senders->begin();
sender_it != current_senders->end();
/* incremented manually */) {
const RtpSenderInfo& info = *sender_it;
const cricket::StreamParams* params =
cricket::GetStreamBySsrc(streams, info.first_ssrc);
if (!params || params->id != info.sender_id ||
params->first_stream_id() != info.stream_id) {
OnLocalSenderRemoved(info, media_type);
sender_it = current_senders->erase(sender_it);
} else {
++sender_it;
}
}
// Find new and active senders.
for (const cricket::StreamParams& params : streams) {
// The sync_label is the MediaStream label and the |stream.id| is the
// sender id.
const std::string& stream_id = params.first_stream_id();
const std::string& sender_id = params.id;
uint32_t ssrc = params.first_ssrc();
const RtpSenderInfo* sender_info =
FindSenderInfo(*current_senders, stream_id, sender_id);
if (!sender_info) {
current_senders->push_back(RtpSenderInfo(stream_id, sender_id, ssrc));
OnLocalSenderAdded(current_senders->back(), media_type);
}
}
}
void PeerConnection::OnLocalSenderAdded(const RtpSenderInfo& sender_info,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(!IsUnifiedPlan());
auto sender = FindSenderById(sender_info.sender_id);
if (!sender) {
@ -2895,6 +2598,7 @@ void PeerConnection::OnLocalSenderAdded(const RtpSenderInfo& sender_info,
void PeerConnection::OnLocalSenderRemoved(const RtpSenderInfo& sender_info,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
auto sender = FindSenderById(sender_info.sender_id);
if (!sender) {
// This is the normal case. I.e., RemoveStream has been called and the
@ -3198,17 +2902,9 @@ bool PeerConnection::GetSslRole(const std::string& content_name,
return false;
}
void PeerConnection::SetSessionError(SessionError error,
const std::string& error_desc) {
RTC_DCHECK_RUN_ON(signaling_thread());
if (error != session_error_) {
session_error_ = error;
session_error_desc_ = error_desc;
}
}
void PeerConnection::UpdatePayloadTypeDemuxingState(
cricket::ContentSource source) {
RTC_DCHECK_RUN_ON(signaling_thread());
// We may need to delete any created default streams and disable creation of
// new ones on the basis of payload type. This is needed to avoid SSRC
// collisions in Call's RtpDemuxer, in the case that a transceiver has
@ -3288,107 +2984,6 @@ void PeerConnection::UpdatePayloadTypeDemuxingState(
}
}
RTCError PeerConnection::PushdownMediaDescription(
SdpType type,
cricket::ContentSource source) {
const SessionDescriptionInterface* sdesc =
(source == cricket::CS_LOCAL ? local_description()
: remote_description());
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(sdesc);
UpdatePayloadTypeDemuxingState(source);
// Push down the new SDP media section for each audio/video transceiver.
for (const auto& transceiver : transceivers_.List()) {
const ContentInfo* content_info =
sdp_handler_.FindMediaSectionForTransceiver(transceiver, sdesc);
cricket::ChannelInterface* channel = transceiver->internal()->channel();
if (!channel || !content_info || content_info->rejected) {
continue;
}
const MediaContentDescription* content_desc =
content_info->media_description();
if (!content_desc) {
continue;
}
std::string error;
bool success = (source == cricket::CS_LOCAL)
? channel->SetLocalContent(content_desc, type, &error)
: channel->SetRemoteContent(content_desc, type, &error);
if (!success) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
}
}
// If using the RtpDataChannel, push down the new SDP section for it too.
if (data_channel_controller_.rtp_data_channel()) {
const ContentInfo* data_content =
cricket::GetFirstDataContent(sdesc->description());
if (data_content && !data_content->rejected) {
const MediaContentDescription* data_desc =
data_content->media_description();
if (data_desc) {
std::string error;
bool success =
(source == cricket::CS_LOCAL)
? data_channel_controller_.rtp_data_channel()->SetLocalContent(
data_desc, type, &error)
: data_channel_controller_.rtp_data_channel()->SetRemoteContent(
data_desc, type, &error);
if (!success) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
}
}
}
}
// Need complete offer/answer with an SCTP m= section before starting SCTP,
// according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
if (sctp_mid_s_ && local_description() && remote_description()) {
rtc::scoped_refptr<SctpTransport> sctp_transport =
transport_controller_->GetSctpTransport(*sctp_mid_s_);
auto local_sctp_description = cricket::GetFirstSctpDataContentDescription(
local_description()->description());
auto remote_sctp_description = cricket::GetFirstSctpDataContentDescription(
remote_description()->description());
if (sctp_transport && local_sctp_description && remote_sctp_description) {
int max_message_size;
// A remote max message size of zero means "any size supported".
// We configure the connection with our own max message size.
if (remote_sctp_description->max_message_size() == 0) {
max_message_size = local_sctp_description->max_message_size();
} else {
max_message_size =
std::min(local_sctp_description->max_message_size(),
remote_sctp_description->max_message_size());
}
sctp_transport->Start(local_sctp_description->port(),
remote_sctp_description->port(), max_message_size);
}
}
return RTCError::OK();
}
RTCError PeerConnection::PushdownTransportDescription(
cricket::ContentSource source,
SdpType type) {
RTC_DCHECK_RUN_ON(signaling_thread());
if (source == cricket::CS_LOCAL) {
const SessionDescriptionInterface* sdesc = local_description();
RTC_DCHECK(sdesc);
return transport_controller_->SetLocalDescription(type,
sdesc->description());
} else {
const SessionDescriptionInterface* sdesc = remote_description();
RTC_DCHECK(sdesc);
return transport_controller_->SetRemoteDescription(type,
sdesc->description());
}
}
bool PeerConnection::GetTransportDescription(
const SessionDescription* description,
const std::string& content_name,
@ -3653,21 +3248,6 @@ void PeerConnection::OnTransportControllerDtlsHandshakeError(
static_cast<int>(rtc::SSLHandshakeError::MAX_VALUE));
}
void PeerConnection::EnableSending() {
RTC_DCHECK_RUN_ON(signaling_thread());
for (const auto& transceiver : transceivers_.List()) {
cricket::ChannelInterface* channel = transceiver->internal()->channel();
if (channel && !channel->enabled()) {
channel->Enable(true);
}
}
if (data_channel_controller_.rtp_data_channel() &&
!data_channel_controller_.rtp_data_channel()->enabled()) {
data_channel_controller_.rtp_data_channel()->Enable(true);
}
}
// Returns the media index for a local ice candidate given the content name.
bool PeerConnection::GetLocalCandidateMediaIndex(
const std::string& content_name,
@ -3791,26 +3371,6 @@ RTCErrorOr<const cricket::ContentInfo*> PeerConnection::FindContentInfo(
"Neither sdp_mline_index nor sdp_mid specified.");
}
void PeerConnection::RemoveUnusedChannels(const SessionDescription* desc) {
RTC_DCHECK_RUN_ON(signaling_thread());
// Destroy video channel first since it may have a pointer to the
// voice channel.
const cricket::ContentInfo* video_info = cricket::GetFirstVideoContent(desc);
if (!video_info || video_info->rejected) {
DestroyTransceiverChannel(GetVideoTransceiver());
}
const cricket::ContentInfo* audio_info = cricket::GetFirstAudioContent(desc);
if (!audio_info || audio_info->rejected) {
DestroyTransceiverChannel(GetAudioTransceiver());
}
const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc);
if (!data_info || data_info->rejected) {
DestroyDataChannelTransport();
}
}
RTCError PeerConnection::CreateChannels(const SessionDescription& desc) {
// Creating the media channels. Transports should already have been created
// at this point.
@ -4010,27 +3570,6 @@ bool PeerConnection::HasRtcpMuxEnabled(const cricket::ContentInfo* content) {
return content->media_description()->rtcp_mux();
}
const char* PeerConnection::SessionErrorToString(SessionError error) const {
switch (error) {
case SessionError::kNone:
return "ERROR_NONE";
case SessionError::kContent:
return "ERROR_CONTENT";
case SessionError::kTransport:
return "ERROR_TRANSPORT";
}
RTC_NOTREACHED();
return "";
}
std::string PeerConnection::GetSessionErrorMsg() {
RTC_DCHECK_RUN_ON(signaling_thread());
rtc::StringBuilder desc;
desc << kSessionError << SessionErrorToString(session_error()) << ". ";
desc << kSessionErrorDesc << session_error_desc() << ".";
return desc.Release();
}
void PeerConnection::ReportSdpFormatReceived(
const SessionDescriptionInterface& remote_offer) {
int num_audio_mlines = 0;
@ -4120,30 +3659,6 @@ void PeerConnection::ReportUsagePattern() const {
}
}
void PeerConnection::ReportNegotiatedSdpSemantics(
const SessionDescriptionInterface& answer) {
SdpSemanticNegotiated semantics_negotiated;
switch (answer.description()->msid_signaling()) {
case 0:
semantics_negotiated = kSdpSemanticNegotiatedNone;
break;
case cricket::kMsidSignalingMediaSection:
semantics_negotiated = kSdpSemanticNegotiatedUnifiedPlan;
break;
case cricket::kMsidSignalingSsrcAttribute:
semantics_negotiated = kSdpSemanticNegotiatedPlanB;
break;
case cricket::kMsidSignalingMediaSection |
cricket::kMsidSignalingSsrcAttribute:
semantics_negotiated = kSdpSemanticNegotiatedMixed;
break;
default:
RTC_NOTREACHED();
}
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SdpSemanticNegotiated",
semantics_negotiated, kSdpSemanticNegotiatedMax);
}
// We need to check the local/remote description for the Transport instead of
// the session, because a new Transport added during renegotiation may have
// them unset while the session has them set from the previous negotiation.

View File

@ -363,6 +363,10 @@ class PeerConnection : public PeerConnectionInternal,
RTC_DCHECK_RUN_ON(signaling_thread());
return &mid_generator_;
}
absl::optional<std::string> sctp_mid() {
RTC_DCHECK_RUN_ON(signaling_thread());
return sctp_mid_s_;
}
// Functions made public for testing.
void ReturnHistogramVeryQuicklyForTesting() {
@ -370,10 +374,6 @@ class PeerConnection : public PeerConnectionInternal,
return_histogram_very_quickly_ = true;
}
void RequestUsagePatternReportForTesting();
absl::optional<std::string> sctp_mid() {
RTC_DCHECK_RUN_ON(signaling_thread());
return sctp_mid_s_;
}
protected:
~PeerConnection() override;
@ -426,9 +426,6 @@ class PeerConnection : public PeerConnectionInternal,
GetFirstAudioTransceiver() const RTC_RUN_ON(signaling_thread());
// Helper function to remove stopped transceivers.
void RemoveStoppedTransceivers();
void CreateAudioReceiver(MediaStreamInterface* stream,
const RtpSenderInfo& remote_sender_info)
RTC_RUN_ON(signaling_thread());
@ -480,7 +477,7 @@ class PeerConnection : public PeerConnectionInternal,
cricket::MediaType media_type,
rtc::scoped_refptr<MediaStreamTrackInterface> track,
const RtpTransceiverInit& init,
bool fire_callback = true) RTC_RUN_ON(signaling_thread());
bool fire_callback = true);
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
CreateSender(cricket::MediaType media_type,
@ -560,37 +557,9 @@ class PeerConnection : public PeerConnectionInternal,
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
GetTransceiverByMLineIndex(size_t mline_index) const;
// Runs the algorithm **process the removal of a remote track** specified in
// the WebRTC specification.
// This method will update the following lists:
// |remove_list| is the list of transceivers for which the receiving track is
// being removed.
// |removed_streams| is the list of streams which no longer have a receiving
// track so should be removed.
// https://w3c.github.io/webrtc-pc/#process-remote-track-removal
void ProcessRemovalOfRemoteTrack(
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
transceiver,
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>* remove_list,
std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams);
void RemoveRemoteStreamsIfEmpty(
const std::vector<rtc::scoped_refptr<MediaStreamInterface>>&
remote_streams,
std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams);
void OnNegotiationNeeded();
RTCError HandleLegacyOfferOptions(const RTCOfferAnswerOptions& options);
void RemoveRecvDirectionFromReceivingTransceiversOfType(
cricket::MediaType media_type) RTC_RUN_ON(signaling_thread());
void AddUpToOneReceivingTransceiverOfType(cricket::MediaType media_type);
std::vector<
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
GetReceivingTransceiversOfType(cricket::MediaType media_type)
RTC_RUN_ON(signaling_thread());
// Generates MediaDescriptionOptions for the |session_opts| based on existing
// local description or remote description.
void GenerateMediaDescriptionOptions(
@ -617,56 +586,30 @@ class PeerConnection : public PeerConnectionInternal,
// channels are configured this will return nullopt.
absl::optional<std::string> GetDataMid() const;
// Remove all local and remote senders of type |media_type|.
// Called when a media type is rejected (m-line set to port 0).
void RemoveSenders(cricket::MediaType media_type);
// Makes sure a MediaStreamTrack is created for each StreamParam in |streams|,
// and existing MediaStreamTracks are removed if there is no corresponding
// StreamParam. If |default_track_needed| is true, a default MediaStreamTrack
// is created if it doesn't exist; if false, it's removed if it exists.
// |media_type| is the type of the |streams| and can be either audio or video.
// If a new MediaStream is created it is added to |new_streams|.
void UpdateRemoteSendersList(
const std::vector<cricket::StreamParams>& streams,
bool default_track_needed,
cricket::MediaType media_type,
StreamCollection* new_streams);
// Triggered when a remote sender has been seen for the first time in a remote
// session description. It creates a remote MediaStreamTrackInterface
// implementation and triggers CreateAudioReceiver or CreateVideoReceiver.
void OnRemoteSenderAdded(const RtpSenderInfo& sender_info,
cricket::MediaType media_type)
RTC_RUN_ON(signaling_thread());
cricket::MediaType media_type);
// Triggered when a remote sender has been removed from a remote session
// description. It removes the remote sender with id |sender_id| from a remote
// MediaStream and triggers DestroyAudioReceiver or DestroyVideoReceiver.
void OnRemoteSenderRemoved(const RtpSenderInfo& sender_info,
cricket::MediaType media_type)
RTC_RUN_ON(signaling_thread());
cricket::MediaType media_type);
// Finds remote MediaStreams without any tracks and removes them from
// |remote_streams_| and notifies the observer that the MediaStreams no longer
// exist.
void UpdateEndedRemoteMediaStreams();
// Loops through the vector of |streams| and finds added and removed
// StreamParams since last time this method was called.
// For each new or removed StreamParam, OnLocalSenderSeen or
// OnLocalSenderRemoved is invoked.
void UpdateLocalSenders(const std::vector<cricket::StreamParams>& streams,
cricket::MediaType media_type);
// Triggered when a local sender has been seen for the first time in a local
// session description.
// This method triggers CreateAudioSender or CreateVideoSender if the rtp
// streams in the local SessionDescription can be mapped to a MediaStreamTrack
// in a MediaStream in |local_streams_|
void OnLocalSenderAdded(const RtpSenderInfo& sender_info,
cricket::MediaType media_type)
RTC_RUN_ON(signaling_thread());
cricket::MediaType media_type);
// Triggered when a local sender has been removed from a local session
// description.
@ -674,8 +617,7 @@ class PeerConnection : public PeerConnectionInternal,
// has been removed from the local SessionDescription and the stream can be
// mapped to a MediaStreamTrack in a MediaStream in |local_streams_|.
void OnLocalSenderRemoved(const RtpSenderInfo& sender_info,
cricket::MediaType media_type)
RTC_RUN_ON(signaling_thread());
cricket::MediaType media_type);
// Returns true if the PeerConnection is configured to use Unified Plan
// semantics for creating offers/answers and setting local/remote
@ -753,19 +695,6 @@ class PeerConnection : public PeerConnectionInternal,
cricket::ChannelManager* channel_manager() const;
enum class SessionError {
kNone, // No error.
kContent, // Error in BaseChannel SetLocalContent/SetRemoteContent.
kTransport, // Error from the underlying transport.
};
// Returns the last error in the session. See the enum above for details.
SessionError session_error() const {
RTC_DCHECK_RUN_ON(signaling_thread());
return session_error_;
}
const std::string& session_error_desc() const { return session_error_desc_; }
cricket::ChannelInterface* GetChannel(const std::string& content_name);
cricket::IceConfig ParseIceConfig(
@ -778,20 +707,9 @@ class PeerConnection : public PeerConnectionInternal,
void OnCertificateReady(
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
// Updates the error state, signaling if necessary.
void SetSessionError(SessionError error, const std::string& error_desc);
// Based on number of transceivers per media type, enabled or disable
// payload type based demuxing in the affected channels.
void UpdatePayloadTypeDemuxingState(cricket::ContentSource source)
RTC_RUN_ON(signaling_thread());
// Push the media parts of the local or remote session description
// down to all of the channels.
RTCError PushdownMediaDescription(SdpType type,
cricket::ContentSource source);
RTCError PushdownTransportDescription(cricket::ContentSource source,
SdpType type);
void UpdatePayloadTypeDemuxingState(cricket::ContentSource source);
// Returns true and the TransportInfo of the given |content_name|
// from |description|. Returns false if it's not available.
@ -800,11 +718,6 @@ class PeerConnection : public PeerConnectionInternal,
const std::string& content_name,
cricket::TransportDescription* info);
// Enables media channels to allow sending of media.
// This enables media to flow on all configured audio/video channels and the
// RtpDataChannel.
void EnableSending();
// Destroys all BaseChannels and destroys the SCTP data channel, if present.
void DestroyAllChannels() RTC_RUN_ON(signaling_thread());
@ -822,9 +735,6 @@ class PeerConnection : public PeerConnectionInternal,
RTCErrorOr<const cricket::ContentInfo*> FindContentInfo(
const SessionDescriptionInterface* description,
const IceCandidateInterface* candidate) RTC_RUN_ON(signaling_thread());
// Deletes the corresponding channel of contents that don't exist in |desc|.
// |desc| can be null. This means that all channels are deleted.
void RemoveUnusedChannels(const cricket::SessionDescription* desc);
// Allocates media channels based on the |desc|. If |desc| doesn't have
// the BUNDLE option, this method will disable BUNDLE in PortAllocator.
@ -879,16 +789,9 @@ class PeerConnection : public PeerConnectionInternal,
RTC_RUN_ON(signaling_thread());
void OnTransportControllerDtlsHandshakeError(rtc::SSLHandshakeError error);
const char* SessionErrorToString(SessionError error) const;
std::string GetSessionErrorMsg();
// Report the UMA metric SdpFormatReceived for the given remote offer.
void ReportSdpFormatReceived(const SessionDescriptionInterface& remote_offer);
// Report inferred negotiated SDP semantics from a local/remote answer to the
// UMA observer.
void ReportNegotiatedSdpSemantics(const SessionDescriptionInterface& answer);
// Invoked when TransportController connection completion is signaled.
// Reports stats for all transports in use.
void ReportTransportStats() RTC_RUN_ON(signaling_thread());
@ -1055,10 +958,6 @@ class PeerConnection : public PeerConnectionInternal,
// all the MIDs that have been seen over the life of the PeerConnection.
rtc::UniqueStringGenerator mid_generator_ RTC_GUARDED_BY(signaling_thread());
SessionError session_error_ RTC_GUARDED_BY(signaling_thread()) =
SessionError::kNone;
std::string session_error_desc_ RTC_GUARDED_BY(signaling_thread());
std::string session_id_ RTC_GUARDED_BY(signaling_thread());
std::unique_ptr<JsepTransportController>

View File

@ -64,6 +64,9 @@ const char kSdpWithoutDtlsFingerprint[] =
"Called with SDP without DTLS fingerprint.";
const char kSdpWithoutSdesCrypto[] = "Called with SDP without SDES crypto.";
const char kSessionError[] = "Session error code: ";
const char kSessionErrorDesc[] = "Session error description: ";
// UMA metric names.
const char kSimulcastVersionApplyLocalDescription[] =
"WebRTC.PeerConnection.Simulcast.ApplyLocalDescription";
@ -71,6 +74,11 @@ const char kSimulcastVersionApplyRemoteDescription[] =
"WebRTC.PeerConnection.Simulcast.ApplyRemoteDescription";
const char kSimulcastDisabled[] = "WebRTC.PeerConnection.Simulcast.Disabled";
const char kDefaultStreamId[] = "default";
// NOTE: Duplicated in peer_connection.cc:
static const char kDefaultAudioSenderId[] = "defaulta0";
static const char kDefaultVideoSenderId[] = "defaultv0";
void NoteAddIceCandidateResult(int result) {
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.AddIceCandidate", result,
kAddIceCandidateMax);
@ -1064,7 +1072,7 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
}
}
RTCError error = pc_->PushdownTransportDescription(cricket::CS_LOCAL, type);
RTCError error = PushdownTransportDescription(cricket::CS_LOCAL, type);
if (!error.ok()) {
return error;
}
@ -1088,7 +1096,8 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
// information about DTLS transports.
if (transceiver->mid()) {
auto dtls_transport =
pc_->LookupDtlsTransportByMidInternal(*transceiver->mid());
pc_->transport_controller_->LookupDtlsTransportByMid(
*transceiver->mid());
transceiver->internal()->sender_internal()->set_transport(
dtls_transport);
transceiver->internal()->receiver_internal()->set_transport(
@ -1112,8 +1121,8 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
(transceiver->internal()->fired_direction() &&
RtpTransceiverDirectionHasRecv(
*transceiver->internal()->fired_direction()))) {
pc_->ProcessRemovalOfRemoteTrack(transceiver, &remove_list,
&removed_streams);
ProcessRemovalOfRemoteTrack(transceiver, &remove_list,
&removed_streams);
}
// 2.2.7.1.6.2: Set transceiver's [[CurrentDirection]] and
// [[FiredDirection]] slots to direction.
@ -1140,7 +1149,7 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
}
}
// Remove unused channels if MediaContentDescription is rejected.
pc_->RemoveUnusedChannels(local_description()->description());
RemoveUnusedChannels(local_description()->description());
}
error = UpdateSessionState(type, cricket::CS_LOCAL,
@ -1155,9 +1164,8 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
}
pending_ice_restarts_.clear();
if (pc_->session_error() != PeerConnection::SessionError::kNone) {
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
pc_->GetSessionErrorMsg());
if (session_error() != SessionError::kNone) {
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, GetSessionErrorMsg());
}
// If setting the description decided our SSL role, allocate any necessary
@ -1202,11 +1210,11 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
GetFirstAudioContent(local_description()->description());
if (audio_content) {
if (audio_content->rejected) {
pc_->RemoveSenders(cricket::MEDIA_TYPE_AUDIO);
RemoveSenders(cricket::MEDIA_TYPE_AUDIO);
} else {
const cricket::AudioContentDescription* audio_desc =
audio_content->media_description()->as_audio();
pc_->UpdateLocalSenders(audio_desc->streams(), audio_desc->type());
UpdateLocalSenders(audio_desc->streams(), audio_desc->type());
}
}
@ -1214,11 +1222,11 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
GetFirstVideoContent(local_description()->description());
if (video_content) {
if (video_content->rejected) {
pc_->RemoveSenders(cricket::MEDIA_TYPE_VIDEO);
RemoveSenders(cricket::MEDIA_TYPE_VIDEO);
} else {
const cricket::VideoContentDescription* video_desc =
video_content->media_description()->as_video();
pc_->UpdateLocalSenders(video_desc->streams(), video_desc->type());
UpdateLocalSenders(video_desc->streams(), video_desc->type());
}
}
}
@ -1346,7 +1354,7 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
ReportSimulcastApiVersion(kSimulcastVersionApplyRemoteDescription,
*remote_description()->description());
RTCError error = pc_->PushdownTransportDescription(cricket::CS_REMOTE, type);
RTCError error = PushdownTransportDescription(cricket::CS_REMOTE, type);
if (!error.ok()) {
return error;
}
@ -1371,7 +1379,7 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
}
}
// Remove unused channels if MediaContentDescription is rejected.
pc_->RemoveUnusedChannels(remote_description()->description());
RemoveUnusedChannels(remote_description()->description());
}
// NOTE: Candidates allocation will be initiated only when
@ -1414,9 +1422,8 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
}
}
if (pc_->session_error() != PeerConnection::SessionError::kNone) {
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
pc_->GetSessionErrorMsg());
if (session_error() != SessionError::kNone) {
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, GetSessionErrorMsg());
}
// Set the the ICE connection state to connecting since the connection may
@ -1493,8 +1500,8 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
if (!RtpTransceiverDirectionHasRecv(local_direction) &&
(transceiver->fired_direction() &&
RtpTransceiverDirectionHasRecv(*transceiver->fired_direction()))) {
pc_->ProcessRemovalOfRemoteTrack(transceiver, &remove_list,
&removed_streams);
ProcessRemovalOfRemoteTrack(transceiver, &remove_list,
&removed_streams);
}
// 2.2.8.1.10: Set transceiver's [[FiredDirection]] slot to direction.
transceiver->internal()->set_fired_direction(local_direction);
@ -1507,7 +1514,8 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
// 2.2.8.1.11.[3-6]: Set the transport internal slots.
if (transceiver->mid()) {
auto dtls_transport =
pc_->LookupDtlsTransportByMidInternal(*transceiver->mid());
pc_->transport_controller_->LookupDtlsTransportByMid(
*transceiver->mid());
transceiver->internal()->sender_internal()->set_transport(
dtls_transport);
transceiver->internal()->receiver_internal()->set_transport(
@ -1589,14 +1597,14 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
// and MediaStreams.
if (audio_content) {
if (audio_content->rejected) {
pc_->RemoveSenders(cricket::MEDIA_TYPE_AUDIO);
RemoveSenders(cricket::MEDIA_TYPE_AUDIO);
} else {
bool default_audio_track_needed =
!remote_peer_supports_msid_ &&
RtpTransceiverDirectionHasSend(audio_desc->direction());
pc_->UpdateRemoteSendersList(GetActiveStreams(audio_desc),
default_audio_track_needed,
audio_desc->type(), new_streams);
UpdateRemoteSendersList(GetActiveStreams(audio_desc),
default_audio_track_needed, audio_desc->type(),
new_streams);
}
}
@ -1604,14 +1612,14 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
// and MediaStreams.
if (video_content) {
if (video_content->rejected) {
pc_->RemoveSenders(cricket::MEDIA_TYPE_VIDEO);
RemoveSenders(cricket::MEDIA_TYPE_VIDEO);
} else {
bool default_video_track_needed =
!remote_peer_supports_msid_ &&
RtpTransceiverDirectionHasSend(video_desc->direction());
pc_->UpdateRemoteSendersList(GetActiveStreams(video_desc),
default_video_track_needed,
video_desc->type(), new_streams);
UpdateRemoteSendersList(GetActiveStreams(video_desc),
default_video_track_needed, video_desc->type(),
new_streams);
}
}
@ -1662,8 +1670,8 @@ void SdpOfferAnswerHandler::DoSetLocalDescription(
// If a session error has occurred the PeerConnection is in a possibly
// inconsistent state so fail right away.
if (pc_->session_error() != PeerConnection::SessionError::kNone) {
std::string error_message = pc_->GetSessionErrorMsg();
if (session_error() != SessionError::kNone) {
std::string error_message = GetSessionErrorMsg();
RTC_LOG(LS_ERROR) << "SetLocalDescription: " << error_message;
observer->OnSetLocalDescriptionComplete(
RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
@ -1703,8 +1711,7 @@ void SdpOfferAnswerHandler::DoSetLocalDescription(
// If ApplyLocalDescription 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.
pc_->SetSessionError(PeerConnection::SessionError::kContent,
error.message());
SetSessionError(SessionError::kContent, error.message());
std::string error_message =
GetSetDescriptionErrorMessage(cricket::CS_LOCAL, type, error);
RTC_LOG(LS_ERROR) << error_message;
@ -1715,7 +1722,7 @@ void SdpOfferAnswerHandler::DoSetLocalDescription(
RTC_DCHECK(local_description());
if (local_description()->GetType() == SdpType::kAnswer) {
pc_->RemoveStoppedTransceivers();
RemoveStoppedTransceivers();
// TODO(deadbeef): We already had to hop to the network thread for
// MaybeStartGathering...
@ -1723,7 +1730,7 @@ void SdpOfferAnswerHandler::DoSetLocalDescription(
RTC_FROM_HERE, rtc::Bind(&cricket::PortAllocator::DiscardCandidatePool,
pc_->port_allocator_.get()));
// Make UMA notes about what was agreed to.
pc_->ReportNegotiatedSdpSemantics(*local_description());
ReportNegotiatedSdpSemantics(*local_description());
}
observer->OnSetLocalDescriptionComplete(RTCError::OK());
@ -1772,8 +1779,8 @@ void SdpOfferAnswerHandler::DoCreateOffer(
// If a session error has occurred the PeerConnection is in a possibly
// inconsistent state so fail right away.
if (pc_->session_error() != PeerConnection::SessionError::kNone) {
std::string error_message = pc_->GetSessionErrorMsg();
if (session_error() != SessionError::kNone) {
std::string error_message = GetSessionErrorMsg();
RTC_LOG(LS_ERROR) << "CreateOffer: " << error_message;
pc_->PostCreateSessionDescriptionFailure(
observer,
@ -1792,7 +1799,7 @@ void SdpOfferAnswerHandler::DoCreateOffer(
// 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 = pc_->HandleLegacyOfferOptions(options);
RTCError error = HandleLegacyOfferOptions(options);
if (!error.ok()) {
pc_->PostCreateSessionDescriptionFailure(observer, std::move(error));
return;
@ -1846,8 +1853,8 @@ void SdpOfferAnswerHandler::DoCreateAnswer(
// If a session error has occurred the PeerConnection is in a possibly
// inconsistent state so fail right away.
if (pc_->session_error() != PeerConnection::SessionError::kNone) {
std::string error_message = pc_->GetSessionErrorMsg();
if (session_error() != SessionError::kNone) {
std::string error_message = GetSessionErrorMsg();
RTC_LOG(LS_ERROR) << "CreateAnswer: " << error_message;
pc_->PostCreateSessionDescriptionFailure(
observer,
@ -1908,8 +1915,8 @@ void SdpOfferAnswerHandler::DoSetRemoteDescription(
// If a session error has occurred the PeerConnection is in a possibly
// inconsistent state so fail right away.
if (pc_->session_error() != PeerConnection::SessionError::kNone) {
std::string error_message = pc_->GetSessionErrorMsg();
if (session_error() != SessionError::kNone) {
std::string error_message = GetSessionErrorMsg();
RTC_LOG(LS_ERROR) << "SetRemoteDescription: " << error_message;
observer->OnSetRemoteDescriptionComplete(
RTCError(RTCErrorType::INTERNAL_ERROR, std::move(error_message)));
@ -1963,8 +1970,7 @@ void SdpOfferAnswerHandler::DoSetRemoteDescription(
// 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.
pc_->SetSessionError(PeerConnection::SessionError::kContent,
error.message());
SetSessionError(SessionError::kContent, error.message());
std::string error_message =
GetSetDescriptionErrorMessage(cricket::CS_REMOTE, type, error);
RTC_LOG(LS_ERROR) << error_message;
@ -1975,14 +1981,14 @@ void SdpOfferAnswerHandler::DoSetRemoteDescription(
RTC_DCHECK(remote_description());
if (type == SdpType::kAnswer) {
pc_->RemoveStoppedTransceivers();
RemoveStoppedTransceivers();
// TODO(deadbeef): We already had to hop to the network thread for
// MaybeStartGathering...
pc_->network_thread()->Invoke<void>(
RTC_FROM_HERE, rtc::Bind(&cricket::PortAllocator::DiscardCandidatePool,
pc_->port_allocator_.get()));
// Make UMA notes about what was agreed to.
pc_->ReportNegotiatedSdpSemantics(*remote_description());
ReportNegotiatedSdpSemantics(*remote_description());
}
observer->OnSetRemoteDescriptionComplete(RTCError::OK());
@ -2043,7 +2049,7 @@ void SdpOfferAnswerHandler::SetAssociatedRemoteStreams(
// TODO(hbos): When we remove remote_streams(), use set_stream_ids()
// instead. https://crbug.com/webrtc/9480
receiver->SetStreams(media_streams);
pc_->RemoveRemoteStreamsIfEmpty(previous_streams, removed_streams);
RemoveRemoteStreamsIfEmpty(previous_streams, removed_streams);
}
bool SdpOfferAnswerHandler::AddIceCandidate(
@ -2253,11 +2259,11 @@ RTCError SdpOfferAnswerHandler::UpdateSessionState(
// If there's already a pending error then no state transition should happen.
// But all call-sites should be verifying this before calling us!
RTC_DCHECK(pc_->session_error() == PeerConnection::SessionError::kNone);
RTC_DCHECK(session_error() == SessionError::kNone);
// If this is answer-ish we're ready to let media flow.
if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
pc_->EnableSending();
EnableSending();
}
// Update the signaling state according to the specified state machine (see
@ -2279,7 +2285,7 @@ RTCError SdpOfferAnswerHandler::UpdateSessionState(
// Update internal objects according to the session description's media
// descriptions.
RTCError error = pc_->PushdownMediaDescription(type, source);
RTCError error = PushdownMediaDescription(type, source);
if (!error.ok()) {
return error;
}
@ -2656,9 +2662,8 @@ void SdpOfferAnswerHandler::GenerateNegotiationNeededEvent() {
RTCError SdpOfferAnswerHandler::ValidateSessionDescription(
const SessionDescriptionInterface* sdesc,
cricket::ContentSource source) {
if (pc_->session_error() != PeerConnection::SessionError::kNone) {
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
pc_->GetSessionErrorMsg());
if (session_error() != SessionError::kNone) {
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, GetSessionErrorMsg());
}
if (!sdesc || !sdesc->description()) {
@ -3541,4 +3546,496 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanAnswer(
}
}
const char* SdpOfferAnswerHandler::SessionErrorToString(
SessionError error) const {
switch (error) {
case SessionError::kNone:
return "ERROR_NONE";
case SessionError::kContent:
return "ERROR_CONTENT";
case SessionError::kTransport:
return "ERROR_TRANSPORT";
}
RTC_NOTREACHED();
return "";
}
std::string SdpOfferAnswerHandler::GetSessionErrorMsg() {
RTC_DCHECK_RUN_ON(signaling_thread());
rtc::StringBuilder desc;
desc << kSessionError << SessionErrorToString(session_error()) << ". ";
desc << kSessionErrorDesc << session_error_desc() << ".";
return desc.Release();
}
void SdpOfferAnswerHandler::SetSessionError(SessionError error,
const std::string& error_desc) {
RTC_DCHECK_RUN_ON(signaling_thread());
if (error != session_error_) {
session_error_ = error;
session_error_desc_ = error_desc;
}
}
RTCError SdpOfferAnswerHandler::HandleLegacyOfferOptions(
const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(IsUnifiedPlan());
if (options.offer_to_receive_audio == 0) {
RemoveRecvDirectionFromReceivingTransceiversOfType(
cricket::MEDIA_TYPE_AUDIO);
} else if (options.offer_to_receive_audio == 1) {
AddUpToOneReceivingTransceiverOfType(cricket::MEDIA_TYPE_AUDIO);
} else if (options.offer_to_receive_audio > 1) {
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER,
"offer_to_receive_audio > 1 is not supported.");
}
if (options.offer_to_receive_video == 0) {
RemoveRecvDirectionFromReceivingTransceiversOfType(
cricket::MEDIA_TYPE_VIDEO);
} else if (options.offer_to_receive_video == 1) {
AddUpToOneReceivingTransceiverOfType(cricket::MEDIA_TYPE_VIDEO);
} else if (options.offer_to_receive_video > 1) {
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_PARAMETER,
"offer_to_receive_video > 1 is not supported.");
}
return RTCError::OK();
}
void SdpOfferAnswerHandler::RemoveRecvDirectionFromReceivingTransceiversOfType(
cricket::MediaType media_type) {
for (const auto& transceiver : GetReceivingTransceiversOfType(media_type)) {
RtpTransceiverDirection new_direction =
RtpTransceiverDirectionWithRecvSet(transceiver->direction(), false);
if (new_direction != transceiver->direction()) {
RTC_LOG(LS_INFO) << "Changing " << cricket::MediaTypeToString(media_type)
<< " transceiver (MID="
<< transceiver->mid().value_or("<not set>") << ") from "
<< RtpTransceiverDirectionToString(
transceiver->direction())
<< " to "
<< RtpTransceiverDirectionToString(new_direction)
<< " since CreateOffer specified offer_to_receive=0";
transceiver->internal()->set_direction(new_direction);
}
}
}
void SdpOfferAnswerHandler::AddUpToOneReceivingTransceiverOfType(
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
if (GetReceivingTransceiversOfType(media_type).empty()) {
RTC_LOG(LS_INFO)
<< "Adding one recvonly " << cricket::MediaTypeToString(media_type)
<< " transceiver since CreateOffer specified offer_to_receive=1";
RtpTransceiverInit init;
init.direction = RtpTransceiverDirection::kRecvOnly;
pc_->AddTransceiver(media_type, nullptr, init,
/*update_negotiation_needed=*/false);
}
}
std::vector<rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
SdpOfferAnswerHandler::GetReceivingTransceiversOfType(
cricket::MediaType media_type) {
std::vector<
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
receiving_transceivers;
for (const auto& transceiver : pc_->transceivers_.List()) {
if (!transceiver->stopped() && transceiver->media_type() == media_type &&
RtpTransceiverDirectionHasRecv(transceiver->direction())) {
receiving_transceivers.push_back(transceiver);
}
}
return receiving_transceivers;
}
void SdpOfferAnswerHandler::ProcessRemovalOfRemoteTrack(
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
transceiver,
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>* remove_list,
std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
RTC_DCHECK(transceiver->mid());
RTC_LOG(LS_INFO) << "Processing the removal of a track for MID="
<< *transceiver->mid();
std::vector<rtc::scoped_refptr<MediaStreamInterface>> previous_streams =
transceiver->internal()->receiver_internal()->streams();
// This will remove the remote track from the streams.
transceiver->internal()->receiver_internal()->set_stream_ids({});
remove_list->push_back(transceiver);
RemoveRemoteStreamsIfEmpty(previous_streams, removed_streams);
}
void SdpOfferAnswerHandler::RemoveRemoteStreamsIfEmpty(
const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& remote_streams,
std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
RTC_DCHECK_RUN_ON(signaling_thread());
// TODO(https://crbug.com/webrtc/9480): When we use stream IDs instead of
// streams, see if the stream was removed by checking if this was the last
// receiver with that stream ID.
for (const auto& remote_stream : remote_streams) {
if (remote_stream->GetAudioTracks().empty() &&
remote_stream->GetVideoTracks().empty()) {
pc_->remote_streams_internal()->RemoveStream(remote_stream);
removed_streams->push_back(remote_stream);
}
}
}
void SdpOfferAnswerHandler::RemoveSenders(cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
UpdateLocalSenders(std::vector<cricket::StreamParams>(), media_type);
UpdateRemoteSendersList(std::vector<cricket::StreamParams>(), false,
media_type, nullptr);
}
void SdpOfferAnswerHandler::UpdateLocalSenders(
const std::vector<cricket::StreamParams>& streams,
cricket::MediaType media_type) {
RTC_DCHECK_RUN_ON(signaling_thread());
std::vector<PeerConnection::RtpSenderInfo>* current_senders =
pc_->GetLocalSenderInfos(media_type);
// Find removed tracks. I.e., tracks where the track id, stream id or ssrc
// don't match the new StreamParam.
for (auto sender_it = current_senders->begin();
sender_it != current_senders->end();
/* incremented manually */) {
const PeerConnection::RtpSenderInfo& info = *sender_it;
const cricket::StreamParams* params =
cricket::GetStreamBySsrc(streams, info.first_ssrc);
if (!params || params->id != info.sender_id ||
params->first_stream_id() != info.stream_id) {
pc_->OnLocalSenderRemoved(info, media_type);
sender_it = current_senders->erase(sender_it);
} else {
++sender_it;
}
}
// Find new and active senders.
for (const cricket::StreamParams& params : streams) {
// The sync_label is the MediaStream label and the |stream.id| is the
// sender id.
const std::string& stream_id = params.first_stream_id();
const std::string& sender_id = params.id;
uint32_t ssrc = params.first_ssrc();
const PeerConnection::RtpSenderInfo* sender_info =
pc_->FindSenderInfo(*current_senders, stream_id, sender_id);
if (!sender_info) {
current_senders->push_back(
PeerConnection::RtpSenderInfo(stream_id, sender_id, ssrc));
pc_->OnLocalSenderAdded(current_senders->back(), media_type);
}
}
}
void SdpOfferAnswerHandler::UpdateRemoteSendersList(
const cricket::StreamParamsVec& streams,
bool default_sender_needed,
cricket::MediaType media_type,
StreamCollection* new_streams) {
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(!IsUnifiedPlan());
std::vector<PeerConnection::RtpSenderInfo>* current_senders =
pc_->GetRemoteSenderInfos(media_type);
// Find removed senders. I.e., senders where the sender id or ssrc don't match
// the new StreamParam.
for (auto sender_it = current_senders->begin();
sender_it != current_senders->end();
/* incremented manually */) {
const PeerConnection::RtpSenderInfo& info = *sender_it;
const cricket::StreamParams* params =
cricket::GetStreamBySsrc(streams, info.first_ssrc);
std::string params_stream_id;
if (params) {
params_stream_id =
(!params->first_stream_id().empty() ? params->first_stream_id()
: kDefaultStreamId);
}
bool sender_exists = params && params->id == info.sender_id &&
params_stream_id == info.stream_id;
// If this is a default track, and we still need it, don't remove it.
if ((info.stream_id == kDefaultStreamId && default_sender_needed) ||
sender_exists) {
++sender_it;
} else {
pc_->OnRemoteSenderRemoved(info, media_type);
sender_it = current_senders->erase(sender_it);
}
}
// Find new and active senders.
for (const cricket::StreamParams& params : streams) {
if (!params.has_ssrcs()) {
// The remote endpoint has streams, but didn't signal ssrcs. For an active
// sender, this means it is coming from a Unified Plan endpoint,so we just
// create a default.
default_sender_needed = true;
break;
}
// |params.id| is the sender id and the stream id uses the first of
// |params.stream_ids|. The remote description could come from a Unified
// Plan endpoint, with multiple or no stream_ids() signaled. Since this is
// not supported in Plan B, we just take the first here and create the
// default stream ID if none is specified.
const std::string& stream_id =
(!params.first_stream_id().empty() ? params.first_stream_id()
: kDefaultStreamId);
const std::string& sender_id = params.id;
uint32_t ssrc = params.first_ssrc();
rtc::scoped_refptr<MediaStreamInterface> stream =
pc_->remote_streams_internal()->find(stream_id);
if (!stream) {
// This is a new MediaStream. Create a new remote MediaStream.
stream = MediaStreamProxy::Create(rtc::Thread::Current(),
MediaStream::Create(stream_id));
pc_->remote_streams_internal()->AddStream(stream);
new_streams->AddStream(stream);
}
const PeerConnection::RtpSenderInfo* sender_info =
pc_->FindSenderInfo(*current_senders, stream_id, sender_id);
if (!sender_info) {
current_senders->push_back(
PeerConnection::RtpSenderInfo(stream_id, sender_id, ssrc));
pc_->OnRemoteSenderAdded(current_senders->back(), media_type);
}
}
// Add default sender if necessary.
if (default_sender_needed) {
rtc::scoped_refptr<MediaStreamInterface> default_stream =
pc_->remote_streams_internal()->find(kDefaultStreamId);
if (!default_stream) {
// Create the new default MediaStream.
default_stream = MediaStreamProxy::Create(
rtc::Thread::Current(), MediaStream::Create(kDefaultStreamId));
pc_->remote_streams_internal()->AddStream(default_stream);
new_streams->AddStream(default_stream);
}
std::string default_sender_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
? kDefaultAudioSenderId
: kDefaultVideoSenderId;
const PeerConnection::RtpSenderInfo* default_sender_info =
pc_->FindSenderInfo(*current_senders, kDefaultStreamId,
default_sender_id);
if (!default_sender_info) {
current_senders->push_back(PeerConnection::RtpSenderInfo(
kDefaultStreamId, default_sender_id, /*ssrc=*/0));
pc_->OnRemoteSenderAdded(current_senders->back(), media_type);
}
}
}
void SdpOfferAnswerHandler::EnableSending() {
RTC_DCHECK_RUN_ON(signaling_thread());
for (const auto& transceiver : pc_->transceivers_.List()) {
cricket::ChannelInterface* channel = transceiver->internal()->channel();
if (channel && !channel->enabled()) {
channel->Enable(true);
}
}
if (pc_->data_channel_controller()->rtp_data_channel() &&
!pc_->data_channel_controller()->rtp_data_channel()->enabled()) {
pc_->data_channel_controller()->rtp_data_channel()->Enable(true);
}
}
RTCError SdpOfferAnswerHandler::PushdownMediaDescription(
SdpType type,
cricket::ContentSource source) {
const SessionDescriptionInterface* sdesc =
(source == cricket::CS_LOCAL ? local_description()
: remote_description());
RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(sdesc);
pc_->UpdatePayloadTypeDemuxingState(source);
// Push down the new SDP media section for each audio/video transceiver.
for (const auto& transceiver : pc_->transceivers_.List()) {
const ContentInfo* content_info =
FindMediaSectionForTransceiver(transceiver, sdesc);
cricket::ChannelInterface* channel = transceiver->internal()->channel();
if (!channel || !content_info || content_info->rejected) {
continue;
}
const MediaContentDescription* content_desc =
content_info->media_description();
if (!content_desc) {
continue;
}
std::string error;
bool success = (source == cricket::CS_LOCAL)
? channel->SetLocalContent(content_desc, type, &error)
: channel->SetRemoteContent(content_desc, type, &error);
if (!success) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
}
}
// If using the RtpDataChannel, push down the new SDP section for it too.
if (pc_->data_channel_controller()->rtp_data_channel()) {
const ContentInfo* data_content =
cricket::GetFirstDataContent(sdesc->description());
if (data_content && !data_content->rejected) {
const MediaContentDescription* data_desc =
data_content->media_description();
if (data_desc) {
std::string error;
bool success = (source == cricket::CS_LOCAL)
? pc_->data_channel_controller()
->rtp_data_channel()
->SetLocalContent(data_desc, type, &error)
: pc_->data_channel_controller()
->rtp_data_channel()
->SetRemoteContent(data_desc, type, &error);
if (!success) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
}
}
}
}
// Need complete offer/answer with an SCTP m= section before starting SCTP,
// according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
if (pc_->sctp_mid() && local_description() && remote_description()) {
rtc::scoped_refptr<SctpTransport> sctp_transport =
pc_->transport_controller_->GetSctpTransport(*(pc_->sctp_mid()));
auto local_sctp_description = cricket::GetFirstSctpDataContentDescription(
local_description()->description());
auto remote_sctp_description = cricket::GetFirstSctpDataContentDescription(
remote_description()->description());
if (sctp_transport && local_sctp_description && remote_sctp_description) {
int max_message_size;
// A remote max message size of zero means "any size supported".
// We configure the connection with our own max message size.
if (remote_sctp_description->max_message_size() == 0) {
max_message_size = local_sctp_description->max_message_size();
} else {
max_message_size =
std::min(local_sctp_description->max_message_size(),
remote_sctp_description->max_message_size());
}
sctp_transport->Start(local_sctp_description->port(),
remote_sctp_description->port(), max_message_size);
}
}
return RTCError::OK();
}
RTCError SdpOfferAnswerHandler::PushdownTransportDescription(
cricket::ContentSource source,
SdpType type) {
RTC_DCHECK_RUN_ON(signaling_thread());
if (source == cricket::CS_LOCAL) {
const SessionDescriptionInterface* sdesc = local_description();
RTC_DCHECK(sdesc);
return pc_->transport_controller_->SetLocalDescription(
type, sdesc->description());
} else {
const SessionDescriptionInterface* sdesc = remote_description();
RTC_DCHECK(sdesc);
return pc_->transport_controller_->SetRemoteDescription(
type, sdesc->description());
}
}
void SdpOfferAnswerHandler::RemoveStoppedTransceivers() {
RTC_DCHECK_RUN_ON(signaling_thread());
// 3.2.10.1: For each transceiver in the connection's set of transceivers
// run the following steps:
if (!IsUnifiedPlan())
return;
// Traverse a copy of the transceiver list.
auto transceiver_list = pc_->transceivers_.List();
for (auto transceiver : transceiver_list) {
// 3.2.10.1.1: If transceiver is stopped, associated with an m= section
// and the associated m= section is rejected in
// connection.[[CurrentLocalDescription]] or
// connection.[[CurrentRemoteDescription]], remove the
// transceiver from the connection's set of transceivers.
if (!transceiver->stopped()) {
continue;
}
const ContentInfo* local_content =
FindMediaSectionForTransceiver(transceiver, local_description());
const ContentInfo* remote_content =
FindMediaSectionForTransceiver(transceiver, remote_description());
if ((local_content && local_content->rejected) ||
(remote_content && remote_content->rejected)) {
RTC_LOG(LS_INFO) << "Dissociating transceiver"
<< " since the media section is being recycled.";
transceiver->internal()->set_mid(absl::nullopt);
transceiver->internal()->set_mline_index(absl::nullopt);
pc_->transceivers_.Remove(transceiver);
continue;
}
if (!local_content && !remote_content) {
// TODO(bugs.webrtc.org/11973): Consider if this should be removed already
// See https://github.com/w3c/webrtc-pc/issues/2576
RTC_LOG(LS_INFO)
<< "Dropping stopped transceiver that was never associated";
pc_->transceivers_.Remove(transceiver);
continue;
}
}
}
void SdpOfferAnswerHandler::RemoveUnusedChannels(
const SessionDescription* desc) {
RTC_DCHECK_RUN_ON(signaling_thread());
// Destroy video channel first since it may have a pointer to the
// voice channel.
const cricket::ContentInfo* video_info = cricket::GetFirstVideoContent(desc);
if (!video_info || video_info->rejected) {
pc_->DestroyTransceiverChannel(pc_->GetVideoTransceiver());
}
const cricket::ContentInfo* audio_info = cricket::GetFirstAudioContent(desc);
if (!audio_info || audio_info->rejected) {
pc_->DestroyTransceiverChannel(pc_->GetAudioTransceiver());
}
const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc);
if (!data_info || data_info->rejected) {
pc_->DestroyDataChannelTransport();
}
}
void SdpOfferAnswerHandler::ReportNegotiatedSdpSemantics(
const SessionDescriptionInterface& answer) {
SdpSemanticNegotiated semantics_negotiated;
switch (answer.description()->msid_signaling()) {
case 0:
semantics_negotiated = kSdpSemanticNegotiatedNone;
break;
case cricket::kMsidSignalingMediaSection:
semantics_negotiated = kSdpSemanticNegotiatedUnifiedPlan;
break;
case cricket::kMsidSignalingSsrcAttribute:
semantics_negotiated = kSdpSemanticNegotiatedPlanB;
break;
case cricket::kMsidSignalingMediaSection |
cricket::kMsidSignalingSsrcAttribute:
semantics_negotiated = kSdpSemanticNegotiatedMixed;
break;
default:
RTC_NOTREACHED();
}
RTC_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.SdpSemanticNegotiated",
semantics_negotiated, kSdpSemanticNegotiatedMax);
}
} // namespace webrtc

View File

@ -150,6 +150,12 @@ class SdpOfferAnswerHandler {
class SetSessionDescriptionObserverAdapter;
friend class SetSessionDescriptionObserverAdapter;
enum class SessionError {
kNone, // No error.
kContent, // Error in BaseChannel SetLocalContent/SetRemoteContent.
kTransport, // Error from the underlying transport.
};
// Represents the [[LocalIceCredentialsToReplace]] internal slot in the spec.
// It makes the next CreateOffer() produce new ICE credentials even if
// RTCOfferAnswerOptions::ice_restart is false.
@ -316,6 +322,89 @@ class SdpOfferAnswerHandler {
cricket::MediaSessionOptions* session_options)
RTC_RUN_ON(signaling_thread());
const char* SessionErrorToString(SessionError error) const;
std::string GetSessionErrorMsg();
// Returns the last error in the session. See the enum above for details.
SessionError session_error() const {
RTC_DCHECK_RUN_ON(signaling_thread());
return session_error_;
}
const std::string& session_error_desc() const { return session_error_desc_; }
RTCError HandleLegacyOfferOptions(
const PeerConnectionInterface::RTCOfferAnswerOptions& options);
void RemoveRecvDirectionFromReceivingTransceiversOfType(
cricket::MediaType media_type) RTC_RUN_ON(signaling_thread());
void AddUpToOneReceivingTransceiverOfType(cricket::MediaType media_type);
std::vector<
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
GetReceivingTransceiversOfType(cricket::MediaType media_type)
RTC_RUN_ON(signaling_thread());
// Runs the algorithm **process the removal of a remote track** specified in
// the WebRTC specification.
// This method will update the following lists:
// |remove_list| is the list of transceivers for which the receiving track is
// being removed.
// |removed_streams| is the list of streams which no longer have a receiving
// track so should be removed.
// https://w3c.github.io/webrtc-pc/#process-remote-track-removal
void ProcessRemovalOfRemoteTrack(
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
transceiver,
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>* remove_list,
std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams);
void RemoveRemoteStreamsIfEmpty(
const std::vector<rtc::scoped_refptr<MediaStreamInterface>>&
remote_streams,
std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams);
// Remove all local and remote senders of type |media_type|.
// Called when a media type is rejected (m-line set to port 0).
void RemoveSenders(cricket::MediaType media_type);
// Loops through the vector of |streams| and finds added and removed
// StreamParams since last time this method was called.
// For each new or removed StreamParam, OnLocalSenderSeen or
// OnLocalSenderRemoved is invoked.
void UpdateLocalSenders(const std::vector<cricket::StreamParams>& streams,
cricket::MediaType media_type);
// Makes sure a MediaStreamTrack is created for each StreamParam in |streams|,
// and existing MediaStreamTracks are removed if there is no corresponding
// StreamParam. If |default_track_needed| is true, a default MediaStreamTrack
// is created if it doesn't exist; if false, it's removed if it exists.
// |media_type| is the type of the |streams| and can be either audio or video.
// If a new MediaStream is created it is added to |new_streams|.
void UpdateRemoteSendersList(
const std::vector<cricket::StreamParams>& streams,
bool default_track_needed,
cricket::MediaType media_type,
StreamCollection* new_streams);
// Enables media channels to allow sending of media.
// This enables media to flow on all configured audio/video channels and the
// RtpDataChannel.
void EnableSending();
// Push the media parts of the local or remote session description
// down to all of the channels.
RTCError PushdownMediaDescription(SdpType type,
cricket::ContentSource source);
RTCError PushdownTransportDescription(cricket::ContentSource source,
SdpType type);
// Helper function to remove stopped transceivers.
void RemoveStoppedTransceivers();
// Deletes the corresponding channel of contents that don't exist in |desc|.
// |desc| can be null. This means that all channels are deleted.
void RemoveUnusedChannels(const cricket::SessionDescription* desc);
// Report inferred negotiated SDP semantics from a local/remote answer to the
// UMA observer.
void ReportNegotiatedSdpSemantics(const SessionDescriptionInterface& answer);
// ===================================================================
PeerConnection* const pc_;
@ -370,6 +459,13 @@ class SdpOfferAnswerHandler {
bool have_pending_rtp_data_channel_ RTC_GUARDED_BY(signaling_thread()) =
false;
// Updates the error state, signaling if necessary.
void SetSessionError(SessionError error, const std::string& error_desc);
SessionError session_error_ RTC_GUARDED_BY(signaling_thread()) =
SessionError::kNone;
std::string session_error_desc_ RTC_GUARDED_BY(signaling_thread());
rtc::WeakPtrFactory<SdpOfferAnswerHandler> weak_ptr_factory_
RTC_GUARDED_BY(signaling_thread());
};