| 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()),
|
|
|