Index: webrtc/pc/mediasession.cc |
diff --git a/webrtc/pc/mediasession.cc b/webrtc/pc/mediasession.cc |
index 000c289c186b9c2daa5f41b0730d96d55f2b2665..5e380883896728d14d285f5ad00070e273f28d89 100644 |
--- a/webrtc/pc/mediasession.cc |
+++ b/webrtc/pc/mediasession.cc |
@@ -22,6 +22,7 @@ |
#include "webrtc/base/checks.h" |
#include "webrtc/base/helpers.h" |
#include "webrtc/base/logging.h" |
+#include "webrtc/base/optional.h" |
#include "webrtc/base/stringutils.h" |
#include "webrtc/common_types.h" |
#include "webrtc/common_video/h264/profile_level_id.h" |
@@ -1430,6 +1431,9 @@ SessionDescription* MediaSessionDescriptionFactory::CreateOffer( |
SessionDescription* MediaSessionDescriptionFactory::CreateAnswer( |
const SessionDescription* offer, const MediaSessionOptions& options, |
const SessionDescription* current_description) const { |
+ if (!offer) { |
+ return nullptr; |
+ } |
// The answer contains the intersection of the codecs in the offer with the |
// codecs we support. As indicated by XEP-0167, we retain the same payload ids |
// from the offer in the answer. |
@@ -1438,55 +1442,61 @@ SessionDescription* MediaSessionDescriptionFactory::CreateAnswer( |
StreamParamsVec current_streams; |
GetCurrentStreamParams(current_description, ¤t_streams); |
- if (offer) { |
- 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, |
- ¤t_streams, answer.get())) { |
- return NULL; |
- } |
- } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) { |
- if (!AddVideoContentForAnswer(offer, options, current_description, |
- ¤t_streams, answer.get())) { |
- return NULL; |
- } |
- } else { |
- RTC_DCHECK(IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)); |
- if (!AddDataContentForAnswer(offer, options, current_description, |
- ¤t_streams, answer.get())) { |
- return NULL; |
- } |
- } |
- } |
- } |
- |
// If the offer supports BUNDLE, and we want to use it too, create a BUNDLE |
// group in the answer with the appropriate content names. |
- if (offer->HasGroup(GROUP_TYPE_BUNDLE) && options.bundle_enabled) { |
- const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE); |
- ContentGroup answer_bundle(GROUP_TYPE_BUNDLE); |
- for (ContentInfos::const_iterator content = answer->contents().begin(); |
- content != answer->contents().end(); ++content) { |
- if (!content->rejected && offer_bundle->HasContentName(content->name)) { |
- answer_bundle.AddContentName(content->name); |
+ const ContentGroup* offer_bundle = offer->GetGroupByName(GROUP_TYPE_BUNDLE); |
+ ContentGroup answer_bundle(GROUP_TYPE_BUNDLE); |
+ // 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(), ¤t_streams, |
+ answer.get())) { |
+ return NULL; |
} |
- } |
- if (answer_bundle.FirstContentName()) { |
- answer->AddGroup(answer_bundle); |
- |
- // Share the same ICE credentials and crypto params across all contents, |
- // as BUNDLE requires. |
- if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) { |
- LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle."; |
+ } else if (IsMediaContentOfType(&*it, MEDIA_TYPE_VIDEO)) { |
+ if (!AddVideoContentForAnswer(offer, options, current_description, |
+ bundle_transport.get(), ¤t_streams, |
+ answer.get())) { |
return NULL; |
} |
- |
- if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) { |
- LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle."; |
+ } else { |
+ RTC_DCHECK(IsMediaContentOfType(&*it, MEDIA_TYPE_DATA)); |
+ if (!AddDataContentForAnswer(offer, options, current_description, |
+ bundle_transport.get(), ¤t_streams, |
+ answer.get())) { |
return NULL; |
} |
} |
+ // 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 && |
+ offer_bundle->HasContentName(added.name)) { |
+ answer_bundle.AddContentName(added.name); |
+ bundle_transport.reset( |
+ new TransportInfo(*answer->GetTransportInfoByName(added.name))); |
+ } |
+ } |
+ |
+ // Only put BUNDLE group in answer if nonempty. |
+ if (answer_bundle.FirstContentName()) { |
+ answer->AddGroup(answer_bundle); |
+ |
+ // Share the same ICE credentials and crypto params across all contents, |
+ // as BUNDLE requires. |
+ if (!UpdateTransportInfoForBundle(answer_bundle, answer.get())) { |
+ LOG(LS_ERROR) << "CreateAnswer failed to UpdateTransportInfoForBundle."; |
+ return NULL; |
+ } |
+ |
+ if (!UpdateCryptoParamsForBundle(answer_bundle, answer.get())) { |
+ LOG(LS_ERROR) << "CreateAnswer failed to UpdateCryptoParamsForBundle."; |
+ return NULL; |
+ } |
} |
return answer.release(); |
@@ -1634,16 +1644,17 @@ TransportDescription* MediaSessionDescriptionFactory::CreateTransportAnswer( |
const std::string& content_name, |
const SessionDescription* offer_desc, |
const TransportOptions& transport_options, |
- const SessionDescription* current_desc) const { |
+ const SessionDescription* current_desc, |
+ bool require_transport_attributes) const { |
if (!transport_desc_factory_) |
return NULL; |
const TransportDescription* offer_tdesc = |
GetTransportDescription(content_name, offer_desc); |
const TransportDescription* current_tdesc = |
GetTransportDescription(content_name, current_desc); |
- return |
- transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options, |
- current_tdesc); |
+ return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options, |
+ require_transport_attributes, |
+ current_tdesc); |
} |
bool MediaSessionDescriptionFactory::AddTransportAnswer( |
@@ -1838,15 +1849,17 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( |
const SessionDescription* offer, |
const MediaSessionOptions& options, |
const SessionDescription* current_description, |
+ const TransportInfo* bundle_transport, |
StreamParamsVec* current_streams, |
SessionDescription* answer) const { |
const ContentInfo* audio_content = GetFirstAudioContent(offer); |
const AudioContentDescription* offer_audio = |
static_cast<const AudioContentDescription*>(audio_content->description); |
- std::unique_ptr<TransportDescription> audio_transport(CreateTransportAnswer( |
- audio_content->name, offer, |
- GetTransportOptions(options, audio_content->name), current_description)); |
+ std::unique_ptr<TransportDescription> audio_transport( |
+ CreateTransportAnswer(audio_content->name, offer, |
+ GetTransportOptions(options, audio_content->name), |
+ current_description, bundle_transport != nullptr)); |
if (!audio_transport) { |
return false; |
} |
@@ -1885,10 +1898,11 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer( |
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 || |
- !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO, |
- audio_answer->protocol(), |
- audio_transport->secure()); |
+ !IsMediaProtocolSupported(MEDIA_TYPE_AUDIO, |
+ audio_answer->protocol(), secure); |
if (!rejected) { |
AddTransportAnswer(audio_content->name, *(audio_transport.get()), answer); |
} else { |
@@ -1906,12 +1920,14 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( |
const SessionDescription* offer, |
const MediaSessionOptions& options, |
const SessionDescription* current_description, |
+ const TransportInfo* bundle_transport, |
StreamParamsVec* current_streams, |
SessionDescription* answer) const { |
const ContentInfo* video_content = GetFirstVideoContent(offer); |
- std::unique_ptr<TransportDescription> video_transport(CreateTransportAnswer( |
- video_content->name, offer, |
- GetTransportOptions(options, video_content->name), current_description)); |
+ std::unique_ptr<TransportDescription> video_transport( |
+ CreateTransportAnswer(video_content->name, offer, |
+ GetTransportOptions(options, video_content->name), |
+ current_description, bundle_transport != nullptr)); |
if (!video_transport) { |
return false; |
} |
@@ -1937,10 +1953,11 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer( |
video_answer.get())) { |
return false; |
} |
+ bool secure = bundle_transport ? bundle_transport->description.secure() |
+ : video_transport->secure(); |
bool rejected = !options.has_video() || video_content->rejected || |
- !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO, |
- video_answer->protocol(), |
- video_transport->secure()); |
+ !IsMediaProtocolSupported(MEDIA_TYPE_VIDEO, |
+ video_answer->protocol(), secure); |
if (!rejected) { |
if (!AddTransportAnswer(video_content->name, *(video_transport.get()), |
answer)) { |
@@ -1961,12 +1978,14 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer( |
const SessionDescription* offer, |
const MediaSessionOptions& options, |
const SessionDescription* current_description, |
+ const TransportInfo* bundle_transport, |
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), current_description)); |
+ std::unique_ptr<TransportDescription> data_transport( |
+ CreateTransportAnswer(data_content->name, offer, |
+ GetTransportOptions(options, data_content->name), |
+ current_description, bundle_transport != nullptr)); |
if (!data_transport) { |
return false; |
} |
@@ -2002,10 +2021,12 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer( |
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 || |
- !IsMediaProtocolSupported(MEDIA_TYPE_DATA, |
- data_answer->protocol(), |
- data_transport->secure()); |
+ !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()), |