Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Unified Diff: webrtc/pc/mediasession.cc

Issue 2991693002: Adding support for Unified Plan offer/answer negotiation. (Closed)
Patch Set: Fix the chromium win-clang bulid by replacing int with Optional<size_t>. Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/pc/mediasession.h ('k') | webrtc/pc/mediasession_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/pc/mediasession.cc
diff --git a/webrtc/pc/mediasession.cc b/webrtc/pc/mediasession.cc
index de8f72c92612714268570a7a2403e2c6d16827c1..4d4744aeb0f369994bc0e18deb0d49f5a07aa414 100644
--- a/webrtc/pc/mediasession.cc
+++ b/webrtc/pc/mediasession.cc
@@ -188,11 +188,14 @@ bool CreateMediaCryptos(const std::vector<std::string>& crypto_suites,
return true;
}
-const CryptoParamsVec* GetCryptos(const MediaContentDescription* media) {
- if (!media) {
- return NULL;
+const CryptoParamsVec* GetCryptos(const ContentInfo* content) {
+ if (!content) {
+ return nullptr;
}
- return &media->cryptos();
+
+ RTC_DCHECK(IsMediaContent(content));
+ return &(static_cast<const MediaContentDescription*>(content->description)
+ ->cryptos());
}
bool FindMatchingCrypto(const CryptoParamsVec& cryptos,
@@ -428,15 +431,15 @@ class UsedRtpHeaderExtensionIds : public UsedIds<webrtc::RtpExtension> {
private:
};
-// Adds a StreamParams for each Stream in Streams with media type
-// media_type to content_description.
+// Adds a StreamParams for each SenderOptions in |sender_options| to
+// content_description.
// |current_params| - All currently known StreamParams of any media type.
template <class C>
-static bool AddStreamParams(MediaType media_type,
- const MediaSessionOptions& options,
- StreamParamsVec* current_streams,
- MediaContentDescriptionImpl<C>* content_description,
- const bool add_legacy_stream) {
+static bool AddStreamParams(
+ const std::vector<SenderOptions>& sender_options,
+ const std::string& rtcp_cname,
+ StreamParamsVec* current_streams,
+ MediaContentDescriptionImpl<C>* content_description) {
// SCTP streams are not negotiated using SDP/ContentDescriptions.
if (IsSctp(content_description->protocol())) {
return true;
@@ -445,44 +448,26 @@ static bool AddStreamParams(MediaType media_type,
const bool include_rtx_streams =
ContainsRtxCodec(content_description->codecs());
- const MediaSessionOptions::Streams& streams = options.streams;
- if (streams.empty() && add_legacy_stream) {
- // TODO(perkj): Remove this legacy stream when all apps use StreamParams.
- std::vector<uint32_t> ssrcs;
- int num_ssrcs = include_rtx_streams ? 2 : 1;
- GenerateSsrcs(*current_streams, num_ssrcs, &ssrcs);
- if (include_rtx_streams) {
- content_description->AddLegacyStream(ssrcs[0], ssrcs[1]);
- content_description->set_multistream(true);
- } else {
- content_description->AddLegacyStream(ssrcs[0]);
- }
- return true;
- }
const bool include_flexfec_stream =
ContainsFlexfecCodec(content_description->codecs());
- MediaSessionOptions::Streams::const_iterator stream_it;
- for (stream_it = streams.begin();
- stream_it != streams.end(); ++stream_it) {
- if (stream_it->type != media_type)
- continue; // Wrong media type.
-
- StreamParams* param = GetStreamByIds(*current_streams, "", stream_it->id);
+ for (const SenderOptions& sender : sender_options) {
// groupid is empty for StreamParams generated using
// MediaSessionDescriptionFactory.
+ StreamParams* param =
+ GetStreamByIds(*current_streams, "" /*group_id*/, sender.track_id);
if (!param) {
- // This is a new stream.
+ // This is a new sender.
std::vector<uint32_t> ssrcs;
- GenerateSsrcs(*current_streams, stream_it->num_sim_layers, &ssrcs);
+ GenerateSsrcs(*current_streams, sender.num_sim_layers, &ssrcs);
StreamParams stream_param;
- stream_param.id = stream_it->id;
+ stream_param.id = sender.track_id;
// Add the generated ssrc.
for (size_t i = 0; i < ssrcs.size(); ++i) {
stream_param.ssrcs.push_back(ssrcs[i]);
}
- if (stream_it->num_sim_layers > 1) {
+ if (sender.num_sim_layers > 1) {
SsrcGroup group(kSimSsrcGroupSemantics, stream_param.ssrcs);
stream_param.ssrc_groups.push_back(group);
}
@@ -512,8 +497,8 @@ static bool AddStreamParams(MediaType media_type,
<< "media streams however, so no FlexFEC SSRC will be generated.";
}
}
- stream_param.cname = options.rtcp_cname;
- stream_param.sync_label = stream_it->sync_label;
+ stream_param.cname = rtcp_cname;
+ stream_param.sync_label = sender.stream_id;
content_description->AddStream(stream_param);
// Store the new StreamParams in current_streams.
@@ -523,7 +508,7 @@ static bool AddStreamParams(MediaType media_type,
// Use existing generated SSRCs/groups, but update the sync_label if
// necessary. This may be needed if a MediaStreamTrack was moved from one
// MediaStream to another.
- param->sync_label = stream_it->sync_label;
+ param->sync_label = sender.stream_id;
content_description->AddStream(*param);
}
}
@@ -735,46 +720,34 @@ static bool IsFlexfecCodec(const C& codec) {
return STR_CASE_CMP(codec.name.c_str(), kFlexfecCodecName) == 0;
}
-static TransportOptions GetTransportOptions(const MediaSessionOptions& options,
- const std::string& content_name) {
- TransportOptions transport_options;
- auto it = options.transport_options.find(content_name);
- if (it != options.transport_options.end()) {
- transport_options = it->second;
- }
- transport_options.enable_ice_renomination = options.enable_ice_renomination;
- return transport_options;
-}
-
-// Create a media content to be offered in a session-initiate,
-// according to the given options.rtcp_mux, options.is_muc,
-// options.streams, codecs, secure_transport, crypto, and streams. If we don't
-// currently have crypto (in current_cryptos) and it is enabled (in
-// secure_policy), crypto is created (according to crypto_suites). If
-// add_legacy_stream is true, and current_streams is empty, a legacy
-// stream is created. The created content is added to the offer.
+// Create a media content to be offered for the given |sender_options|,
+// according to the given options.rtcp_mux, session_options.is_muc, codecs,
+// secure_transport, crypto, and current_streams. If we don't currently have
+// crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
+// created (according to crypto_suites). The created content is added to the
+// offer.
template <class C>
static bool CreateMediaContentOffer(
- const MediaSessionOptions& options,
+ const std::vector<SenderOptions>& sender_options,
+ const MediaSessionOptions& session_options,
const std::vector<C>& codecs,
const SecurePolicy& secure_policy,
const CryptoParamsVec* current_cryptos,
const std::vector<std::string>& crypto_suites,
const RtpHeaderExtensions& rtp_extensions,
- bool add_legacy_stream,
StreamParamsVec* current_streams,
MediaContentDescriptionImpl<C>* offer) {
offer->AddCodecs(codecs);
- offer->set_rtcp_mux(options.rtcp_mux_enabled);
+ offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
offer->set_rtcp_reduced_size(true);
}
- offer->set_multistream(options.is_muc);
+ offer->set_multistream(session_options.is_muc);
offer->set_rtp_header_extensions(rtp_extensions);
- if (!AddStreamParams(offer->type(), options, current_streams, offer,
- add_legacy_stream)) {
+ if (!AddStreamParams(sender_options, session_options.rtcp_cname,
+ current_streams, offer)) {
return false;
}
@@ -882,15 +855,42 @@ static bool FindMatchingCodec(const std::vector<C>& codecs1,
return false;
}
-// Adds all codecs from |reference_codecs| to |offered_codecs| that dont'
+// Find the codec in |codec_list| that |rtx_codec| is associated with.
+template <class C>
+static const C* GetAssociatedCodec(const std::vector<C>& codec_list,
+ const C& rtx_codec) {
+ std::string associated_pt_str;
+ if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
+ &associated_pt_str)) {
+ LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
+ << " is missing an associated payload type.";
+ return nullptr;
+ }
+
+ int associated_pt;
+ if (!rtc::FromString(associated_pt_str, &associated_pt)) {
+ LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
+ << " of RTX codec " << rtx_codec.name << " to an integer.";
+ return nullptr;
+ }
+
+ // Find the associated reference codec for the reference RTX codec.
+ const C* associated_codec = FindCodecById(codec_list, associated_pt);
+ if (!associated_codec) {
+ LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
+ << associated_pt << " for RTX codec " << rtx_codec.name
+ << ".";
+ }
+ return associated_codec;
+}
+
+// Adds all codecs from |reference_codecs| to |offered_codecs| that don't
// already exist in |offered_codecs| and ensure the payload types don't
// collide.
template <class C>
-static void FindCodecsToOffer(
- const std::vector<C>& reference_codecs,
- std::vector<C>* offered_codecs,
- UsedPayloadTypes* used_pltypes) {
-
+static void MergeCodecs(const std::vector<C>& reference_codecs,
+ std::vector<C>* offered_codecs,
+ UsedPayloadTypes* used_pltypes) {
// Add all new codecs that are not RTX codecs.
for (const C& reference_codec : reference_codecs) {
if (!IsRtxCodec(reference_codec) &&
@@ -908,33 +908,11 @@ static void FindCodecsToOffer(
!FindMatchingCodec<C>(reference_codecs, *offered_codecs,
reference_codec, nullptr)) {
C rtx_codec = reference_codec;
-
- std::string associated_pt_str;
- if (!rtx_codec.GetParam(kCodecParamAssociatedPayloadType,
- &associated_pt_str)) {
- LOG(LS_WARNING) << "RTX codec " << rtx_codec.name
- << " is missing an associated payload type.";
- continue;
- }
-
- int associated_pt;
- if (!rtc::FromString(associated_pt_str, &associated_pt)) {
- LOG(LS_WARNING) << "Couldn't convert payload type " << associated_pt_str
- << " of RTX codec " << rtx_codec.name
- << " to an integer.";
- continue;
- }
-
- // Find the associated reference codec for the reference RTX codec.
const C* associated_codec =
- FindCodecById(reference_codecs, associated_pt);
+ GetAssociatedCodec(reference_codecs, rtx_codec);
if (!associated_codec) {
- LOG(LS_WARNING) << "Couldn't find associated codec with payload type "
- << associated_pt << " for RTX codec " << rtx_codec.name
- << ".";
continue;
}
-
// Find a codec in the offered list that matches the reference codec.
// Its payload type may be different than the reference codec.
C matching_codec;
@@ -953,6 +931,22 @@ static void FindCodecsToOffer(
}
}
+static bool FindByUriAndEncryption(const RtpHeaderExtensions& extensions,
+ const webrtc::RtpExtension& ext_to_match,
+ webrtc::RtpExtension* found_extension) {
+ for (RtpHeaderExtensions::const_iterator it = extensions.begin();
+ it != extensions.end(); ++it) {
+ // We assume that all URIs are given in a canonical format.
+ if (it->uri == ext_to_match.uri && it->encrypt == ext_to_match.encrypt) {
+ if (found_extension) {
+ *found_extension = *it;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
static bool FindByUri(const RtpHeaderExtensions& extensions,
const webrtc::RtpExtension& ext_to_match,
webrtc::RtpExtension* found_extension) {
@@ -996,50 +990,41 @@ static bool FindByUriWithEncryptionPreference(
return false;
}
-// Iterates through |offered_extensions|, adding each one to
-// |regular_extensions| (or |encrypted_extensions| if encrypted) and |used_ids|,
-// and resolving ID conflicts.
-// If an offered extension has the same URI as one in |regular_extensions| or
-// |encrypted_extensions|, it will re-use the same ID and won't be treated as
-// a conflict.
-static void FindAndSetRtpHdrExtUsed(RtpHeaderExtensions* offered_extensions,
- RtpHeaderExtensions* regular_extensions,
- RtpHeaderExtensions* encrypted_extensions,
- UsedRtpHeaderExtensionIds* used_ids) {
- for (auto& extension : *offered_extensions) {
- webrtc::RtpExtension existing;
- if ((extension.encrypt &&
- FindByUri(*encrypted_extensions, extension, &existing)) ||
- (!extension.encrypt &&
- FindByUri(*regular_extensions, extension, &existing))) {
- extension.id = existing.id;
- } else {
- used_ids->FindAndSetIdUsed(&extension);
- if (extension.encrypt) {
- encrypted_extensions->push_back(extension);
- } else {
- regular_extensions->push_back(extension);
- }
- }
- }
-}
-
-// Adds |reference_extensions| to |offered_extensions|, while updating
-// |all_extensions| and |used_ids|.
-static void FindRtpHdrExtsToOffer(
- const RtpHeaderExtensions& reference_extensions,
- RtpHeaderExtensions* offered_extensions,
- RtpHeaderExtensions* all_extensions,
- UsedRtpHeaderExtensionIds* used_ids) {
+// Adds all extensions from |reference_extensions| to |offered_extensions| that
+// don't already exist in |offered_extensions| and ensure the IDs don't
+// collide. If an extension is added, it's also added to |regular_extensions| or
+// |encrypted_extensions|, and if the extension is in |regular_extensions| or
+// |encrypted_extensions|, its ID is marked as used in |used_ids|.
+// |offered_extensions| is for either audio or video while |regular_extensions|
+// and |encrypted_extensions| are used for both audio and video. There could be
+// overlap between audio extensions and video extensions.
+static void MergeRtpHdrExts(const RtpHeaderExtensions& reference_extensions,
+ RtpHeaderExtensions* offered_extensions,
+ RtpHeaderExtensions* regular_extensions,
+ RtpHeaderExtensions* encrypted_extensions,
+ UsedRtpHeaderExtensionIds* used_ids) {
for (auto reference_extension : reference_extensions) {
- if (!FindByUri(*offered_extensions, reference_extension, NULL)) {
+ if (!FindByUriAndEncryption(*offered_extensions, reference_extension,
+ nullptr)) {
webrtc::RtpExtension existing;
- if (FindByUri(*all_extensions, reference_extension, &existing)) {
- offered_extensions->push_back(existing);
+ if (reference_extension.encrypt) {
+ if (FindByUriAndEncryption(*encrypted_extensions, reference_extension,
+ &existing)) {
+ offered_extensions->push_back(existing);
+ } else {
+ used_ids->FindAndSetIdUsed(&reference_extension);
+ encrypted_extensions->push_back(reference_extension);
+ offered_extensions->push_back(reference_extension);
+ }
} else {
- used_ids->FindAndSetIdUsed(&reference_extension);
- all_extensions->push_back(reference_extension);
- offered_extensions->push_back(reference_extension);
+ if (FindByUriAndEncryption(*regular_extensions, reference_extension,
+ &existing)) {
+ offered_extensions->push_back(existing);
+ } else {
+ used_ids->FindAndSetIdUsed(&reference_extension);
+ regular_extensions->push_back(reference_extension);
+ offered_extensions->push_back(reference_extension);
+ }
}
}
}
@@ -1103,26 +1088,24 @@ static void StripCNCodecs(AudioCodecs* audio_codecs) {
}
}
-// Create a media content to be answered in a session-accept,
-// according to the given options.rtcp_mux, options.streams, codecs,
-// crypto, and streams. If we don't currently have crypto (in
-// current_cryptos) and it is enabled (in secure_policy), crypto is
-// created (according to crypto_suites). If add_legacy_stream is
-// true, and current_streams is empty, a legacy stream is created.
-// The codecs, rtcp_mux, and crypto are all negotiated with the offer
-// from the incoming session-initiate. If the negotiation fails, this
-// method returns false. The created content is added to the offer.
+// Create a media content to be answered for the given |sender_options|
+// according to the given session_options.rtcp_mux, session_options.streams,
+// codecs, crypto, and current_streams. If we don't currently have crypto (in
+// current_cryptos) and it is enabled (in secure_policy), crypto is created
+// (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
+// negotiated with the offer. If the negotiation fails, this method returns
+// false. The created content is added to the offer.
template <class C>
static bool CreateMediaContentAnswer(
const MediaContentDescriptionImpl<C>* offer,
- const MediaSessionOptions& options,
+ const MediaDescriptionOptions& media_description_options,
+ const MediaSessionOptions& session_options,
const std::vector<C>& local_codecs,
const SecurePolicy& sdes_policy,
const CryptoParamsVec* current_cryptos,
const RtpHeaderExtensions& local_rtp_extenstions,
bool enable_encrypted_rtp_header_extensions,
StreamParamsVec* current_streams,
- bool add_legacy_stream,
bool bundle_enabled,
MediaContentDescriptionImpl<C>* answer) {
std::vector<C> negotiated_codecs;
@@ -1136,14 +1119,15 @@ static bool CreateMediaContentAnswer(
&negotiated_rtp_extensions);
answer->set_rtp_header_extensions(negotiated_rtp_extensions);
- answer->set_rtcp_mux(options.rtcp_mux_enabled && offer->rtcp_mux());
+ answer->set_rtcp_mux(session_options.rtcp_mux_enabled && offer->rtcp_mux());
if (answer->type() == cricket::MEDIA_TYPE_VIDEO) {
answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
}
if (sdes_policy != SEC_DISABLED) {
CryptoParams crypto;
- if (SelectCrypto(offer, bundle_enabled, options.crypto_options, &crypto)) {
+ if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
+ &crypto)) {
if (current_cryptos) {
FindMatchingCrypto(*current_cryptos, crypto, &crypto);
}
@@ -1155,29 +1139,17 @@ static bool CreateMediaContentAnswer(
return false;
}
- if (!AddStreamParams(answer->type(), options, current_streams, answer,
- add_legacy_stream)) {
+ if (!AddStreamParams(media_description_options.sender_options,
+ session_options.rtcp_cname, current_streams, answer)) {
return false; // Something went seriously wrong.
}
- // Make sure the answer media content direction is per default set as
- // described in RFC3264 section 6.1.
- const bool is_data = !IsRtpProtocol(answer->protocol());
- const bool has_send_streams = !answer->streams().empty();
- const bool wants_send = has_send_streams || is_data;
- const bool recv_audio =
- answer->type() == cricket::MEDIA_TYPE_AUDIO && options.recv_audio;
- const bool recv_video =
- answer->type() == cricket::MEDIA_TYPE_VIDEO && options.recv_video;
- const bool recv_data =
- answer->type() == cricket::MEDIA_TYPE_DATA;
- const bool wants_receive = recv_audio || recv_video || recv_data;
-
auto offer_rtd =
RtpTransceiverDirection::FromMediaContentDirection(offer->direction());
- auto wants_rtd = RtpTransceiverDirection(wants_send, wants_receive);
- answer->set_direction(NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd)
- .ToMediaContentDirection());
+
+ answer->set_direction(NegotiateRtpTransceiverDirection(
+ offer_rtd, media_description_options.direction)
+ .ToMediaContentDirection());
return true;
}
@@ -1239,23 +1211,20 @@ static const TransportDescription* GetTransportDescription(
}
// Gets the current DTLS state from the transport description.
-static bool IsDtlsActive(
- const std::string& content_name,
- const SessionDescription* current_description) {
- if (!current_description)
+static bool IsDtlsActive(const ContentInfo* content,
+ const SessionDescription* current_description) {
+ if (!content) {
return false;
+ }
- const ContentInfo* content =
- current_description->GetContentByName(content_name);
- if (!content)
- return false;
+ size_t msection_index = content - &current_description->contents()[0];
- const TransportDescription* current_tdesc =
- GetTransportDescription(content_name, current_description);
- if (!current_tdesc)
+ if (current_description->transport_infos().size() <= msection_index) {
return false;
+ }
- return current_tdesc->secure();
+ return current_description->transport_infos()[msection_index]
+ .description.secure();
}
std::string MediaContentDirectionToString(MediaContentDirection direction) {
@@ -1281,75 +1250,54 @@ std::string MediaContentDirectionToString(MediaContentDirection direction) {
return dir_str;
}
-void MediaSessionOptions::AddSendStream(MediaType type,
- const std::string& id,
- const std::string& sync_label) {
- AddSendStreamInternal(type, id, sync_label, 1);
+void MediaDescriptionOptions::AddAudioSender(const std::string& track_id,
+ const std::string& stream_id) {
+ RTC_DCHECK(type == MEDIA_TYPE_AUDIO);
+ AddSenderInternal(track_id, stream_id, 1);
}
-void MediaSessionOptions::AddSendVideoStream(
- const std::string& id,
- const std::string& sync_label,
- int num_sim_layers) {
- AddSendStreamInternal(MEDIA_TYPE_VIDEO, id, sync_label, num_sim_layers);
+void MediaDescriptionOptions::AddVideoSender(const std::string& track_id,
+ const std::string& stream_id,
+ int num_sim_layers) {
+ RTC_DCHECK(type == MEDIA_TYPE_VIDEO);
+ AddSenderInternal(track_id, stream_id, num_sim_layers);
}
-void MediaSessionOptions::AddSendStreamInternal(
- MediaType type,
- const std::string& id,
- const std::string& sync_label,
- int num_sim_layers) {
- streams.push_back(Stream(type, id, sync_label, num_sim_layers));
-
- // If we haven't already set the data_channel_type, and we add a
- // stream, we assume it's an RTP data stream.
- if (type == MEDIA_TYPE_DATA && data_channel_type == DCT_NONE)
- data_channel_type = DCT_RTP;
+void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
+ const std::string& stream_id) {
+ RTC_DCHECK(type == MEDIA_TYPE_DATA);
+ AddSenderInternal(track_id, stream_id, 1);
}
-void MediaSessionOptions::RemoveSendStream(MediaType type,
- const std::string& id) {
- Streams::iterator stream_it = streams.begin();
- for (; stream_it != streams.end(); ++stream_it) {
- if (stream_it->type == type && stream_it->id == id) {
- streams.erase(stream_it);
- return;
- }
- }
- RTC_NOTREACHED();
+void MediaDescriptionOptions::AddSenderInternal(const std::string& track_id,
+ const std::string& stream_id,
+ int num_sim_layers) {
+ sender_options.push_back(SenderOptions{track_id, stream_id, num_sim_layers});
}
-bool MediaSessionOptions::HasSendMediaStream(MediaType type) const {
- Streams::const_iterator stream_it = streams.begin();
- for (; stream_it != streams.end(); ++stream_it) {
- if (stream_it->type == type) {
- return true;
- }
- }
- return false;
+bool MediaSessionOptions::HasMediaDescription(MediaType type) const {
+ return std::find_if(media_description_options.begin(),
+ media_description_options.end(),
+ [type](const MediaDescriptionOptions& t) {
+ return t.type == type;
+ }) != media_description_options.end();
}
MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
const TransportDescriptionFactory* transport_desc_factory)
- : secure_(SEC_DISABLED),
- add_legacy_(true),
- transport_desc_factory_(transport_desc_factory) {
-}
+ : transport_desc_factory_(transport_desc_factory) {}
MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
ChannelManager* channel_manager,
const TransportDescriptionFactory* transport_desc_factory)
- : secure_(SEC_DISABLED),
- add_legacy_(true),
- transport_desc_factory_(transport_desc_factory) {
+ : transport_desc_factory_(transport_desc_factory) {
channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
channel_manager->GetSupportedVideoCodecs(&video_codecs_);
channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
channel_manager->GetSupportedDataCodecs(&data_codecs_);
- NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
- &audio_sendrecv_codecs_);
+ ComputeAudioCodecsIntersectionAndUnion();
}
const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
@@ -1369,129 +1317,114 @@ void MediaSessionDescriptionFactory::set_audio_codecs(
const AudioCodecs& send_codecs, const AudioCodecs& recv_codecs) {
audio_send_codecs_ = send_codecs;
audio_recv_codecs_ = recv_codecs;
- audio_sendrecv_codecs_.clear();
- // Use NegotiateCodecs to merge our codec lists, since the operation is
- // essentially the same. Put send_codecs as the offered_codecs, which is the
- // order we'd like to follow. The reasoning is that encoding is usually more
- // expensive than decoding, and prioritizing a codec in the send list probably
- // means it's a codec we can handle efficiently.
- NegotiateCodecs(recv_codecs, send_codecs, &audio_sendrecv_codecs_);
+ ComputeAudioCodecsIntersectionAndUnion();
}
SessionDescription* MediaSessionDescriptionFactory::CreateOffer(
- const MediaSessionOptions& options,
+ const MediaSessionOptions& session_options,
const SessionDescription* current_description) const {
std::unique_ptr<SessionDescription> offer(new SessionDescription());
StreamParamsVec current_streams;
GetCurrentStreamParams(current_description, &current_streams);
- const bool wants_send =
- options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_;
- const AudioCodecs& supported_audio_codecs =
- GetAudioCodecsForOffer({wants_send, options.recv_audio});
-
- AudioCodecs audio_codecs;
- VideoCodecs video_codecs;
- DataCodecs data_codecs;
- GetCodecsToOffer(current_description, supported_audio_codecs,
- video_codecs_, data_codecs_,
- &audio_codecs, &video_codecs, &data_codecs);
+ AudioCodecs offer_audio_codecs;
+ VideoCodecs offer_video_codecs;
+ DataCodecs offer_data_codecs;
+ GetCodecsForOffer(current_description, &offer_audio_codecs,
+ &offer_video_codecs, &offer_data_codecs);
- if (!options.vad_enabled) {
+ if (!session_options.vad_enabled) {
// If application doesn't want CN codecs in offer.
- StripCNCodecs(&audio_codecs);
+ StripCNCodecs(&offer_audio_codecs);
}
+ FilterDataCodecs(&offer_data_codecs,
+ session_options.data_channel_type == DCT_SCTP);
RtpHeaderExtensions audio_rtp_extensions;
RtpHeaderExtensions video_rtp_extensions;
GetRtpHdrExtsToOffer(current_description, &audio_rtp_extensions,
&video_rtp_extensions);
- bool audio_added = false;
- bool video_added = false;
- bool data_added = false;
-
- // Iterate through the contents of |current_description| to maintain the order
- // of the m-lines in the new offer.
+ // Must have options for each existing section.
if (current_description) {
- ContentInfos::const_iterator it = current_description->contents().begin();
- for (; it != current_description->contents().end(); ++it) {
- if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
- if (!AddAudioContentForOffer(options, current_description,
- audio_rtp_extensions, audio_codecs,
+ RTC_DCHECK(current_description->contents().size() <=
+ session_options.media_description_options.size());
+ }
+
+ // Iterate through the media description options, matching with existing media
+ // descriptions in |current_description|.
+ int msection_index = 0;
+ for (const MediaDescriptionOptions& media_description_options :
+ session_options.media_description_options) {
+ const ContentInfo* current_content = nullptr;
+ if (current_description &&
+ msection_index <
+ static_cast<int>(current_description->contents().size())) {
+ current_content = &current_description->contents()[msection_index];
+ // Media type must match.
+ RTC_DCHECK(IsMediaContentOfType(current_content,
+ media_description_options.type));
+ }
+ switch (media_description_options.type) {
+ case MEDIA_TYPE_AUDIO:
+ if (!AddAudioContentForOffer(media_description_options, session_options,
+ current_content, current_description,
+ audio_rtp_extensions, offer_audio_codecs,
&current_streams, offer.get())) {
- return NULL;
+ return nullptr;
}
- audio_added = true;
- } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
- if (!AddVideoContentForOffer(options, current_description,
- video_rtp_extensions, video_codecs,
+ break;
+ case MEDIA_TYPE_VIDEO:
+ if (!AddVideoContentForOffer(media_description_options, session_options,
+ current_content, current_description,
+ video_rtp_extensions, offer_video_codecs,
&current_streams, offer.get())) {
- return NULL;
+ return nullptr;
}
- video_added = true;
- } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)) {
- MediaSessionOptions options_copy(options);
- if (IsSctp(static_cast<const MediaContentDescription*>(it->description)
- ->protocol())) {
- options_copy.data_channel_type = DCT_SCTP;
- }
- if (!AddDataContentForOffer(options_copy, current_description,
- &data_codecs, &current_streams,
+ break;
+ case MEDIA_TYPE_DATA:
+ if (!AddDataContentForOffer(media_description_options, session_options,
+ current_content, current_description,
+ offer_data_codecs, &current_streams,
offer.get())) {
- return NULL;
+ return nullptr;
}
- data_added = true;
- } else {
+ break;
+ default:
RTC_NOTREACHED();
- }
}
- }
-
- // Append contents that are not in |current_description|.
- if (!audio_added && options.has_audio() &&
- !AddAudioContentForOffer(options, current_description,
- audio_rtp_extensions, audio_codecs,
- &current_streams, offer.get())) {
- return NULL;
- }
- if (!video_added && options.has_video() &&
- !AddVideoContentForOffer(options, current_description,
- video_rtp_extensions, video_codecs,
- &current_streams, offer.get())) {
- return NULL;
- }
- if (!data_added && options.has_data() &&
- !AddDataContentForOffer(options, current_description, &data_codecs,
- &current_streams, offer.get())) {
- return NULL;
+ ++msection_index;
}
// Bundle the contents together, if we've been asked to do so, and update any
// parameters that need to be tweaked for BUNDLE.
- if (options.bundle_enabled) {
+ if (session_options.bundle_enabled && offer->contents().size() > 0u) {
ContentGroup offer_bundle(GROUP_TYPE_BUNDLE);
- for (ContentInfos::const_iterator content = offer->contents().begin();
- content != offer->contents().end(); ++content) {
- offer_bundle.AddContentName(content->name);
+ for (const ContentInfo& content : offer->contents()) {
+ // TODO(deadbeef): There are conditions that make bundling two media
+ // descriptions together illegal. For example, they use the same payload
+ // type to represent different codecs, or same IDs for different header
+ // extensions. We need to detect this and not try to bundle those media
+ // descriptions together.
+ offer_bundle.AddContentName(content.name);
}
offer->AddGroup(offer_bundle);
if (!UpdateTransportInfoForBundle(offer_bundle, offer.get())) {
LOG(LS_ERROR) << "CreateOffer failed to UpdateTransportInfoForBundle.";
- return NULL;
+ return nullptr;
}
if (!UpdateCryptoParamsForBundle(offer_bundle, offer.get())) {
LOG(LS_ERROR) << "CreateOffer failed to UpdateCryptoParamsForBundle.";
- return NULL;
+ return nullptr;
}
}
-
return offer.release();
}
SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
- const SessionDescription* offer, const MediaSessionOptions& options,
+ const SessionDescription* offer,
+ const MediaSessionOptions& session_options,
const SessionDescription* current_description) const {
if (!offer) {
return nullptr;
@@ -1511,32 +1444,81 @@ SessionDescription* MediaSessionDescriptionFactory::CreateAnswer(
// Transport info shared by the bundle group.
std::unique_ptr<TransportInfo> bundle_transport;
- ContentInfos::const_iterator it = offer->contents().begin();
- for (; it != offer->contents().end(); ++it) {
- if (IsMediaContentOfType(&*it, MEDIA_TYPE_AUDIO)) {
- if (!AddAudioContentForAnswer(offer, options, current_description,
- bundle_transport.get(), &current_streams,
- answer.get())) {
- return NULL;
- }
- } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) {
- if (!AddVideoContentForAnswer(offer, options, current_description,
- bundle_transport.get(), &current_streams,
- answer.get())) {
- return NULL;
- }
- } else {
- RTC_DCHECK(IsMediaContentOfType(&*it, MEDIA_TYPE_DATA));
- if (!AddDataContentForAnswer(offer, options, current_description,
- bundle_transport.get(), &current_streams,
- answer.get())) {
- return NULL;
- }
+ // Get list of all possible codecs that respects existing payload type
+ // mappings and uses a single payload type space.
+ //
+ // Note that these lists may be further filtered for each m= section; this
+ // step is done just to establish the payload type mappings shared by all
+ // sections.
+ AudioCodecs answer_audio_codecs;
+ VideoCodecs answer_video_codecs;
+ DataCodecs answer_data_codecs;
+ GetCodecsForAnswer(current_description, offer, &answer_audio_codecs,
+ &answer_video_codecs, &answer_data_codecs);
+
+ if (!session_options.vad_enabled) {
+ // If application doesn't want CN codecs in answer.
+ StripCNCodecs(&answer_audio_codecs);
+ }
+ FilterDataCodecs(&answer_data_codecs,
+ session_options.data_channel_type == DCT_SCTP);
+
+ // Must have options for exactly as many sections as in the offer.
+ RTC_DCHECK(offer->contents().size() ==
+ session_options.media_description_options.size());
+ // Iterate through the media description options, matching with existing
+ // media descriptions in |current_description|.
+ int msection_index = 0;
+ for (const MediaDescriptionOptions& media_description_options :
+ session_options.media_description_options) {
+ const ContentInfo* offer_content = &offer->contents()[msection_index];
+ // Media types and MIDs must match between the remote offer and the
+ // MediaDescriptionOptions.
+ RTC_DCHECK(
+ IsMediaContentOfType(offer_content, media_description_options.type));
+ RTC_DCHECK(media_description_options.mid == offer_content->name);
+ const ContentInfo* current_content = nullptr;
+ if (current_description &&
+ msection_index <
+ static_cast<int>(current_description->contents().size())) {
+ current_content = &current_description->contents()[msection_index];
+ }
+ switch (media_description_options.type) {
+ case MEDIA_TYPE_AUDIO:
+ if (!AddAudioContentForAnswer(
+ media_description_options, session_options, offer_content,
+ offer, current_content, current_description,
+ bundle_transport.get(), answer_audio_codecs, &current_streams,
+ answer.get())) {
+ return nullptr;
+ }
+ break;
+ case MEDIA_TYPE_VIDEO:
+ if (!AddVideoContentForAnswer(
+ media_description_options, session_options, offer_content,
+ offer, current_content, current_description,
+ bundle_transport.get(), answer_video_codecs, &current_streams,
+ answer.get())) {
+ return nullptr;
+ }
+ break;
+ case MEDIA_TYPE_DATA:
+ if (!AddDataContentForAnswer(media_description_options, session_options,
+ offer_content, offer, current_content,
+ current_description,
+ bundle_transport.get(), answer_data_codecs,
+ &current_streams, answer.get())) {
+ return nullptr;
+ }
+ break;
+ default:
+ RTC_NOTREACHED();
}
+ ++msection_index;
// See if we can add the newly generated m= section to the BUNDLE group in
// the answer.
ContentInfo& added = answer->contents().back();
- if (!added.rejected && options.bundle_enabled && offer_bundle &&
+ if (!added.rejected && session_options.bundle_enabled && offer_bundle &&
offer_bundle->HasContentName(added.name)) {
answer_bundle.AddContentName(added.name);
bundle_transport.reset(
@@ -1596,11 +1578,37 @@ const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
}
}
-void MediaSessionDescriptionFactory::GetCodecsToOffer(
+void MergeCodecsFromDescription(const SessionDescription* description,
+ AudioCodecs* audio_codecs,
+ VideoCodecs* video_codecs,
+ DataCodecs* data_codecs,
+ UsedPayloadTypes* used_pltypes) {
+ RTC_DCHECK(description);
+ for (const ContentInfo& content : description->contents()) {
+ if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
+ const AudioContentDescription* audio =
+ static_cast<AudioContentDescription*>(content.description);
+ MergeCodecs<AudioCodec>(audio->codecs(), audio_codecs, used_pltypes);
+ } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
+ const VideoContentDescription* video =
+ static_cast<VideoContentDescription*>(content.description);
+ MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
+ } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
+ const DataContentDescription* data =
+ static_cast<DataContentDescription*>(content.description);
+ MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
+ }
+ }
+}
+
+// Getting codecs for an offer involves these steps:
+//
+// 1. Construct payload type -> codec mappings for current description.
+// 2. Add any reference codecs that weren't already present
+// 3. For each individual media description (m= section), filter codecs based
+// on the directional attribute (happens in another method).
+void MediaSessionDescriptionFactory::GetCodecsForOffer(
const SessionDescription* current_description,
- const AudioCodecs& supported_audio_codecs,
- const VideoCodecs& supported_video_codecs,
- const DataCodecs& supported_data_codecs,
AudioCodecs* audio_codecs,
VideoCodecs* video_codecs,
DataCodecs* data_codecs) const {
@@ -1609,87 +1617,150 @@ void MediaSessionDescriptionFactory::GetCodecsToOffer(
video_codecs->clear();
data_codecs->clear();
+ // First - get all codecs from the current description if the media type
+ // is used. Add them to |used_pltypes| so the payload type is not reused if a
+ // new media type is added.
+ if (current_description) {
+ MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
+ data_codecs, &used_pltypes);
+ }
+
+ // Add our codecs that are not in |current_description|.
+ MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
+ MergeCodecs<VideoCodec>(video_codecs_, video_codecs, &used_pltypes);
+ MergeCodecs<DataCodec>(data_codecs_, data_codecs, &used_pltypes);
+}
+
+// Getting codecs for an answer involves these steps:
+//
+// 1. Construct payload type -> codec mappings for current description.
+// 2. Add any codecs from the offer that weren't already present.
+// 3. Add any remaining codecs that weren't already present.
+// 4. For each individual media description (m= section), filter codecs based
+// on the directional attribute (happens in another method).
+void MediaSessionDescriptionFactory::GetCodecsForAnswer(
+ const SessionDescription* current_description,
+ const SessionDescription* remote_offer,
+ AudioCodecs* audio_codecs,
+ VideoCodecs* video_codecs,
+ DataCodecs* data_codecs) const {
+ UsedPayloadTypes used_pltypes;
+ audio_codecs->clear();
+ video_codecs->clear();
+ data_codecs->clear();
// First - get all codecs from the current description if the media type
- // is used.
- // Add them to |used_pltypes| so the payloadtype is not reused if a new media
- // type is added.
+ // is used. Add them to |used_pltypes| so the payload type is not reused if a
+ // new media type is added.
if (current_description) {
- const AudioContentDescription* audio =
- GetFirstAudioContentDescription(current_description);
- if (audio) {
- *audio_codecs = audio->codecs();
- used_pltypes.FindAndSetIdUsed<AudioCodec>(audio_codecs);
- }
- const VideoContentDescription* video =
- GetFirstVideoContentDescription(current_description);
- if (video) {
- *video_codecs = video->codecs();
- used_pltypes.FindAndSetIdUsed<VideoCodec>(video_codecs);
- }
- const DataContentDescription* data =
- GetFirstDataContentDescription(current_description);
- if (data) {
- *data_codecs = data->codecs();
- used_pltypes.FindAndSetIdUsed<DataCodec>(data_codecs);
+ MergeCodecsFromDescription(current_description, audio_codecs, video_codecs,
+ data_codecs, &used_pltypes);
+ }
+
+ // Second - filter out codecs that we don't support at all and should ignore.
+ AudioCodecs filtered_offered_audio_codecs;
+ VideoCodecs filtered_offered_video_codecs;
+ DataCodecs filtered_offered_data_codecs;
+ for (const ContentInfo& content : remote_offer->contents()) {
+ if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
+ const AudioContentDescription* audio =
+ static_cast<AudioContentDescription*>(content.description);
+ for (const AudioCodec& offered_audio_codec : audio->codecs()) {
+ if (!FindMatchingCodec<AudioCodec>(audio->codecs(),
+ filtered_offered_audio_codecs,
+ offered_audio_codec, nullptr) &&
+ FindMatchingCodec<AudioCodec>(audio->codecs(), all_audio_codecs_,
+ offered_audio_codec, nullptr)) {
+ filtered_offered_audio_codecs.push_back(offered_audio_codec);
+ }
+ }
+ } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
+ const VideoContentDescription* video =
+ static_cast<VideoContentDescription*>(content.description);
+ for (const VideoCodec& offered_video_codec : video->codecs()) {
+ if (!FindMatchingCodec<VideoCodec>(video->codecs(),
+ filtered_offered_video_codecs,
+ offered_video_codec, nullptr) &&
+ FindMatchingCodec<VideoCodec>(video->codecs(), video_codecs_,
+ offered_video_codec, nullptr)) {
+ filtered_offered_video_codecs.push_back(offered_video_codec);
+ }
+ }
+ } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
+ const DataContentDescription* data =
+ static_cast<DataContentDescription*>(content.description);
+ for (const DataCodec& offered_data_codec : data->codecs()) {
+ if (!FindMatchingCodec<DataCodec>(data->codecs(),
+ filtered_offered_data_codecs,
+ offered_data_codec, nullptr) &&
+ FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
+ offered_data_codec, nullptr)) {
+ filtered_offered_data_codecs.push_back(offered_data_codec);
+ }
+ }
}
}
- // Add our codecs that are not in |current_description|.
- FindCodecsToOffer<AudioCodec>(supported_audio_codecs, audio_codecs,
- &used_pltypes);
- FindCodecsToOffer<VideoCodec>(supported_video_codecs, video_codecs,
- &used_pltypes);
- FindCodecsToOffer<DataCodec>(supported_data_codecs, data_codecs,
- &used_pltypes);
+ // Add codecs that are not in |current_description| but were in
+ // |remote_offer|.
+ MergeCodecs<AudioCodec>(filtered_offered_audio_codecs, audio_codecs,
+ &used_pltypes);
+ MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
+ &used_pltypes);
+ MergeCodecs<DataCodec>(filtered_offered_data_codecs, data_codecs,
+ &used_pltypes);
}
void MediaSessionDescriptionFactory::GetRtpHdrExtsToOffer(
const SessionDescription* current_description,
- RtpHeaderExtensions* audio_extensions,
- RtpHeaderExtensions* video_extensions) const {
+ RtpHeaderExtensions* offer_audio_extensions,
+ RtpHeaderExtensions* offer_video_extensions) const {
// All header extensions allocated from the same range to avoid potential
// issues when using BUNDLE.
UsedRtpHeaderExtensionIds used_ids;
RtpHeaderExtensions all_regular_extensions;
RtpHeaderExtensions all_encrypted_extensions;
- audio_extensions->clear();
- video_extensions->clear();
+ offer_audio_extensions->clear();
+ offer_video_extensions->clear();
// First - get all extensions from the current description if the media type
// is used.
// Add them to |used_ids| so the local ids are not reused if a new media
// type is added.
if (current_description) {
- const AudioContentDescription* audio =
- GetFirstAudioContentDescription(current_description);
- if (audio) {
- *audio_extensions = audio->rtp_header_extensions();
- FindAndSetRtpHdrExtUsed(audio_extensions, &all_regular_extensions,
- &all_encrypted_extensions, &used_ids);
- }
- const VideoContentDescription* video =
- GetFirstVideoContentDescription(current_description);
- if (video) {
- *video_extensions = video->rtp_header_extensions();
- FindAndSetRtpHdrExtUsed(video_extensions, &all_regular_extensions,
- &all_encrypted_extensions, &used_ids);
+ for (const ContentInfo& content : current_description->contents()) {
+ if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
+ const AudioContentDescription* audio =
+ static_cast<const AudioContentDescription*>(content.description);
+ MergeRtpHdrExts(audio->rtp_header_extensions(), offer_audio_extensions,
+ &all_regular_extensions, &all_encrypted_extensions,
+ &used_ids);
+ } else if (IsMediaContentOfType(&content, MEDIA_TYPE_VIDEO)) {
+ const VideoContentDescription* video =
+ static_cast<const VideoContentDescription*>(content.description);
+ MergeRtpHdrExts(video->rtp_header_extensions(), offer_video_extensions,
+ &all_regular_extensions, &all_encrypted_extensions,
+ &used_ids);
+ }
}
}
// Add our default RTP header extensions that are not in
// |current_description|.
- FindRtpHdrExtsToOffer(audio_rtp_header_extensions(), audio_extensions,
- &all_regular_extensions, &used_ids);
- FindRtpHdrExtsToOffer(video_rtp_header_extensions(), video_extensions,
- &all_regular_extensions, &used_ids);
+ MergeRtpHdrExts(audio_rtp_header_extensions(), offer_audio_extensions,
+ &all_regular_extensions, &all_encrypted_extensions,
+ &used_ids);
+ MergeRtpHdrExts(video_rtp_header_extensions(), offer_video_extensions,
+ &all_regular_extensions, &all_encrypted_extensions,
+ &used_ids);
+
// TODO(jbauch): Support adding encrypted header extensions to existing
// sessions.
if (enable_encrypted_rtp_header_extensions_ && !current_description) {
- AddEncryptedVersionsOfHdrExts(audio_extensions, &all_encrypted_extensions,
- &used_ids);
- AddEncryptedVersionsOfHdrExts(video_extensions, &all_encrypted_extensions,
- &used_ids);
+ AddEncryptedVersionsOfHdrExts(offer_audio_extensions,
+ &all_encrypted_extensions, &used_ids);
+ AddEncryptedVersionsOfHdrExts(offer_video_extensions,
+ &all_encrypted_extensions, &used_ids);
}
}
@@ -1743,35 +1814,71 @@ bool MediaSessionDescriptionFactory::AddTransportAnswer(
return true;
}
+// |audio_codecs| = set of all possible codecs that can be used, with correct
+// payload type mappings
+//
+// |supported_audio_codecs| = set of codecs that are supported for the direction
+// of this m= section
+//
+// acd->codecs() = set of previously negotiated codecs for this m= section
+//
+// The payload types should come from audio_codecs, but the order should come
+// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
+// change existing codec priority, and that new codecs are added with the right
+// priority.
bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
- const MediaSessionOptions& options,
+ const MediaDescriptionOptions& media_description_options,
+ const MediaSessionOptions& session_options,
+ const ContentInfo* current_content,
const SessionDescription* current_description,
const RtpHeaderExtensions& audio_rtp_extensions,
const AudioCodecs& audio_codecs,
StreamParamsVec* current_streams,
SessionDescription* desc) const {
- const ContentInfo* current_audio_content =
- GetFirstAudioContent(current_description);
- std::string content_name =
- current_audio_content ? current_audio_content->name : CN_AUDIO;
+ // Filter audio_codecs (which includes all codecs, with correctly remapped
+ // payload types) based on transceiver direction.
+ const AudioCodecs& supported_audio_codecs =
+ GetAudioCodecsForOffer(media_description_options.direction);
+
+ AudioCodecs filtered_codecs;
+ // Add the codecs from current content if exists.
+ if (current_content) {
+ RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
+ const AudioContentDescription* acd =
+ static_cast<const AudioContentDescription*>(
+ current_content->description);
+ for (const AudioCodec& codec : acd->codecs()) {
+ if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
+ codec, nullptr)) {
+ filtered_codecs.push_back(codec);
+ }
+ }
+ }
+ // Add other supported audio codecs.
+ AudioCodec found_codec;
+ for (const AudioCodec& codec : supported_audio_codecs) {
+ if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
+ codec, &found_codec) &&
+ !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
+ codec, nullptr)) {
+ // Use the |found_codec| from |audio_codecs| because it has the correctly
+ // mapped payload type.
+ filtered_codecs.push_back(found_codec);
+ }
+ }
cricket::SecurePolicy sdes_policy =
- IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
- : secure();
+ IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
+ : secure();
std::unique_ptr<AudioContentDescription> audio(new AudioContentDescription());
std::vector<std::string> crypto_suites;
- GetSupportedAudioSdesCryptoSuiteNames(options.crypto_options, &crypto_suites);
+ GetSupportedAudioSdesCryptoSuiteNames(session_options.crypto_options,
+ &crypto_suites);
if (!CreateMediaContentOffer(
- options,
- audio_codecs,
- sdes_policy,
- GetCryptos(GetFirstAudioContentDescription(current_description)),
- crypto_suites,
- audio_rtp_extensions,
- add_legacy_,
- current_streams,
- audio.get())) {
+ media_description_options.sender_options, session_options,
+ filtered_codecs, sdes_policy, GetCryptos(current_content),
+ crypto_suites, audio_rtp_extensions, current_streams, audio.get())) {
return false;
}
audio->set_lang(lang_);
@@ -1779,13 +1886,13 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
SetMediaProtocol(secure_transport, audio.get());
- auto offer_rtd =
- RtpTransceiverDirection(!audio->streams().empty(), options.recv_audio);
- audio->set_direction(offer_rtd.ToMediaContentDirection());
+ audio->set_direction(
+ media_description_options.direction.ToMediaContentDirection());
- desc->AddContent(content_name, NS_JINGLE_RTP, audio.release());
- if (!AddTransportOffer(content_name,
- GetTransportOptions(options, content_name),
+ desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
+ media_description_options.stopped, audio.release());
+ if (!AddTransportOffer(media_description_options.mid,
+ media_description_options.transport_options,
current_description, desc)) {
return false;
}
@@ -1794,87 +1901,98 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
}
bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
- const MediaSessionOptions& options,
+ const MediaDescriptionOptions& media_description_options,
+ const MediaSessionOptions& session_options,
+ const ContentInfo* current_content,
const SessionDescription* current_description,
const RtpHeaderExtensions& video_rtp_extensions,
const VideoCodecs& video_codecs,
StreamParamsVec* current_streams,
SessionDescription* desc) const {
- const ContentInfo* current_video_content =
- GetFirstVideoContent(current_description);
- std::string content_name =
- current_video_content ? current_video_content->name : CN_VIDEO;
-
cricket::SecurePolicy sdes_policy =
- IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
- : secure();
+ IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
+ : secure();
std::unique_ptr<VideoContentDescription> video(new VideoContentDescription());
std::vector<std::string> crypto_suites;
- GetSupportedVideoSdesCryptoSuiteNames(options.crypto_options, &crypto_suites);
+ GetSupportedVideoSdesCryptoSuiteNames(session_options.crypto_options,
+ &crypto_suites);
+
+ VideoCodecs filtered_codecs;
+ // Add the codecs from current content if exists.
+ if (current_content) {
+ RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
+ const VideoContentDescription* vcd =
+ static_cast<const VideoContentDescription*>(
+ current_content->description);
+ for (const VideoCodec& codec : vcd->codecs()) {
+ if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
+ nullptr)) {
+ filtered_codecs.push_back(codec);
+ }
+ }
+ }
+ // Add other supported video codecs.
+ VideoCodec found_codec;
+ for (const VideoCodec& codec : video_codecs_) {
+ if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
+ &found_codec) &&
+ !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
+ nullptr)) {
+ // Use the |found_codec| from |video_codecs| because it has the correctly
+ // mapped payload type.
+ filtered_codecs.push_back(found_codec);
+ }
+ }
+
if (!CreateMediaContentOffer(
- options,
- video_codecs,
- sdes_policy,
- GetCryptos(GetFirstVideoContentDescription(current_description)),
- crypto_suites,
- video_rtp_extensions,
- add_legacy_,
- current_streams,
- video.get())) {
+ media_description_options.sender_options, session_options,
+ filtered_codecs, sdes_policy, GetCryptos(current_content),
+ crypto_suites, video_rtp_extensions, current_streams, video.get())) {
return false;
}
- video->set_bandwidth(options.video_bandwidth);
+ video->set_bandwidth(kAutoBandwidth);
bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
SetMediaProtocol(secure_transport, video.get());
- if (!video->streams().empty()) {
- if (options.recv_video) {
- video->set_direction(MD_SENDRECV);
- } else {
- video->set_direction(MD_SENDONLY);
- }
- } else {
- if (options.recv_video) {
- video->set_direction(MD_RECVONLY);
- } else {
- video->set_direction(MD_INACTIVE);
- }
- }
+ video->set_direction(
+ media_description_options.direction.ToMediaContentDirection());
- desc->AddContent(content_name, NS_JINGLE_RTP, video.release());
- if (!AddTransportOffer(content_name,
- GetTransportOptions(options, content_name),
+ desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
+ media_description_options.stopped, video.release());
+ if (!AddTransportOffer(media_description_options.mid,
+ media_description_options.transport_options,
current_description, desc)) {
return false;
}
-
return true;
}
bool MediaSessionDescriptionFactory::AddDataContentForOffer(
- const MediaSessionOptions& options,
+ const MediaDescriptionOptions& media_description_options,
+ const MediaSessionOptions& session_options,
+ const ContentInfo* current_content,
const SessionDescription* current_description,
- DataCodecs* data_codecs,
+ const DataCodecs& data_codecs,
StreamParamsVec* current_streams,
SessionDescription* desc) const {
bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
std::unique_ptr<DataContentDescription> data(new DataContentDescription());
- bool is_sctp = (options.data_channel_type == DCT_SCTP);
-
- FilterDataCodecs(data_codecs, is_sctp);
-
- const ContentInfo* current_data_content =
- GetFirstDataContent(current_description);
- std::string content_name =
- current_data_content ? current_data_content->name : CN_DATA;
+ bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
+ // If the DataChannel type is not specified, use the DataChannel type in
+ // the current description.
+ if (session_options.data_channel_type == DCT_NONE && current_content) {
+ is_sctp = (static_cast<const DataContentDescription*>(
+ current_content->description)
+ ->protocol() == kMediaProtocolSctp);
+ }
cricket::SecurePolicy sdes_policy =
- IsDtlsActive(content_name, current_description) ? cricket::SEC_DISABLED
- : secure();
+ IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
+ : secure();
std::vector<std::string> crypto_suites;
if (is_sctp) {
// SDES doesn't make sense for SCTP, so we disable it, and we only
@@ -1890,227 +2008,279 @@ bool MediaSessionDescriptionFactory::AddDataContentForOffer(
data->set_protocol(
secure_transport ? kMediaProtocolDtlsSctp : kMediaProtocolSctp);
} else {
- GetSupportedDataSdesCryptoSuiteNames(options.crypto_options,
+ GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
&crypto_suites);
}
+ // Even SCTP uses a "codec".
if (!CreateMediaContentOffer(
- options,
- *data_codecs,
- sdes_policy,
- GetCryptos(GetFirstDataContentDescription(current_description)),
- crypto_suites,
- RtpHeaderExtensions(),
- add_legacy_,
- current_streams,
- data.get())) {
+ media_description_options.sender_options, session_options,
+ data_codecs, sdes_policy, GetCryptos(current_content), crypto_suites,
+ RtpHeaderExtensions(), current_streams, data.get())) {
return false;
}
if (is_sctp) {
- desc->AddContent(content_name, NS_JINGLE_DRAFT_SCTP, data.release());
+ desc->AddContent(media_description_options.mid, NS_JINGLE_DRAFT_SCTP,
+ data.release());
} else {
- data->set_bandwidth(options.data_bandwidth);
+ data->set_bandwidth(kDataMaxBandwidth);
SetMediaProtocol(secure_transport, data.get());
- desc->AddContent(content_name, NS_JINGLE_RTP, data.release());
+ desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
+ media_description_options.stopped, data.release());
}
- if (!AddTransportOffer(content_name,
- GetTransportOptions(options, content_name),
+ if (!AddTransportOffer(media_description_options.mid,
+ media_description_options.transport_options,
current_description, desc)) {
return false;
}
return true;
}
+// |audio_codecs| = set of all possible codecs that can be used, with correct
+// payload type mappings
+//
+// |supported_audio_codecs| = set of codecs that are supported for the direction
+// of this m= section
+//
+// acd->codecs() = set of previously negotiated codecs for this m= section
+//
+// The payload types should come from audio_codecs, but the order should come
+// from acd->codecs() and then supported_codecs, to ensure that re-offers don't
+// change existing codec priority, and that new codecs are added with the right
+// priority.
bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
- const SessionDescription* offer,
- const MediaSessionOptions& options,
+ const MediaDescriptionOptions& media_description_options,
+ const MediaSessionOptions& session_options,
+ const ContentInfo* offer_content,
+ const SessionDescription* offer_description,
+ const ContentInfo* current_content,
const SessionDescription* current_description,
const TransportInfo* bundle_transport,
+ const AudioCodecs& audio_codecs,
StreamParamsVec* current_streams,
SessionDescription* answer) const {
- const ContentInfo* audio_content = GetFirstAudioContent(offer);
- const AudioContentDescription* offer_audio =
- static_cast<const AudioContentDescription*>(audio_content->description);
+ const AudioContentDescription* offer_audio_description =
+ static_cast<const AudioContentDescription*>(offer_content->description);
std::unique_ptr<TransportDescription> audio_transport(
- CreateTransportAnswer(audio_content->name, offer,
- GetTransportOptions(options, audio_content->name),
+ CreateTransportAnswer(media_description_options.mid, offer_description,
+ media_description_options.transport_options,
current_description, bundle_transport != nullptr));
if (!audio_transport) {
return false;
}
- // Pick codecs based on the requested communications direction in the offer.
- const bool wants_send =
- options.HasSendMediaStream(MEDIA_TYPE_AUDIO) || add_legacy_;
- auto wants_rtd = RtpTransceiverDirection(wants_send, options.recv_audio);
- auto offer_rtd =
- RtpTransceiverDirection::FromMediaContentDirection(
- offer_audio->direction());
+ // Pick codecs based on the requested communications direction in the offer
+ // and the selected direction in the answer.
+ // Note these will be filtered one final time in CreateMediaContentAnswer.
+ auto wants_rtd = media_description_options.direction;
+ auto offer_rtd = RtpTransceiverDirection::FromMediaContentDirection(
+ offer_audio_description->direction());
auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
- AudioCodecs audio_codecs = GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
- if (!options.vad_enabled) {
- StripCNCodecs(&audio_codecs);
+ AudioCodecs supported_audio_codecs =
+ GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
+
+ AudioCodecs filtered_codecs;
+ // Add the codecs from current content if exists.
+ if (current_content) {
+ RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_AUDIO));
+ const AudioContentDescription* acd =
+ static_cast<const AudioContentDescription*>(
+ current_content->description);
+ for (const AudioCodec& codec : acd->codecs()) {
+ if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
+ codec, nullptr)) {
+ filtered_codecs.push_back(codec);
+ }
+ }
+ }
+ // Add other supported audio codecs.
+ AudioCodec found_codec;
+ for (const AudioCodec& codec : supported_audio_codecs) {
+ if (FindMatchingCodec<AudioCodec>(supported_audio_codecs, audio_codecs,
+ codec, &found_codec) &&
+ !FindMatchingCodec<AudioCodec>(supported_audio_codecs, filtered_codecs,
+ codec, nullptr)) {
+ // Use the |found_codec| from |audio_codecs| because it has the correctly
+ // mapped payload type.
+ filtered_codecs.push_back(found_codec);
+ }
}
- bool bundle_enabled =
- offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
+ bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
+ session_options.bundle_enabled;
std::unique_ptr<AudioContentDescription> audio_answer(
new AudioContentDescription());
// Do not require or create SDES cryptos if DTLS is used.
cricket::SecurePolicy sdes_policy =
audio_transport->secure() ? cricket::SEC_DISABLED : secure();
if (!CreateMediaContentAnswer(
- offer_audio,
- options,
- audio_codecs,
- sdes_policy,
- GetCryptos(GetFirstAudioContentDescription(current_description)),
- audio_rtp_extensions_,
- enable_encrypted_rtp_header_extensions_,
- current_streams,
- add_legacy_,
- bundle_enabled,
- audio_answer.get())) {
+ offer_audio_description, media_description_options, session_options,
+ filtered_codecs, sdes_policy, GetCryptos(current_content),
+ audio_rtp_extensions_, enable_encrypted_rtp_header_extensions_,
+ current_streams, bundle_enabled, audio_answer.get())) {
return false; // Fails the session setup.
}
bool secure = bundle_transport ? bundle_transport->description.secure()
: audio_transport->secure();
- bool rejected = !options.has_audio() || audio_content->rejected ||
+ bool rejected = media_description_options.stopped ||
+ offer_content->rejected ||
!IsMediaProtocolSupported(MEDIA_TYPE_AUDIO,
audio_answer->protocol(), secure);
if (!rejected) {
- AddTransportAnswer(audio_content->name, *(audio_transport.get()), answer);
+ AddTransportAnswer(media_description_options.mid, *(audio_transport.get()),
+ answer);
} else {
- // RFC 3264
- // The answer MUST contain the same number of m-lines as the offer.
- LOG(LS_INFO) << "Audio is not supported in the answer.";
+ LOG(LS_INFO) << "Audio m= section '" << media_description_options.mid
+ << "' being rejected in answer.";
}
- answer->AddContent(audio_content->name, audio_content->type, rejected,
- audio_answer.release());
+ answer->AddContent(media_description_options.mid, offer_content->type,
+ rejected, audio_answer.release());
return true;
}
bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
- const SessionDescription* offer,
- const MediaSessionOptions& options,
+ const MediaDescriptionOptions& media_description_options,
+ const MediaSessionOptions& session_options,
+ const ContentInfo* offer_content,
+ const SessionDescription* offer_description,
+ const ContentInfo* current_content,
const SessionDescription* current_description,
const TransportInfo* bundle_transport,
+ const VideoCodecs& video_codecs,
StreamParamsVec* current_streams,
SessionDescription* answer) const {
- const ContentInfo* video_content = GetFirstVideoContent(offer);
+ const VideoContentDescription* offer_video_description =
+ static_cast<const VideoContentDescription*>(offer_content->description);
+
std::unique_ptr<TransportDescription> video_transport(
- CreateTransportAnswer(video_content->name, offer,
- GetTransportOptions(options, video_content->name),
+ CreateTransportAnswer(media_description_options.mid, offer_description,
+ media_description_options.transport_options,
current_description, bundle_transport != nullptr));
if (!video_transport) {
return false;
}
+ VideoCodecs filtered_codecs;
+ // Add the codecs from current content if exists.
+ if (current_content) {
+ RTC_DCHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_VIDEO));
+ const VideoContentDescription* vcd =
+ static_cast<const VideoContentDescription*>(
+ current_content->description);
+ for (const VideoCodec& codec : vcd->codecs()) {
+ if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
+ nullptr)) {
+ filtered_codecs.push_back(codec);
+ }
+ }
+ }
+ // Add other supported video codecs.
+ VideoCodec found_codec;
+ for (const VideoCodec& codec : video_codecs_) {
+ if (FindMatchingCodec<VideoCodec>(video_codecs_, video_codecs, codec,
+ &found_codec) &&
+ !FindMatchingCodec<VideoCodec>(video_codecs_, filtered_codecs, codec,
+ nullptr)) {
+ // Use the |found_codec| from |video_codecs| because it has the correctly
+ // mapped payload type.
+ filtered_codecs.push_back(found_codec);
+ }
+ }
+
+ bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
+ session_options.bundle_enabled;
+
std::unique_ptr<VideoContentDescription> video_answer(
new VideoContentDescription());
// Do not require or create SDES cryptos if DTLS is used.
cricket::SecurePolicy sdes_policy =
video_transport->secure() ? cricket::SEC_DISABLED : secure();
- bool bundle_enabled =
- offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
if (!CreateMediaContentAnswer(
- static_cast<const VideoContentDescription*>(
- video_content->description),
- options,
- video_codecs_,
- sdes_policy,
- GetCryptos(GetFirstVideoContentDescription(current_description)),
- video_rtp_extensions_,
- enable_encrypted_rtp_header_extensions_,
- current_streams,
- add_legacy_,
- bundle_enabled,
- video_answer.get())) {
- return false;
+ offer_video_description, media_description_options, session_options,
+ filtered_codecs, sdes_policy, GetCryptos(current_content),
+ video_rtp_extensions_, enable_encrypted_rtp_header_extensions_,
+ current_streams, bundle_enabled, video_answer.get())) {
+ return false; // Failed the sessin setup.
}
bool secure = bundle_transport ? bundle_transport->description.secure()
: video_transport->secure();
- bool rejected = !options.has_video() || video_content->rejected ||
+ bool rejected = media_description_options.stopped ||
+ offer_content->rejected ||
!IsMediaProtocolSupported(MEDIA_TYPE_VIDEO,
video_answer->protocol(), secure);
if (!rejected) {
- if (!AddTransportAnswer(video_content->name, *(video_transport.get()),
- answer)) {
+ if (!AddTransportAnswer(media_description_options.mid,
+ *(video_transport.get()), answer)) {
return false;
}
- video_answer->set_bandwidth(options.video_bandwidth);
+ video_answer->set_bandwidth(kAutoBandwidth);
} else {
- // RFC 3264
- // The answer MUST contain the same number of m-lines as the offer.
- LOG(LS_INFO) << "Video is not supported in the answer.";
+ LOG(LS_INFO) << "Video m= section '" << media_description_options.mid
+ << "' being rejected in answer.";
}
- answer->AddContent(video_content->name, video_content->type, rejected,
- video_answer.release());
+ answer->AddContent(media_description_options.mid, offer_content->type,
+ rejected, video_answer.release());
return true;
}
bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
- const SessionDescription* offer,
- const MediaSessionOptions& options,
+ const MediaDescriptionOptions& media_description_options,
+ const MediaSessionOptions& session_options,
+ const ContentInfo* offer_content,
+ const SessionDescription* offer_description,
+ const ContentInfo* current_content,
const SessionDescription* current_description,
const TransportInfo* bundle_transport,
+ const DataCodecs& data_codecs,
StreamParamsVec* current_streams,
SessionDescription* answer) const {
- const ContentInfo* data_content = GetFirstDataContent(offer);
std::unique_ptr<TransportDescription> data_transport(
- CreateTransportAnswer(data_content->name, offer,
- GetTransportOptions(options, data_content->name),
+ CreateTransportAnswer(media_description_options.mid, offer_description,
+ media_description_options.transport_options,
current_description, bundle_transport != nullptr));
if (!data_transport) {
return false;
}
- bool is_sctp = (options.data_channel_type == DCT_SCTP);
- std::vector<DataCodec> data_codecs(data_codecs_);
- FilterDataCodecs(&data_codecs, is_sctp);
std::unique_ptr<DataContentDescription> data_answer(
new DataContentDescription());
// Do not require or create SDES cryptos if DTLS is used.
cricket::SecurePolicy sdes_policy =
data_transport->secure() ? cricket::SEC_DISABLED : secure();
- bool bundle_enabled =
- offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled;
+ bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
+ session_options.bundle_enabled;
if (!CreateMediaContentAnswer(
static_cast<const DataContentDescription*>(
- data_content->description),
- options,
- data_codecs_,
- sdes_policy,
- GetCryptos(GetFirstDataContentDescription(current_description)),
- RtpHeaderExtensions(),
- enable_encrypted_rtp_header_extensions_,
- current_streams,
- add_legacy_,
- bundle_enabled,
- data_answer.get())) {
+ offer_content->description),
+ media_description_options, session_options, data_codecs, sdes_policy,
+ GetCryptos(current_content), RtpHeaderExtensions(),
+ enable_encrypted_rtp_header_extensions_, current_streams,
+ bundle_enabled, data_answer.get())) {
return false; // Fails the session setup.
}
// Respond with sctpmap if the offer uses sctpmap.
const DataContentDescription* offer_data_description =
- static_cast<const DataContentDescription*>(data_content->description);
+ static_cast<const DataContentDescription*>(offer_content->description);
bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
data_answer->set_use_sctpmap(offer_uses_sctpmap);
bool secure = bundle_transport ? bundle_transport->description.secure()
: data_transport->secure();
- bool rejected = !options.has_data() || data_content->rejected ||
+ bool rejected = session_options.data_channel_type == DCT_NONE ||
+ media_description_options.stopped ||
+ offer_content->rejected ||
!IsMediaProtocolSupported(MEDIA_TYPE_DATA,
data_answer->protocol(), secure);
if (!rejected) {
- data_answer->set_bandwidth(options.data_bandwidth);
- if (!AddTransportAnswer(data_content->name, *(data_transport.get()),
- answer)) {
+ data_answer->set_bandwidth(kDataMaxBandwidth);
+ if (!AddTransportAnswer(media_description_options.mid,
+ *(data_transport.get()), answer)) {
return false;
}
} else {
@@ -2118,11 +2288,39 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
// The answer MUST contain the same number of m-lines as the offer.
LOG(LS_INFO) << "Data is not supported in the answer.";
}
- answer->AddContent(data_content->name, data_content->type, rejected,
- data_answer.release());
+ answer->AddContent(media_description_options.mid, offer_content->type,
+ rejected, data_answer.release());
return true;
}
+void MediaSessionDescriptionFactory::ComputeAudioCodecsIntersectionAndUnion() {
+ audio_sendrecv_codecs_.clear();
+ all_audio_codecs_.clear();
+ // Compute the audio codecs union.
+ for (const AudioCodec& send : audio_send_codecs_) {
+ all_audio_codecs_.push_back(send);
+ if (!FindMatchingCodec<AudioCodec>(audio_send_codecs_, audio_recv_codecs_,
+ send, nullptr)) {
+ // It doesn't make sense to have an RTX codec we support sending but not
+ // receiving.
+ RTC_DCHECK(!IsRtxCodec(send));
+ }
+ }
+ for (const AudioCodec& recv : audio_recv_codecs_) {
+ if (!FindMatchingCodec<AudioCodec>(audio_recv_codecs_, audio_send_codecs_,
+ recv, nullptr)) {
+ all_audio_codecs_.push_back(recv);
+ }
+ }
+ // Use NegotiateCodecs to merge our codec lists, since the operation is
+ // essentially the same. Put send_codecs as the offered_codecs, which is the
+ // order we'd like to follow. The reasoning is that encoding is usually more
+ // expensive than decoding, and prioritizing a codec in the send list probably
+ // means it's a codec we can handle efficiently.
+ NegotiateCodecs(audio_recv_codecs_, audio_send_codecs_,
+ &audio_sendrecv_codecs_);
+}
+
bool IsMediaContent(const ContentInfo* content) {
return (content &&
(content->type == NS_JINGLE_RTP ||
« no previous file with comments | « webrtc/pc/mediasession.h ('k') | webrtc/pc/mediasession_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698