Chromium Code Reviews| Index: webrtc/pc/mediasession.cc |
| diff --git a/webrtc/pc/mediasession.cc b/webrtc/pc/mediasession.cc |
| index 5e6942384ad734c0f8bfaa6be338bf8028e75540..2056c9800b60ff0f5d22a1cb1fb72772ec9c5e24 100644 |
| --- a/webrtc/pc/mediasession.cc |
| +++ b/webrtc/pc/mediasession.cc |
| @@ -1448,6 +1448,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. |
| @@ -1456,55 +1459,63 @@ 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. |
| + if (options.bundle_enabled) { |
| + ContentInfo& added = answer->contents().back(); |
| + if (!added.rejected && offer_bundle && |
| + offer_bundle->HasContentName(added.name)) { |
| + answer_bundle.AddContentName(added.name); |
| + bundle_transport.reset( |
| + new TransportInfo(*answer->GetTransportInfoByName(added.name))); |
|
pthatcher1
2017/02/17 19:17:32
Why do you need to set the bundle_transport here?
Taylor Brandstetter
2017/02/17 21:49:15
Because it's needed inside the loop, for AddXConte
|
| + } |
| + } |
|
pthatcher1
2017/02/17 19:17:32
Might be more clear with one if statement:
Conten
Taylor Brandstetter
2017/02/17 21:49:15
Done.
|
| + } |
|
pthatcher1
2017/02/17 19:17:32
If the offer has this:
a=bundle b a
m=
a=mid:a
m=
Taylor Brandstetter
2017/02/17 21:49:15
Yes we already do that. Yes, it's technically wron
|
| + |
| + // 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(); |
| @@ -1652,16 +1663,16 @@ 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 bundled) 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, |
| + current_tdesc, bundled); |
| } |
| bool MediaSessionDescriptionFactory::AddTransportAnswer( |
| @@ -1856,15 +1867,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; |
| } |
| @@ -1903,10 +1916,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 { |
| @@ -1924,12 +1938,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; |
| } |
| @@ -1955,10 +1971,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)) { |
| @@ -1979,12 +1996,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; |
| } |
| @@ -2014,10 +2033,11 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer( |
| return false; // Fails the session setup. |
| } |
| + 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()), |