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:
committed by
Commit Bot
parent
bd9c33ad59
commit
a474fbf413
@ -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.
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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());
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user