blob: a2a216b6ed057ce7703821f201fd11ddfe8073d6 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kwiberg31022942016-03-11 14:18:21 -080011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <string>
13#include <vector>
14
Steve Anton6fe1fba2018-12-11 10:15:23 -080015#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "media/base/codec.h"
17#include "media/base/testutils.h"
18#include "p2p/base/p2pconstants.h"
19#include "p2p/base/transportdescription.h"
20#include "p2p/base/transportinfo.h"
21#include "pc/mediasession.h"
Steve Anton1d03a752017-11-27 14:30:09 -080022#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "pc/srtpfilter.h"
24#include "rtc_base/checks.h"
25#include "rtc_base/fakesslidentity.h"
26#include "rtc_base/gunit.h"
27#include "rtc_base/messagedigest.h"
28#include "rtc_base/ssladapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020029#include "rtc_base/strings/string_builder.h"
Steve Antone38a5a12018-11-21 16:05:15 -080030#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000031
Yves Gerey665174f2018-06-19 15:03:05 +020032#define ASSERT_CRYPTO(cd, s, cs) \
33 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080034 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035
36typedef std::vector<cricket::Candidate> Candidates;
37
38using cricket::MediaContentDescription;
39using cricket::MediaSessionDescriptionFactory;
zhihuang1c378ed2017-08-17 14:10:50 -070040using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041using cricket::MediaSessionOptions;
42using cricket::MediaType;
Steve Anton5adfafd2017-12-20 16:34:00 -080043using cricket::MediaProtocolType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000044using cricket::SessionDescription;
45using cricket::SsrcGroup;
46using cricket::StreamParams;
47using cricket::StreamParamsVec;
48using cricket::TransportDescription;
49using cricket::TransportDescriptionFactory;
50using cricket::TransportInfo;
51using cricket::ContentInfo;
52using cricket::CryptoParamsVec;
53using cricket::AudioContentDescription;
54using cricket::VideoContentDescription;
55using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080056using cricket::GetFirstAudioContent;
57using cricket::GetFirstVideoContent;
58using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059using cricket::GetFirstAudioContentDescription;
60using cricket::GetFirstVideoContentDescription;
61using cricket::GetFirstDataContentDescription;
62using cricket::kAutoBandwidth;
63using cricket::AudioCodec;
64using cricket::VideoCodec;
65using cricket::DataCodec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066using cricket::MEDIA_TYPE_AUDIO;
67using cricket::MEDIA_TYPE_VIDEO;
68using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069using cricket::SEC_DISABLED;
70using cricket::SEC_ENABLED;
71using cricket::SEC_REQUIRED;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070072using rtc::CS_AES_CM_128_HMAC_SHA1_32;
73using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070074using rtc::CS_AEAD_AES_128_GCM;
75using rtc::CS_AEAD_AES_256_GCM;
Steve Antone38a5a12018-11-21 16:05:15 -080076using testing::ElementsAreArray;
isheriff6f8d6862016-05-26 11:24:55 -070077using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080078using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079
80static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070081 AudioCodec(103, "ISAC", 16000, -1, 1),
82 AudioCodec(102, "iLBC", 8000, 13300, 1),
83 AudioCodec(0, "PCMU", 8000, 64000, 1),
84 AudioCodec(8, "PCMA", 8000, 64000, 1),
85 AudioCodec(117, "red", 8000, 0, 1),
86 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087
88static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +020089 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -070090 AudioCodec(0, "PCMU", 8000, 64000, 1),
91 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092};
93
94static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070095 AudioCodec(102, "iLBC", 8000, 13300, 1),
96 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097};
98
perkj26752742016-10-24 01:21:16 -070099static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
100 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101
zhihuang1c378ed2017-08-17 14:10:50 -0700102static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
103 VideoCodec(96, "H264-SVC")};
104
perkj26752742016-10-24 01:21:16 -0700105static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
106 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107
perkj26752742016-10-24 01:21:16 -0700108static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109
deadbeef67cf2c12016-04-13 10:07:16 -0700110static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
111 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
deadbeef67cf2c12016-04-13 10:07:16 -0700113static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
114 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115
deadbeef67cf2c12016-04-13 10:07:16 -0700116static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
117 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118
isheriff6f8d6862016-05-26 11:24:55 -0700119static const RtpExtension kAudioRtpExtension1[] = {
120 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
121 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122};
123
jbauch5869f502017-06-29 12:31:36 -0700124static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
125 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
126 RtpExtension("http://google.com/testing/audio_something", 10),
127 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
128};
129
isheriff6f8d6862016-05-26 11:24:55 -0700130static const RtpExtension kAudioRtpExtension2[] = {
131 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
132 RtpExtension("http://google.com/testing/audio_something_else", 8),
133 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134};
135
isheriff6f8d6862016-05-26 11:24:55 -0700136static const RtpExtension kAudioRtpExtension3[] = {
137 RtpExtension("http://google.com/testing/audio_something", 2),
138 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700139};
140
jbauch5869f502017-06-29 12:31:36 -0700141static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
142 RtpExtension("http://google.com/testing/audio_something", 2),
143 // Use RTP extension that supports encryption.
144 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
145};
146
147static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
148 RtpExtension("http://google.com/testing/audio_something", 2),
149 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
150 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
151};
152
isheriff6f8d6862016-05-26 11:24:55 -0700153static const RtpExtension kAudioRtpExtensionAnswer[] = {
154 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155};
156
jbauch5869f502017-06-29 12:31:36 -0700157static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
158 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
159};
160
isheriff6f8d6862016-05-26 11:24:55 -0700161static const RtpExtension kVideoRtpExtension1[] = {
162 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
163 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164};
165
jbauch5869f502017-06-29 12:31:36 -0700166static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
167 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
168 RtpExtension("http://google.com/testing/video_something", 13),
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
170};
171
isheriff6f8d6862016-05-26 11:24:55 -0700172static const RtpExtension kVideoRtpExtension2[] = {
173 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
174 RtpExtension("http://google.com/testing/video_something_else", 14),
175 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176};
177
isheriff6f8d6862016-05-26 11:24:55 -0700178static const RtpExtension kVideoRtpExtension3[] = {
179 RtpExtension("http://google.com/testing/video_something", 4),
180 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700181};
182
jbauch5869f502017-06-29 12:31:36 -0700183static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
184 RtpExtension("http://google.com/testing/video_something", 4),
185 // Use RTP extension that supports encryption.
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
187};
188
isheriff6f8d6862016-05-26 11:24:55 -0700189static const RtpExtension kVideoRtpExtensionAnswer[] = {
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000191};
192
jbauch5869f502017-06-29 12:31:36 -0700193static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
194 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
195};
196
Peter Boström0c4e06b2015-10-07 12:23:21 +0200197static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
198static const uint32_t kSimSsrc[] = {10, 20, 30};
199static const uint32_t kFec1Ssrc[] = {10, 11};
200static const uint32_t kFec2Ssrc[] = {20, 21};
201static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202
203static const char kMediaStream1[] = "stream_1";
204static const char kMediaStream2[] = "stream_2";
205static const char kVideoTrack1[] = "video_1";
206static const char kVideoTrack2[] = "video_2";
207static const char kAudioTrack1[] = "audio_1";
208static const char kAudioTrack2[] = "audio_2";
209static const char kAudioTrack3[] = "audio_3";
210static const char kDataTrack1[] = "data_1";
211static const char kDataTrack2[] = "data_2";
212static const char kDataTrack3[] = "data_3";
213
zhihuangcf5b37c2016-05-05 11:44:35 -0700214static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
215 "RTP/SAVPF"};
216static const char* kMediaProtocolsDtls[] = {
217 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
218 "UDP/TLS/RTP/SAVP"};
219
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700220// SRTP cipher name negotiated by the tests. This must be updated if the
221// default changes.
222static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
223static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
224
zhihuang1c378ed2017-08-17 14:10:50 -0700225// These constants are used to make the code using "AddMediaSection" more
226// readable.
227static constexpr bool kStopped = true;
228static constexpr bool kActive = false;
229
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000230static bool IsMediaContentOfType(const ContentInfo* content,
231 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800232 RTC_DCHECK(content);
233 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000234}
235
Steve Anton4e70a722017-11-28 14:57:10 -0800236static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800237 RTC_DCHECK(content);
238 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000239}
240
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000241static void AddRtxCodec(const VideoCodec& rtx_codec,
242 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800243 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000244 codecs->push_back(rtx_codec);
245}
246
247template <class T>
248static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
249 std::vector<std::string> codec_names;
250 for (const auto& codec : codecs) {
251 codec_names.push_back(codec.name);
252 }
253 return codec_names;
254}
255
zhihuang1c378ed2017-08-17 14:10:50 -0700256// This is used for test only. MIDs are not the identification of the
257// MediaDescriptionOptions since some end points may not support MID and the SDP
258// may not contain 'mid'.
259std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
260 const std::string& mid,
261 MediaSessionOptions* opts) {
262 return std::find_if(
263 opts->media_description_options.begin(),
264 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700265 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
266}
267
268std::vector<MediaDescriptionOptions>::const_iterator
269FindFirstMediaDescriptionByMid(const std::string& mid,
270 const MediaSessionOptions& opts) {
271 return std::find_if(
272 opts.media_description_options.begin(),
273 opts.media_description_options.end(),
274 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700275}
276
277// Add a media section to the |session_options|.
278static void AddMediaSection(MediaType type,
279 const std::string& mid,
Steve Anton4e70a722017-11-28 14:57:10 -0800280 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700281 bool stopped,
282 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800283 opts->media_description_options.push_back(
284 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700285}
286
Steve Anton4e70a722017-11-28 14:57:10 -0800287static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700288 MediaSessionOptions* opts) {
289 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
290 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
291}
292
293static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800294 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700295 MediaSessionOptions* opts) {
296 opts->data_channel_type = dct;
297 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
298}
299
Steve Anton8ffb9c32017-08-31 15:45:38 -0700300static void AttachSenderToMediaSection(
301 const std::string& mid,
302 MediaType type,
303 const std::string& track_id,
304 const std::vector<std::string>& stream_ids,
305 int num_sim_layer,
306 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700307 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
308 switch (type) {
309 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700310 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700311 break;
312 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700313 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700314 break;
315 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700316 RTC_CHECK(stream_ids.size() == 1U);
317 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700318 break;
319 default:
320 RTC_NOTREACHED();
321 }
322}
323
324static void DetachSenderFromMediaSection(const std::string& mid,
325 const std::string& track_id,
326 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700327 std::vector<cricket::SenderOptions>& sender_options_list =
328 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
329 auto sender_it =
330 std::find_if(sender_options_list.begin(), sender_options_list.end(),
331 [track_id](const cricket::SenderOptions& sender_options) {
332 return sender_options.track_id == track_id;
333 });
334 RTC_DCHECK(sender_it != sender_options_list.end());
335 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700336}
337
338// Helper function used to create a default MediaSessionOptions for Plan B SDP.
339// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
340static MediaSessionOptions CreatePlanBMediaSessionOptions() {
341 MediaSessionOptions session_options;
Steve Anton4e70a722017-11-28 14:57:10 -0800342 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
343 kActive, &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700344 return session_options;
345}
346
347// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
348// was designed for Plan B SDP, where only one audio "m=" section and one video
349// "m=" section could be generated, and ordering couldn't be controlled. Many of
350// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351class MediaSessionDescriptionFactoryTest : public testing::Test {
352 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700353 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700354 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
355 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
357 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700358 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
359 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000360 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
361 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200362 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700363 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200364 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700365 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000366 }
367
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000368 // Create a video StreamParamsVec object with:
369 // - one video stream with 3 simulcast streams and FEC,
370 StreamParamsVec CreateComplexVideoStreamParamsVec() {
371 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
372 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
373 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
374 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
375
376 std::vector<SsrcGroup> ssrc_groups;
377 ssrc_groups.push_back(sim_group);
378 ssrc_groups.push_back(fec_group1);
379 ssrc_groups.push_back(fec_group2);
380 ssrc_groups.push_back(fec_group3);
381
382 StreamParams simulcast_params;
383 simulcast_params.id = kVideoTrack1;
384 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
385 simulcast_params.ssrc_groups = ssrc_groups;
386 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800387 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000388
389 StreamParamsVec video_streams;
390 video_streams.push_back(simulcast_params);
391
392 return video_streams;
393 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000394
395 bool CompareCryptoParams(const CryptoParamsVec& c1,
396 const CryptoParamsVec& c2) {
397 if (c1.size() != c2.size())
398 return false;
399 for (size_t i = 0; i < c1.size(); ++i)
400 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
401 c1[i].key_params != c2[i].key_params ||
402 c1[i].session_params != c2[i].session_params)
403 return false;
404 return true;
405 }
406
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700407 // Returns true if the transport info contains "renomination" as an
408 // ICE option.
409 bool GetIceRenomination(const TransportInfo* transport_info) {
410 const std::vector<std::string>& ice_options =
411 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700412 auto iter =
413 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700414 return iter != ice_options.end();
415 }
416
zhihuang1c378ed2017-08-17 14:10:50 -0700417 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700418 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 bool has_current_desc) {
420 const std::string current_audio_ufrag = "current_audio_ufrag";
421 const std::string current_audio_pwd = "current_audio_pwd";
422 const std::string current_video_ufrag = "current_video_ufrag";
423 const std::string current_video_pwd = "current_video_pwd";
424 const std::string current_data_ufrag = "current_data_ufrag";
425 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800426 std::unique_ptr<SessionDescription> current_desc;
427 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000428 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800429 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800430 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200431 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800432 TransportDescription(current_audio_ufrag, current_audio_pwd)));
433 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200434 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800435 TransportDescription(current_video_ufrag, current_video_pwd)));
436 current_desc->AddTransportInfo(TransportInfo(
437 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 }
439 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800440 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000441 } else {
kwiberg31022942016-03-11 14:18:21 -0800442 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800443 offer = f1_.CreateOffer(options, NULL);
444 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000445 }
446 ASSERT_TRUE(desc.get() != NULL);
447 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000448 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 EXPECT_TRUE(ti_audio != NULL);
450 if (has_current_desc) {
451 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
452 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
453 } else {
454 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
455 ti_audio->description.ice_ufrag.size());
456 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
457 ti_audio->description.ice_pwd.size());
458 }
zhihuang1c378ed2017-08-17 14:10:50 -0700459 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700460 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700461 EXPECT_EQ(
462 media_desc_options_it->transport_options.enable_ice_renomination,
463 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464
465 } else {
466 EXPECT_TRUE(ti_audio == NULL);
467 }
468 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000469 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000470 EXPECT_TRUE(ti_video != NULL);
471 if (options.bundle_enabled) {
472 EXPECT_EQ(ti_audio->description.ice_ufrag,
473 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200474 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475 } else {
476 if (has_current_desc) {
477 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
478 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
479 } else {
480 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
481 ti_video->description.ice_ufrag.size());
482 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
483 ti_video->description.ice_pwd.size());
484 }
485 }
zhihuang1c378ed2017-08-17 14:10:50 -0700486 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700487 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700488 EXPECT_EQ(
489 media_desc_options_it->transport_options.enable_ice_renomination,
490 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000491 } else {
492 EXPECT_TRUE(ti_video == NULL);
493 }
494 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
495 if (options.has_data()) {
496 EXPECT_TRUE(ti_data != NULL);
497 if (options.bundle_enabled) {
498 EXPECT_EQ(ti_audio->description.ice_ufrag,
499 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200500 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 } else {
502 if (has_current_desc) {
503 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
504 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
505 } else {
506 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
507 ti_data->description.ice_ufrag.size());
508 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
509 ti_data->description.ice_pwd.size());
510 }
511 }
zhihuang1c378ed2017-08-17 14:10:50 -0700512 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700513 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700514 EXPECT_EQ(
515 media_desc_options_it->transport_options.enable_ice_renomination,
516 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700517
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 } else {
519 EXPECT_TRUE(ti_video == NULL);
520 }
521 }
522
523 void TestCryptoWithBundle(bool offer) {
524 f1_.set_secure(SEC_ENABLED);
525 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800526 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
527 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
528 &options);
kwiberg31022942016-03-11 14:18:21 -0800529 std::unique_ptr<SessionDescription> ref_desc;
530 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 if (offer) {
532 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800533 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800535 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 } else {
537 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800538 ref_desc = f1_.CreateOffer(options, NULL);
539 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800541 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000542 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800543 desc->GetContentDescriptionByName("audio");
544 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800546 desc->GetContentDescriptionByName("video");
547 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
549 video_media_desc->cryptos()));
550 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800551 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 audio_media_desc->cryptos()[0].cipher_suite);
553
554 // Verify the selected crypto is one from the reference audio
555 // media content.
556 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800557 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558 bool found = false;
559 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
560 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200561 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 found = true;
563 break;
564 }
565 }
566 EXPECT_TRUE(found);
567 }
568
569 // This test that the audio and video media direction is set to
570 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700571 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800573 RtpTransceiverDirection direction_in_offer,
574 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700575 MediaSessionOptions offer_opts;
576 AddAudioVideoSections(direction_in_offer, &offer_opts);
577
Steve Anton6fe1fba2018-12-11 10:15:23 -0800578 std::unique_ptr<SessionDescription> offer =
579 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700581 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700583 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585
zhihuang1c378ed2017-08-17 14:10:50 -0700586 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800587 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800588 std::unique_ptr<SessionDescription> answer =
589 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 const AudioContentDescription* acd_answer =
591 GetFirstAudioContentDescription(answer.get());
592 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
593 const VideoContentDescription* vcd_answer =
594 GetFirstVideoContentDescription(answer.get());
595 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
596 }
597
598 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800599 RTC_DCHECK(content);
600 RTC_CHECK(content->media_description());
601 const cricket::AudioContentDescription* audio_desc =
602 content->media_description()->as_audio();
603 RTC_CHECK(audio_desc);
604 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
605 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800607 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 }
609 return true;
610 }
611
jbauchcb560652016-08-04 05:20:32 -0700612 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
613 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800614 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700615 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700616
jbauchcb560652016-08-04 05:20:32 -0700617 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800618 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700619 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700620
jbauchcb560652016-08-04 05:20:32 -0700621 f1_.set_secure(SEC_ENABLED);
622 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800623 std::unique_ptr<SessionDescription> offer =
624 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700625 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800626 std::unique_ptr<SessionDescription> answer =
627 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700628 const ContentInfo* ac = answer->GetContentByName("audio");
629 const ContentInfo* vc = answer->GetContentByName("video");
630 ASSERT_TRUE(ac != NULL);
631 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800632 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
633 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800634 const AudioContentDescription* acd = ac->media_description()->as_audio();
635 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700636 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800637 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700638 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700639 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700640 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
641 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700642 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700643 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700644 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700645 }
646 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800647 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200648 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
649 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700650 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700651 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700652 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700653 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700654 }
Steve Antone38a5a12018-11-21 16:05:15 -0800655 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700656 }
657
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 protected:
659 MediaSessionDescriptionFactory f1_;
660 MediaSessionDescriptionFactory f2_;
661 TransportDescriptionFactory tdf1_;
662 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663};
664
665// Create a typical audio offer, and ensure it matches what we expect.
666TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
667 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800668 std::unique_ptr<SessionDescription> offer =
669 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 ASSERT_TRUE(offer.get() != NULL);
671 const ContentInfo* ac = offer->GetContentByName("audio");
672 const ContentInfo* vc = offer->GetContentByName("video");
673 ASSERT_TRUE(ac != NULL);
674 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800675 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800676 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700678 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700679 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
681 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700682 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800683 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684}
685
686// Create a typical video offer, and ensure it matches what we expect.
687TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
688 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800689 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000690 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800691 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 ASSERT_TRUE(offer.get() != NULL);
693 const ContentInfo* ac = offer->GetContentByName("audio");
694 const ContentInfo* vc = offer->GetContentByName("video");
695 ASSERT_TRUE(ac != NULL);
696 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800697 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
698 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800699 const AudioContentDescription* acd = ac->media_description()->as_audio();
700 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700702 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700703 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000704 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
705 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700706 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800707 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000708 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
709 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700710 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
712 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700713 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800714 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000715}
716
717// Test creating an offer with bundle where the Codecs have the same dynamic
718// RTP playlod type. The test verifies that the offer don't contain the
719// duplicate RTP payload types.
720TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
721 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700722 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000723 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
724 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
725 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
726
727 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800728 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
729 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800731 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732 const VideoContentDescription* vcd =
733 GetFirstVideoContentDescription(offer.get());
734 const AudioContentDescription* acd =
735 GetFirstAudioContentDescription(offer.get());
736 const DataContentDescription* dcd =
737 GetFirstDataContentDescription(offer.get());
738 ASSERT_TRUE(NULL != vcd);
739 ASSERT_TRUE(NULL != acd);
740 ASSERT_TRUE(NULL != dcd);
741 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
742 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
743 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
744 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
745 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
746 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
747}
748
zhihuang1c378ed2017-08-17 14:10:50 -0700749// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750// after an audio only session has been negotiated.
751TEST_F(MediaSessionDescriptionFactoryTest,
752 TestCreateUpdatedVideoOfferWithBundle) {
753 f1_.set_secure(SEC_ENABLED);
754 f2_.set_secure(SEC_ENABLED);
755 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800756 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
757 kActive, &opts);
758 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kInactive,
759 kStopped, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 opts.data_channel_type = cricket::DCT_NONE;
761 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800762 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
763 std::unique_ptr<SessionDescription> answer =
764 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000765
766 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800767 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
768 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
769 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800771 std::unique_ptr<SessionDescription> updated_offer(
772 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773
774 const AudioContentDescription* acd =
775 GetFirstAudioContentDescription(updated_offer.get());
776 const VideoContentDescription* vcd =
777 GetFirstVideoContentDescription(updated_offer.get());
778 const DataContentDescription* dcd =
779 GetFirstDataContentDescription(updated_offer.get());
780 EXPECT_TRUE(NULL != vcd);
781 EXPECT_TRUE(NULL != acd);
782 EXPECT_TRUE(NULL != dcd);
783
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700784 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800785 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700786 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800787 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700788 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800789 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790}
deadbeef44f08192015-12-15 16:20:09 -0800791
wu@webrtc.org78187522013-10-07 23:32:02 +0000792// Create a RTP data offer, and ensure it matches what we expect.
793TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800795 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
796 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800798 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 ASSERT_TRUE(offer.get() != NULL);
800 const ContentInfo* ac = offer->GetContentByName("audio");
801 const ContentInfo* dc = offer->GetContentByName("data");
802 ASSERT_TRUE(ac != NULL);
803 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800804 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
805 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800806 const AudioContentDescription* acd = ac->media_description()->as_audio();
807 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700809 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700810 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
812 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700813 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800814 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
816 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700817 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200819 dcd->bandwidth()); // default bandwidth (auto)
820 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700821 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800822 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823}
824
wu@webrtc.org78187522013-10-07 23:32:02 +0000825// Create an SCTP data offer with bundle without error.
826TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
827 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000828 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800829 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000830 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800831 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000832 EXPECT_TRUE(offer.get() != NULL);
833 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
834}
835
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000836// Test creating an sctp data channel from an already generated offer.
837TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
838 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000839 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800840 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000841 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800842 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000843 ASSERT_TRUE(offer1.get() != NULL);
844 const ContentInfo* data = offer1->GetContentByName("data");
845 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800846 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000847
848 // Now set data_channel_type to 'none' (default) and make sure that the
849 // datachannel type that gets generated from the previous offer, is of the
850 // same type.
851 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800852 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000853 f1_.CreateOffer(opts, offer1.get()));
854 data = offer2->GetContentByName("data");
855 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800856 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000857}
858
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859// Create an audio, video offer without legacy StreamParams.
860TEST_F(MediaSessionDescriptionFactoryTest,
861 TestCreateOfferWithoutLegacyStreams) {
862 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800863 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800864 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 ASSERT_TRUE(offer.get() != NULL);
866 const ContentInfo* ac = offer->GetContentByName("audio");
867 const ContentInfo* vc = offer->GetContentByName("video");
868 ASSERT_TRUE(ac != NULL);
869 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800870 const AudioContentDescription* acd = ac->media_description()->as_audio();
871 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872
Yves Gerey665174f2018-06-19 15:03:05 +0200873 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
874 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000875}
876
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000877// Creates an audio+video sendonly offer.
878TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700879 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800880 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700881 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700882 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700883 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700884 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000885
Steve Anton6fe1fba2018-12-11 10:15:23 -0800886 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000887 ASSERT_TRUE(offer.get() != NULL);
888 EXPECT_EQ(2u, offer->contents().size());
889 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
890 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
891
Steve Anton4e70a722017-11-28 14:57:10 -0800892 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
893 GetMediaDirection(&offer->contents()[0]));
894 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
895 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000896}
897
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000898// Verifies that the order of the media contents in the current
899// SessionDescription is preserved in the new SessionDescription.
900TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
901 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800902 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000903
kwiberg31022942016-03-11 14:18:21 -0800904 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000905 ASSERT_TRUE(offer1.get() != NULL);
906 EXPECT_EQ(1u, offer1->contents().size());
907 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
908
Steve Anton4e70a722017-11-28 14:57:10 -0800909 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
910 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800911 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000912 f1_.CreateOffer(opts, offer1.get()));
913 ASSERT_TRUE(offer2.get() != NULL);
914 EXPECT_EQ(2u, offer2->contents().size());
915 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
916 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
917
Steve Anton4e70a722017-11-28 14:57:10 -0800918 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
919 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800920 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000921 f1_.CreateOffer(opts, offer2.get()));
922 ASSERT_TRUE(offer3.get() != NULL);
923 EXPECT_EQ(3u, offer3->contents().size());
924 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
925 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
926 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000927}
928
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000929// Create a typical audio answer, and ensure it matches what we expect.
930TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
931 f1_.set_secure(SEC_ENABLED);
932 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800933 std::unique_ptr<SessionDescription> offer =
934 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000935 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800936 std::unique_ptr<SessionDescription> answer =
937 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000938 const ContentInfo* ac = answer->GetContentByName("audio");
939 const ContentInfo* vc = answer->GetContentByName("video");
940 ASSERT_TRUE(ac != NULL);
941 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800942 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800943 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800945 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -0700946 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
948 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700949 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800950 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951}
952
jbauchcb560652016-08-04 05:20:32 -0700953// Create a typical audio answer with GCM ciphers enabled, and ensure it
954// matches what we expect.
955TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
956 f1_.set_secure(SEC_ENABLED);
957 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700958 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700959 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800960 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700961 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800962 std::unique_ptr<SessionDescription> answer =
963 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700964 const ContentInfo* ac = answer->GetContentByName("audio");
965 const ContentInfo* vc = answer->GetContentByName("video");
966 ASSERT_TRUE(ac != NULL);
967 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800968 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800969 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -0700970 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800971 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -0700972 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700973 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
974 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700975 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -0800976 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700977}
978
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979// Create a typical video answer, and ensure it matches what we expect.
980TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
981 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800982 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983 f1_.set_secure(SEC_ENABLED);
984 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800985 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800987 std::unique_ptr<SessionDescription> answer =
988 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000989 const ContentInfo* ac = answer->GetContentByName("audio");
990 const ContentInfo* vc = answer->GetContentByName("video");
991 ASSERT_TRUE(ac != NULL);
992 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800993 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
994 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800995 const AudioContentDescription* acd = ac->media_description()->as_audio();
996 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000997 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800998 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000999 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001000 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001001 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001002 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001004 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001005 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1006 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001007 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001008 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001009}
1010
jbauchcb560652016-08-04 05:20:32 -07001011// Create a typical video answer with GCM ciphers enabled, and ensure it
1012// matches what we expect.
1013TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1014 TestVideoGcmCipher(true, true);
1015}
1016
1017// Create a typical video answer with GCM ciphers enabled for the offer only,
1018// and ensure it matches what we expect.
1019TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1020 TestVideoGcmCipher(true, false);
1021}
1022
1023// Create a typical video answer with GCM ciphers enabled for the answer only,
1024// and ensure it matches what we expect.
1025TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1026 TestVideoGcmCipher(false, true);
1027}
1028
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001030 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001031 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001032 f1_.set_secure(SEC_ENABLED);
1033 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001034 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001035 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001036 std::unique_ptr<SessionDescription> answer =
1037 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001038 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001039 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001041 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001042 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1043 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001044 const AudioContentDescription* acd = ac->media_description()->as_audio();
1045 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001046 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001047 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001048 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001049 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001050 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001051 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001052 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001053 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001054 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001055 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001056 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001057 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001058}
1059
jbauchcb560652016-08-04 05:20:32 -07001060TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001061 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001062 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001063 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001064 f1_.set_secure(SEC_ENABLED);
1065 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001066 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001067 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001068 std::unique_ptr<SessionDescription> answer =
1069 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001070 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001071 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001072 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001073 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001074 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1075 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001076 const AudioContentDescription* acd = ac->media_description()->as_audio();
1077 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001078 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001079 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001080 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001081 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001082 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001083 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001084 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001085 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001086 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001087 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001088 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001089 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001090}
1091
1092// The use_sctpmap flag should be set in a DataContentDescription by default.
1093// The answer's use_sctpmap flag should match the offer's.
1094TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1095 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001096 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001097 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001098 ASSERT_TRUE(offer.get() != NULL);
1099 ContentInfo* dc_offer = offer->GetContentByName("data");
1100 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001101 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001102 EXPECT_TRUE(dcd_offer->use_sctpmap());
1103
Steve Anton6fe1fba2018-12-11 10:15:23 -08001104 std::unique_ptr<SessionDescription> answer =
1105 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001106 const ContentInfo* dc_answer = answer->GetContentByName("data");
1107 ASSERT_TRUE(dc_answer != NULL);
1108 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001109 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001110 EXPECT_TRUE(dcd_answer->use_sctpmap());
1111}
1112
1113// The answer's use_sctpmap flag should match the offer's.
1114TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1115 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001116 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001117 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001118 ASSERT_TRUE(offer.get() != NULL);
1119 ContentInfo* dc_offer = offer->GetContentByName("data");
1120 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001121 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001122 dcd_offer->set_use_sctpmap(false);
1123
Steve Anton6fe1fba2018-12-11 10:15:23 -08001124 std::unique_ptr<SessionDescription> answer =
1125 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001126 const ContentInfo* dc_answer = answer->GetContentByName("data");
1127 ASSERT_TRUE(dc_answer != NULL);
1128 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001129 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001130 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001131}
1132
deadbeef8b7e9ad2017-05-25 09:38:55 -07001133// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1134// and "TCP/DTLS/SCTP" offers.
1135TEST_F(MediaSessionDescriptionFactoryTest,
1136 TestCreateDataAnswerToDifferentOfferedProtos) {
1137 // Need to enable DTLS offer/answer generation (disabled by default in this
1138 // test).
1139 f1_.set_secure(SEC_ENABLED);
1140 f2_.set_secure(SEC_ENABLED);
1141 tdf1_.set_secure(SEC_ENABLED);
1142 tdf2_.set_secure(SEC_ENABLED);
1143
1144 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001145 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001146 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001147 ASSERT_TRUE(offer.get() != nullptr);
1148 ContentInfo* dc_offer = offer->GetContentByName("data");
1149 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001150 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001151
1152 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1153 "TCP/DTLS/SCTP"};
1154 for (const std::string& proto : protos) {
1155 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001156 std::unique_ptr<SessionDescription> answer =
1157 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001158 const ContentInfo* dc_answer = answer->GetContentByName("data");
1159 ASSERT_TRUE(dc_answer != nullptr);
1160 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001161 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001162 EXPECT_FALSE(dc_answer->rejected);
1163 EXPECT_EQ(proto, dcd_answer->protocol());
1164 }
1165}
1166
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001167// Verifies that the order of the media contents in the offer is preserved in
1168// the answer.
1169TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1170 MediaSessionOptions opts;
1171
1172 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001173 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001174 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001175 ASSERT_TRUE(offer1.get() != NULL);
1176
1177 // Appends audio to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001178 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1179 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001180 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001181 f1_.CreateOffer(opts, offer1.get()));
1182 ASSERT_TRUE(offer2.get() != NULL);
1183
1184 // Appends video to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001185 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1186 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001187 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001188 f1_.CreateOffer(opts, offer2.get()));
1189 ASSERT_TRUE(offer3.get() != NULL);
1190
Steve Anton6fe1fba2018-12-11 10:15:23 -08001191 std::unique_ptr<SessionDescription> answer =
1192 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001193 ASSERT_TRUE(answer.get() != NULL);
1194 EXPECT_EQ(3u, answer->contents().size());
1195 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1196 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1197 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1198}
1199
ossu075af922016-06-14 03:29:38 -07001200// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1201// answerer settings.
1202
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203// This test that the media direction is set to send/receive in an answer if
1204// the offer is send receive.
1205TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001206 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1207 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001208}
1209
1210// This test that the media direction is set to receive only in an answer if
1211// the offer is send only.
1212TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001213 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1214 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001215}
1216
1217// This test that the media direction is set to send only in an answer if
1218// the offer is recv only.
1219TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001220 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1221 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222}
1223
1224// This test that the media direction is set to inactive in an answer if
1225// the offer is inactive.
1226TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001227 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1228 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229}
1230
1231// Test that a data content with an unknown protocol is rejected in an answer.
1232TEST_F(MediaSessionDescriptionFactoryTest,
1233 CreateDataAnswerToOfferWithUnknownProtocol) {
1234 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001235 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001236 f1_.set_secure(SEC_ENABLED);
1237 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001238 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001239 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001241 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 ASSERT_TRUE(dcd_offer != NULL);
1243 std::string protocol = "a weird unknown protocol";
1244 dcd_offer->set_protocol(protocol);
1245
Steve Anton6fe1fba2018-12-11 10:15:23 -08001246 std::unique_ptr<SessionDescription> answer =
1247 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248
1249 const ContentInfo* dc_answer = answer->GetContentByName("data");
1250 ASSERT_TRUE(dc_answer != NULL);
1251 EXPECT_TRUE(dc_answer->rejected);
1252 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001253 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254 ASSERT_TRUE(dcd_answer != NULL);
1255 EXPECT_EQ(protocol, dcd_answer->protocol());
1256}
1257
1258// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1259TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001260 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 f1_.set_secure(SEC_DISABLED);
1262 f2_.set_secure(SEC_DISABLED);
1263 tdf1_.set_secure(SEC_DISABLED);
1264 tdf2_.set_secure(SEC_DISABLED);
1265
Steve Anton6fe1fba2018-12-11 10:15:23 -08001266 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267 const AudioContentDescription* offer_acd =
1268 GetFirstAudioContentDescription(offer.get());
1269 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001270 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271
Steve Anton6fe1fba2018-12-11 10:15:23 -08001272 std::unique_ptr<SessionDescription> answer =
1273 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274
1275 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1276 ASSERT_TRUE(ac_answer != NULL);
1277 EXPECT_FALSE(ac_answer->rejected);
1278
1279 const AudioContentDescription* answer_acd =
1280 GetFirstAudioContentDescription(answer.get());
1281 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001282 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001283}
1284
1285// Create a video offer and answer and ensure the RTP header extensions
1286// matches what we expect.
1287TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1288 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001289 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001290 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1291 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1292 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1293 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1294
Steve Anton6fe1fba2018-12-11 10:15:23 -08001295 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001297 std::unique_ptr<SessionDescription> answer =
1298 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001299
Yves Gerey665174f2018-06-19 15:03:05 +02001300 EXPECT_EQ(
1301 MAKE_VECTOR(kAudioRtpExtension1),
1302 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1303 EXPECT_EQ(
1304 MAKE_VECTOR(kVideoRtpExtension1),
1305 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1306 EXPECT_EQ(
1307 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1308 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1309 EXPECT_EQ(
1310 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1311 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312}
1313
jbauch5869f502017-06-29 12:31:36 -07001314TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001315 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001316 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001317 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001318
1319 f1_.set_enable_encrypted_rtp_header_extensions(true);
1320 f2_.set_enable_encrypted_rtp_header_extensions(true);
1321
Yves Gerey665174f2018-06-19 15:03:05 +02001322 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1323 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1324 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1325 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001326
Steve Anton6fe1fba2018-12-11 10:15:23 -08001327 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001328 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001329 std::unique_ptr<SessionDescription> answer =
1330 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001331
Yves Gerey665174f2018-06-19 15:03:05 +02001332 EXPECT_EQ(
1333 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1334 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1335 EXPECT_EQ(
1336 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1337 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1338 EXPECT_EQ(
1339 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1340 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1341 EXPECT_EQ(
1342 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1343 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001344}
1345
1346TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001347 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001348 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001349 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001350
1351 f1_.set_enable_encrypted_rtp_header_extensions(true);
1352
Yves Gerey665174f2018-06-19 15:03:05 +02001353 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1354 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1355 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1356 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001357
Steve Anton6fe1fba2018-12-11 10:15:23 -08001358 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001359 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001360 std::unique_ptr<SessionDescription> answer =
1361 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001362
Yves Gerey665174f2018-06-19 15:03:05 +02001363 EXPECT_EQ(
1364 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1365 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1366 EXPECT_EQ(
1367 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1368 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1369 EXPECT_EQ(
1370 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1371 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1372 EXPECT_EQ(
1373 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1374 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001375}
1376
1377TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001378 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001379 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001380 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001381
1382 f2_.set_enable_encrypted_rtp_header_extensions(true);
1383
Yves Gerey665174f2018-06-19 15:03:05 +02001384 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1385 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1386 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1387 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001388
Steve Anton6fe1fba2018-12-11 10:15:23 -08001389 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001390 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001391 std::unique_ptr<SessionDescription> answer =
1392 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001393
Yves Gerey665174f2018-06-19 15:03:05 +02001394 EXPECT_EQ(
1395 MAKE_VECTOR(kAudioRtpExtension1),
1396 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1397 EXPECT_EQ(
1398 MAKE_VECTOR(kVideoRtpExtension1),
1399 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1400 EXPECT_EQ(
1401 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1402 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1403 EXPECT_EQ(
1404 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1405 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001406}
1407
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001408// Create an audio, video, data answer without legacy StreamParams.
1409TEST_F(MediaSessionDescriptionFactoryTest,
1410 TestCreateAnswerWithoutLegacyStreams) {
1411 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001412 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1413 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001414 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001415 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001416 std::unique_ptr<SessionDescription> answer =
1417 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001418 const ContentInfo* ac = answer->GetContentByName("audio");
1419 const ContentInfo* vc = answer->GetContentByName("video");
1420 const ContentInfo* dc = answer->GetContentByName("data");
1421 ASSERT_TRUE(ac != NULL);
1422 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001423 const AudioContentDescription* acd = ac->media_description()->as_audio();
1424 const VideoContentDescription* vcd = vc->media_description()->as_video();
1425 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001426
1427 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1428 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1429 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1430}
1431
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001432// Create a typical video answer, and ensure it matches what we expect.
1433TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1434 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001435 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1436 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1437 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001438
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001439 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001440 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1441 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1442 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001443
kwiberg31022942016-03-11 14:18:21 -08001444 std::unique_ptr<SessionDescription> offer;
1445 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001446
1447 offer_opts.rtcp_mux_enabled = true;
1448 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001449 offer = f1_.CreateOffer(offer_opts, NULL);
1450 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001451 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1452 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1453 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1454 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1455 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1456 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1457 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1458 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1459 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1460 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1461 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1462 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1463
1464 offer_opts.rtcp_mux_enabled = true;
1465 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001466 offer = f1_.CreateOffer(offer_opts, NULL);
1467 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001468 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1469 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1470 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1471 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1472 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1473 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1474 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1475 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1476 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1477 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1478 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1479 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1480
1481 offer_opts.rtcp_mux_enabled = false;
1482 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001483 offer = f1_.CreateOffer(offer_opts, NULL);
1484 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001485 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1486 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1487 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1488 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1489 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1490 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1491 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1492 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1493 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1494 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1495 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1496 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1497
1498 offer_opts.rtcp_mux_enabled = false;
1499 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001500 offer = f1_.CreateOffer(offer_opts, NULL);
1501 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001502 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1503 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1504 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1505 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1506 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1507 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1508 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1509 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1510 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1511 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1512 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1513 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1514}
1515
1516// Create an audio-only answer to a video offer.
1517TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1518 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001519 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1520 kActive, &opts);
1521 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1522 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001523 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001524 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001525
1526 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001527 std::unique_ptr<SessionDescription> answer =
1528 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001529 const ContentInfo* ac = answer->GetContentByName("audio");
1530 const ContentInfo* vc = answer->GetContentByName("video");
1531 ASSERT_TRUE(ac != NULL);
1532 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001533 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001534 EXPECT_TRUE(vc->rejected);
1535}
1536
1537// Create an audio-only answer to an offer with data.
1538TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001539 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001540 opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001541 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1542 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001543 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001544 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001545
1546 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001547 std::unique_ptr<SessionDescription> answer =
1548 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549 const ContentInfo* ac = answer->GetContentByName("audio");
1550 const ContentInfo* dc = answer->GetContentByName("data");
1551 ASSERT_TRUE(ac != NULL);
1552 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001553 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554 EXPECT_TRUE(dc->rejected);
1555}
1556
1557// Create an answer that rejects the contents which are rejected in the offer.
1558TEST_F(MediaSessionDescriptionFactoryTest,
1559 CreateAnswerToOfferWithRejectedMedia) {
1560 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001561 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1562 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001563 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001564 ASSERT_TRUE(offer.get() != NULL);
1565 ContentInfo* ac = offer->GetContentByName("audio");
1566 ContentInfo* vc = offer->GetContentByName("video");
1567 ContentInfo* dc = offer->GetContentByName("data");
1568 ASSERT_TRUE(ac != NULL);
1569 ASSERT_TRUE(vc != NULL);
1570 ASSERT_TRUE(dc != NULL);
1571 ac->rejected = true;
1572 vc->rejected = true;
1573 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001574 std::unique_ptr<SessionDescription> answer =
1575 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001576 ac = answer->GetContentByName("audio");
1577 vc = answer->GetContentByName("video");
1578 dc = answer->GetContentByName("data");
1579 ASSERT_TRUE(ac != NULL);
1580 ASSERT_TRUE(vc != NULL);
1581 ASSERT_TRUE(dc != NULL);
1582 EXPECT_TRUE(ac->rejected);
1583 EXPECT_TRUE(vc->rejected);
1584 EXPECT_TRUE(dc->rejected);
1585}
1586
Johannes Kron0854eb62018-10-10 22:33:20 +02001587TEST_F(MediaSessionDescriptionFactoryTest,
1588 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1589 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001590 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001591 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001592 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001593 ASSERT_TRUE(offer.get() != NULL);
1594 std::unique_ptr<SessionDescription> answer_no_support(
1595 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001596 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001597
1598 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001599 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001600 ASSERT_TRUE(offer.get() != NULL);
1601 std::unique_ptr<SessionDescription> answer_support(
1602 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001603 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001604}
1605
1606TEST_F(MediaSessionDescriptionFactoryTest,
1607 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1608 MediaSessionOptions opts;
1609 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001610 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001611 MediaContentDescription* video_offer =
1612 offer->GetContentDescriptionByName("video");
1613 ASSERT_TRUE(video_offer);
1614 MediaContentDescription* audio_offer =
1615 offer->GetContentDescriptionByName("audio");
1616 ASSERT_TRUE(audio_offer);
1617
1618 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001619 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1620 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001621
1622 ASSERT_TRUE(offer.get() != NULL);
1623 std::unique_ptr<SessionDescription> answer_no_support(
1624 f2_.CreateAnswer(offer.get(), opts, NULL));
1625 MediaContentDescription* video_answer =
1626 answer_no_support->GetContentDescriptionByName("video");
1627 MediaContentDescription* audio_answer =
1628 answer_no_support->GetContentDescriptionByName("audio");
1629 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001630 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001631 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001632 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001633
1634 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001635 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1636 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001637 ASSERT_TRUE(offer.get() != NULL);
1638 std::unique_ptr<SessionDescription> answer_support(
1639 f2_.CreateAnswer(offer.get(), opts, NULL));
1640 video_answer = answer_support->GetContentDescriptionByName("video");
1641 audio_answer = answer_support->GetContentDescriptionByName("audio");
1642 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001643 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001644 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001645 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001646}
1647
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001648// Create an audio and video offer with:
1649// - one video track
1650// - two audio tracks
1651// - two data tracks
1652// and ensure it matches what we expect. Also updates the initial offer by
1653// adding a new video track and replaces one of the audio tracks.
1654TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1655 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001656 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001657 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001658 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001659 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001660 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001661 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001662 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001663
Steve Anton4e70a722017-11-28 14:57:10 -08001664 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001665 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001666 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001667 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001668 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001669
1670 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001671 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001672
1673 ASSERT_TRUE(offer.get() != NULL);
1674 const ContentInfo* ac = offer->GetContentByName("audio");
1675 const ContentInfo* vc = offer->GetContentByName("video");
1676 const ContentInfo* dc = offer->GetContentByName("data");
1677 ASSERT_TRUE(ac != NULL);
1678 ASSERT_TRUE(vc != NULL);
1679 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001680 const AudioContentDescription* acd = ac->media_description()->as_audio();
1681 const VideoContentDescription* vcd = vc->media_description()->as_video();
1682 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001683 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001684 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001685
1686 const StreamParamsVec& audio_streams = acd->streams();
1687 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001688 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001689 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1690 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1691 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1692 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1693 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1694 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1695
1696 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1697 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001698 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001699
1700 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1701 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001702 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001703
1704 const StreamParamsVec& video_streams = vcd->streams();
1705 ASSERT_EQ(1U, video_streams.size());
1706 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1707 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1708 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1709 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1710
1711 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1712 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001713 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001714
1715 const StreamParamsVec& data_streams = dcd->streams();
1716 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001717 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001718 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1719 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1720 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1721 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1722 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1723 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1724
1725 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001726 dcd->bandwidth()); // default bandwidth (auto)
1727 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001728 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001729
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730 // Update the offer. Add a new video track that is not synched to the
1731 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001732 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001733 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001734 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1735 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001736 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001737 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1738 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001739 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001740 std::unique_ptr<SessionDescription> updated_offer(
1741 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001742
1743 ASSERT_TRUE(updated_offer.get() != NULL);
1744 ac = updated_offer->GetContentByName("audio");
1745 vc = updated_offer->GetContentByName("video");
1746 dc = updated_offer->GetContentByName("data");
1747 ASSERT_TRUE(ac != NULL);
1748 ASSERT_TRUE(vc != NULL);
1749 ASSERT_TRUE(dc != NULL);
1750 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001751 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001752 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001753 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001754 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001755 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001756
1757 EXPECT_EQ(acd->type(), updated_acd->type());
1758 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1759 EXPECT_EQ(vcd->type(), updated_vcd->type());
1760 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1761 EXPECT_EQ(dcd->type(), updated_dcd->type());
1762 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001763 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001764 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001765 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001766 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001767 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001768 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1769
1770 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1771 ASSERT_EQ(2U, updated_audio_streams.size());
1772 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1773 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1774 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1775 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1776 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1777
1778 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1779 ASSERT_EQ(2U, updated_video_streams.size());
1780 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1781 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001782 // All the media streams in one PeerConnection share one RTCP CNAME.
1783 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784
1785 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1786 ASSERT_EQ(2U, updated_data_streams.size());
1787 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1788 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1789 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1790 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1791 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001792 // The stream correctly got the CNAME from the MediaSessionOptions.
1793 // The Expected RTCP CNAME is the default one as we are using the default
1794 // MediaSessionOptions.
1795 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001796}
1797
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001798// Create an offer with simulcast video stream.
1799TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1800 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001801 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1802 kActive, &opts);
1803 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1804 kActive, &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001805 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001806 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001807 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001808 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001809
1810 ASSERT_TRUE(offer.get() != NULL);
1811 const ContentInfo* vc = offer->GetContentByName("video");
1812 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001813 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001814
1815 const StreamParamsVec& video_streams = vcd->streams();
1816 ASSERT_EQ(1U, video_streams.size());
1817 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1818 const SsrcGroup* sim_ssrc_group =
1819 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1820 ASSERT_TRUE(sim_ssrc_group != NULL);
1821 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1822}
1823
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001824// Create an audio and video answer to a standard video offer with:
1825// - one video track
1826// - two audio tracks
1827// - two data tracks
1828// and ensure it matches what we expect. Also updates the initial answer by
1829// adding a new video track and removes one of the audio tracks.
1830TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1831 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001832 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1833 kActive, &offer_opts);
1834 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1835 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001836 offer_opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001837 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1838 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001839 f1_.set_secure(SEC_ENABLED);
1840 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001841 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001842
zhihuang1c378ed2017-08-17 14:10:50 -07001843 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001844 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
1845 kActive, &answer_opts);
1846 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1847 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001848 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001849 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001850 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001851 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001852 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001853 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001854
Steve Anton4e70a722017-11-28 14:57:10 -08001855 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
1856 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001857 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001858 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001859 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001860 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001861 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001862
Steve Anton6fe1fba2018-12-11 10:15:23 -08001863 std::unique_ptr<SessionDescription> answer =
1864 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001865
1866 ASSERT_TRUE(answer.get() != NULL);
1867 const ContentInfo* ac = answer->GetContentByName("audio");
1868 const ContentInfo* vc = answer->GetContentByName("video");
1869 const ContentInfo* dc = answer->GetContentByName("data");
1870 ASSERT_TRUE(ac != NULL);
1871 ASSERT_TRUE(vc != NULL);
1872 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001873 const AudioContentDescription* acd = ac->media_description()->as_audio();
1874 const VideoContentDescription* vcd = vc->media_description()->as_video();
1875 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001876 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1877 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1878 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001879
1880 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001881 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001882
1883 const StreamParamsVec& audio_streams = acd->streams();
1884 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001885 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001886 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1887 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1888 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1889 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1890 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1891 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1892
1893 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1894 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1895
1896 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001897 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001898
1899 const StreamParamsVec& video_streams = vcd->streams();
1900 ASSERT_EQ(1U, video_streams.size());
1901 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1902 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1903 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1904 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1905
1906 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001907 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001908
1909 const StreamParamsVec& data_streams = dcd->streams();
1910 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001911 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001912 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1913 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1914 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1915 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1916 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1917 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1918
1919 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001920 dcd->bandwidth()); // default bandwidth (auto)
1921 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001922
1923 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001924 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001925 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001926 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001927 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1928 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001929 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001930 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001931
1932 ASSERT_TRUE(updated_answer.get() != NULL);
1933 ac = updated_answer->GetContentByName("audio");
1934 vc = updated_answer->GetContentByName("video");
1935 dc = updated_answer->GetContentByName("data");
1936 ASSERT_TRUE(ac != NULL);
1937 ASSERT_TRUE(vc != NULL);
1938 ASSERT_TRUE(dc != NULL);
1939 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001940 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001942 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001943 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001944 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001945
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001946 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001947 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001948 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001949 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001950 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1952
1953 EXPECT_EQ(acd->type(), updated_acd->type());
1954 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1955 EXPECT_EQ(vcd->type(), updated_vcd->type());
1956 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1957 EXPECT_EQ(dcd->type(), updated_dcd->type());
1958 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1959
1960 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1961 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001962 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001963
1964 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1965 ASSERT_EQ(2U, updated_video_streams.size());
1966 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1967 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001968 // All media streams in one PeerConnection share one CNAME.
1969 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001970
1971 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1972 ASSERT_EQ(1U, updated_data_streams.size());
1973 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1974}
1975
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976// Create an updated offer after creating an answer to the original offer and
1977// verify that the codecs that were part of the original answer are not changed
1978// in the updated offer.
1979TEST_F(MediaSessionDescriptionFactoryTest,
1980 RespondentCreatesOfferAfterCreatingAnswer) {
1981 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001982 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983
Steve Anton6fe1fba2018-12-11 10:15:23 -08001984 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1985 std::unique_ptr<SessionDescription> answer =
1986 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001987
1988 const AudioContentDescription* acd =
1989 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08001990 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001991
1992 const VideoContentDescription* vcd =
1993 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08001994 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001995
kwiberg31022942016-03-11 14:18:21 -08001996 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001997 f2_.CreateOffer(opts, answer.get()));
1998
1999 // The expected audio codecs are the common audio codecs from the first
2000 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2001 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002002 // TODO(wu): |updated_offer| should not include the codec
2003 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002004 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002005 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002006 };
2007
2008 // The expected video codecs are the common video codecs from the first
2009 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2010 // preference order.
2011 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002012 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002013 };
2014
2015 const AudioContentDescription* updated_acd =
2016 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002017 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002018
2019 const VideoContentDescription* updated_vcd =
2020 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002021 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002022}
2023
Steve Anton5c72e712018-12-10 14:25:30 -08002024// Test that a reoffer does not reuse audio codecs from a previous media section
2025// that is being recycled.
2026TEST_F(MediaSessionDescriptionFactoryTest,
2027 ReOfferDoesNotReUseRecycledAudioCodecs) {
2028 f1_.set_video_codecs({});
2029 f2_.set_video_codecs({});
2030
2031 MediaSessionOptions opts;
2032 AddMediaSection(MEDIA_TYPE_AUDIO, "a0", RtpTransceiverDirection::kSendRecv,
2033 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002034 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2035 std::unique_ptr<SessionDescription> answer =
2036 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002037
2038 // Recycle the media section by changing its mid.
2039 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002040 std::unique_ptr<SessionDescription> reoffer =
2041 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002042
2043 // Expect that the results of the first negotiation are ignored. If the m=
2044 // section was not recycled the payload types would match the initial offerer.
2045 const AudioContentDescription* acd =
2046 GetFirstAudioContentDescription(reoffer.get());
2047 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2048}
2049
2050// Test that a reoffer does not reuse video codecs from a previous media section
2051// that is being recycled.
2052TEST_F(MediaSessionDescriptionFactoryTest,
2053 ReOfferDoesNotReUseRecycledVideoCodecs) {
2054 f1_.set_audio_codecs({}, {});
2055 f2_.set_audio_codecs({}, {});
2056
2057 MediaSessionOptions opts;
2058 AddMediaSection(MEDIA_TYPE_VIDEO, "v0", RtpTransceiverDirection::kSendRecv,
2059 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002060 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2061 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002062
2063 // Recycle the media section by changing its mid.
2064 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002065 std::unique_ptr<SessionDescription> reoffer =
2066 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002067
2068 // Expect that the results of the first negotiation are ignored. If the m=
2069 // section was not recycled the payload types would match the initial offerer.
2070 const VideoContentDescription* vcd =
2071 GetFirstVideoContentDescription(reoffer.get());
2072 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2073}
2074
2075// Test that a reanswer does not reuse audio codecs from a previous media
2076// section that is being recycled.
2077TEST_F(MediaSessionDescriptionFactoryTest,
2078 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2079 f1_.set_video_codecs({});
2080 f2_.set_video_codecs({});
2081
2082 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2083 // second offer/answer is forward (|f1_| as offerer).
2084 MediaSessionOptions opts;
2085 AddMediaSection(MEDIA_TYPE_AUDIO, "a0", RtpTransceiverDirection::kSendRecv,
2086 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002087 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2088 std::unique_ptr<SessionDescription> answer =
2089 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002090
2091 // Recycle the media section by changing its mid.
2092 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002093 std::unique_ptr<SessionDescription> reoffer =
2094 f1_.CreateOffer(opts, answer.get());
2095 std::unique_ptr<SessionDescription> reanswer =
2096 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002097
2098 // Expect that the results of the first negotiation are ignored. If the m=
2099 // section was not recycled the payload types would match the initial offerer.
2100 const AudioContentDescription* acd =
2101 GetFirstAudioContentDescription(reanswer.get());
2102 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2103}
2104
2105// Test that a reanswer does not reuse video codecs from a previous media
2106// section that is being recycled.
2107TEST_F(MediaSessionDescriptionFactoryTest,
2108 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2109 f1_.set_audio_codecs({}, {});
2110 f2_.set_audio_codecs({}, {});
2111
2112 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2113 // second offer/answer is forward (|f1_| as offerer).
2114 MediaSessionOptions opts;
2115 AddMediaSection(MEDIA_TYPE_VIDEO, "v0", RtpTransceiverDirection::kSendRecv,
2116 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002117 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2118 std::unique_ptr<SessionDescription> answer =
2119 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002120
2121 // Recycle the media section by changing its mid.
2122 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002123 std::unique_ptr<SessionDescription> reoffer =
2124 f1_.CreateOffer(opts, answer.get());
2125 std::unique_ptr<SessionDescription> reanswer =
2126 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002127
2128 // Expect that the results of the first negotiation are ignored. If the m=
2129 // section was not recycled the payload types would match the initial offerer.
2130 const VideoContentDescription* vcd =
2131 GetFirstVideoContentDescription(reanswer.get());
2132 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2133}
2134
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002135// Create an updated offer after creating an answer to the original offer and
2136// verify that the codecs that were part of the original answer are not changed
2137// in the updated offer. In this test Rtx is enabled.
2138TEST_F(MediaSessionDescriptionFactoryTest,
2139 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2140 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002141 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2142 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002143 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002144 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002145 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002146 f1_.set_video_codecs(f1_codecs);
2147
2148 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002149 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002150 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151 f2_.set_video_codecs(f2_codecs);
2152
Steve Anton6fe1fba2018-12-11 10:15:23 -08002153 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002154 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002155 std::unique_ptr<SessionDescription> answer =
2156 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002157
2158 const VideoContentDescription* vcd =
2159 GetFirstVideoContentDescription(answer.get());
2160
2161 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002162 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2163 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164
2165 EXPECT_EQ(expected_codecs, vcd->codecs());
2166
deadbeef67cf2c12016-04-13 10:07:16 -07002167 // Now, make sure we get same result (except for the order) if |f2_| creates
2168 // an updated offer even though the default payload types between |f1_| and
2169 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002170 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171 f2_.CreateOffer(opts, answer.get()));
2172 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002173 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2175
2176 const VideoContentDescription* updated_vcd =
2177 GetFirstVideoContentDescription(updated_answer.get());
2178
2179 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2180}
2181
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002182// Regression test for:
2183// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2184// Existing codecs should always appear before new codecs in re-offers. But
2185// under a specific set of circumstances, the existing RTX codec was ending up
2186// added to the end of the list.
2187TEST_F(MediaSessionDescriptionFactoryTest,
2188 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2189 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002190 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2191 kActive, &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002192 // We specifically choose different preferred payload types for VP8 to
2193 // trigger the issue.
2194 cricket::VideoCodec vp8_offerer(100, "VP8");
2195 cricket::VideoCodec vp8_offerer_rtx =
2196 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2197 cricket::VideoCodec vp8_answerer(110, "VP8");
2198 cricket::VideoCodec vp8_answerer_rtx =
2199 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2200 cricket::VideoCodec vp9(120, "VP9");
2201 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2202
2203 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2204 // We also specifically cause the answerer to prefer VP9, such that if it
2205 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2206 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2207 vp8_answerer_rtx};
2208
2209 f1_.set_video_codecs(f1_codecs);
2210 f2_.set_video_codecs(f2_codecs);
2211 std::vector<AudioCodec> audio_codecs;
2212 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2213 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2214
2215 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002216 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002217 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002218 std::unique_ptr<SessionDescription> answer =
2219 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002220
2221 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2222 // But if the bug is triggered, RTX for VP8 ends up last.
2223 std::unique_ptr<SessionDescription> updated_offer(
2224 f2_.CreateOffer(opts, answer.get()));
2225
2226 const VideoContentDescription* vcd =
2227 GetFirstVideoContentDescription(updated_offer.get());
2228 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2229 ASSERT_EQ(4u, codecs.size());
2230 EXPECT_EQ(vp8_offerer, codecs[0]);
2231 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2232 EXPECT_EQ(vp9, codecs[2]);
2233 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002234}
2235
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002236// Create an updated offer that adds video after creating an audio only answer
2237// to the original offer. This test verifies that if a video codec and the RTX
2238// codec have the same default payload type as an audio codec that is already in
2239// use, the added codecs payload types are changed.
2240TEST_F(MediaSessionDescriptionFactoryTest,
2241 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2242 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002243 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002244 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002245 f1_.set_video_codecs(f1_codecs);
2246
2247 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002248 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2249 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002250
Steve Anton6fe1fba2018-12-11 10:15:23 -08002251 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2252 std::unique_ptr<SessionDescription> answer =
2253 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002254
2255 const AudioContentDescription* acd =
2256 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002257 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002258
2259 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2260 // reference be the same as an audio codec that was negotiated in the
2261 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002262 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002263 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002264
2265 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2266 int used_pl_type = acd->codecs()[0].id;
2267 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002268 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002269 f2_.set_video_codecs(f2_codecs);
2270
kwiberg31022942016-03-11 14:18:21 -08002271 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002272 f2_.CreateOffer(opts, answer.get()));
2273 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002274 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002275 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2276
2277 const AudioContentDescription* updated_acd =
2278 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002279 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002280
2281 const VideoContentDescription* updated_vcd =
2282 GetFirstVideoContentDescription(updated_answer.get());
2283
2284 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002285 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002286 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002287 EXPECT_NE(used_pl_type, new_h264_pl_type);
2288 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002289 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002290 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2291 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2292}
2293
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002294// Create an updated offer with RTX after creating an answer to an offer
2295// without RTX, and with different default payload types.
2296// Verify that the added RTX codec references the correct payload type.
2297TEST_F(MediaSessionDescriptionFactoryTest,
2298 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2299 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002300 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002301
2302 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2303 // This creates rtx for H264 with the payload type |f2_| uses.
2304 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2305 f2_.set_video_codecs(f2_codecs);
2306
Steve Anton6fe1fba2018-12-11 10:15:23 -08002307 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002308 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002309 std::unique_ptr<SessionDescription> answer =
2310 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002311
2312 const VideoContentDescription* vcd =
2313 GetFirstVideoContentDescription(answer.get());
2314
2315 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2316 EXPECT_EQ(expected_codecs, vcd->codecs());
2317
2318 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2319 // updated offer, even though the default payload types are different from
2320 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002321 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002322 f2_.CreateOffer(opts, answer.get()));
2323 ASSERT_TRUE(updated_offer);
2324
2325 const VideoContentDescription* updated_vcd =
2326 GetFirstVideoContentDescription(updated_offer.get());
2327
2328 // New offer should attempt to add H263, and RTX for H264.
2329 expected_codecs.push_back(kVideoCodecs2[1]);
2330 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2331 &expected_codecs);
2332 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2333}
2334
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002335// Test that RTX is ignored when there is no associated payload type parameter.
2336TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2337 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002338 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2339 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002341 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002342 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002343 f1_.set_video_codecs(f1_codecs);
2344
2345 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002346 // This creates RTX for H264 with the payload type |f2_| uses.
2347 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002348 f2_.set_video_codecs(f2_codecs);
2349
Steve Anton6fe1fba2018-12-11 10:15:23 -08002350 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002351 ASSERT_TRUE(offer.get() != NULL);
2352 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2353 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2354 // is possible to test that that RTX is dropped when
2355 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002356 MediaContentDescription* media_desc =
2357 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2358 ASSERT_TRUE(media_desc);
2359 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002361 for (VideoCodec& codec : codecs) {
2362 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2363 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002364 }
2365 }
2366 desc->set_codecs(codecs);
2367
Steve Anton6fe1fba2018-12-11 10:15:23 -08002368 std::unique_ptr<SessionDescription> answer =
2369 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002370
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002371 std::vector<std::string> codec_names =
2372 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2373 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2374 cricket::kRtxCodecName));
2375}
2376
2377// Test that RTX will be filtered out in the answer if its associated payload
2378// type doesn't match the local value.
2379TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2380 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002381 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2382 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002383 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2384 // This creates RTX for H264 in sender.
2385 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2386 f1_.set_video_codecs(f1_codecs);
2387
2388 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2389 // This creates RTX for H263 in receiver.
2390 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2391 f2_.set_video_codecs(f2_codecs);
2392
Steve Anton6fe1fba2018-12-11 10:15:23 -08002393 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002394 ASSERT_TRUE(offer.get() != NULL);
2395 // Associated payload type doesn't match, therefore, RTX codec is removed in
2396 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002397 std::unique_ptr<SessionDescription> answer =
2398 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002399
2400 std::vector<std::string> codec_names =
2401 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2402 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2403 cricket::kRtxCodecName));
2404}
2405
2406// Test that when multiple RTX codecs are offered, only the matched RTX codec
2407// is added in the answer, and the unsupported RTX codec is filtered out.
2408TEST_F(MediaSessionDescriptionFactoryTest,
2409 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2410 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002411 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2412 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002413 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2414 // This creates RTX for H264-SVC in sender.
2415 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2416 f1_.set_video_codecs(f1_codecs);
2417
2418 // This creates RTX for H264 in sender.
2419 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2420 f1_.set_video_codecs(f1_codecs);
2421
2422 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2423 // This creates RTX for H264 in receiver.
2424 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2425 f2_.set_video_codecs(f2_codecs);
2426
2427 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2428 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002429 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002430 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002431 std::unique_ptr<SessionDescription> answer =
2432 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002433 const VideoContentDescription* vcd =
2434 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002435 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2436 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2437 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002438
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002439 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002440}
2441
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002442// Test that after one RTX codec has been negotiated, a new offer can attempt
2443// to add another.
2444TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2445 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002446 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2447 kActive, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002448 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2449 // This creates RTX for H264 for the offerer.
2450 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2451 f1_.set_video_codecs(f1_codecs);
2452
Steve Anton6fe1fba2018-12-11 10:15:23 -08002453 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002454 ASSERT_TRUE(offer);
2455 const VideoContentDescription* vcd =
2456 GetFirstVideoContentDescription(offer.get());
2457
2458 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2459 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2460 &expected_codecs);
2461 EXPECT_EQ(expected_codecs, vcd->codecs());
2462
2463 // Now, attempt to add RTX for H264-SVC.
2464 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2465 f1_.set_video_codecs(f1_codecs);
2466
kwiberg31022942016-03-11 14:18:21 -08002467 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002468 f1_.CreateOffer(opts, offer.get()));
2469 ASSERT_TRUE(updated_offer);
2470 vcd = GetFirstVideoContentDescription(updated_offer.get());
2471
2472 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2473 &expected_codecs);
2474 EXPECT_EQ(expected_codecs, vcd->codecs());
2475}
2476
Noah Richards2e7a0982015-05-18 14:02:54 -07002477// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2478// generated for each simulcast ssrc and correctly grouped.
2479TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2480 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002481 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2482 kActive, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002483 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002484 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002485 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002486
2487 // Use a single real codec, and then add RTX for it.
2488 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002489 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002490 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2491 f1_.set_video_codecs(f1_codecs);
2492
2493 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2494 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002495 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002496 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002497 MediaContentDescription* media_desc =
2498 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2499 ASSERT_TRUE(media_desc);
2500 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002501 const StreamParamsVec& streams = desc->streams();
2502 // Single stream.
2503 ASSERT_EQ(1u, streams.size());
2504 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2505 EXPECT_EQ(6u, streams[0].ssrcs.size());
2506 // And should have a SIM group for the simulcast.
2507 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2508 // And a FID group for RTX.
2509 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002510 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002511 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2512 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002513 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002514 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2515 EXPECT_EQ(3u, fid_ssrcs.size());
2516}
2517
brandtr03d5fb12016-11-22 03:37:59 -08002518// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2519// together with a FEC-FR grouping.
2520TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2521 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002522 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2523 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002524 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002525 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002526 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002527
2528 // Use a single real codec, and then add FlexFEC for it.
2529 std::vector<VideoCodec> f1_codecs;
2530 f1_codecs.push_back(VideoCodec(97, "H264"));
2531 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2532 f1_.set_video_codecs(f1_codecs);
2533
2534 // Ensure that the offer has a single FlexFEC ssrc and that
2535 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002536 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002537 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002538 MediaContentDescription* media_desc =
2539 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2540 ASSERT_TRUE(media_desc);
2541 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002542 const StreamParamsVec& streams = desc->streams();
2543 // Single stream.
2544 ASSERT_EQ(1u, streams.size());
2545 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2546 EXPECT_EQ(2u, streams[0].ssrcs.size());
2547 // And should have a FEC-FR group for FlexFEC.
2548 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2549 std::vector<uint32_t> primary_ssrcs;
2550 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2551 ASSERT_EQ(1u, primary_ssrcs.size());
2552 uint32_t flexfec_ssrc;
2553 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2554 EXPECT_NE(flexfec_ssrc, 0u);
2555}
2556
2557// Test that FlexFEC is disabled for simulcast.
2558// TODO(brandtr): Remove this test when we support simulcast, either through
2559// multiple FlexfecSenders, or through multistream protection.
2560TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2561 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002562 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2563 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002564 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002565 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002566 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002567
2568 // Use a single real codec, and then add FlexFEC for it.
2569 std::vector<VideoCodec> f1_codecs;
2570 f1_codecs.push_back(VideoCodec(97, "H264"));
2571 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2572 f1_.set_video_codecs(f1_codecs);
2573
2574 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2575 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002576 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002577 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002578 MediaContentDescription* media_desc =
2579 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2580 ASSERT_TRUE(media_desc);
2581 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002582 const StreamParamsVec& streams = desc->streams();
2583 // Single stream.
2584 ASSERT_EQ(1u, streams.size());
2585 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2586 EXPECT_EQ(3u, streams[0].ssrcs.size());
2587 // And should have a SIM group for the simulcast.
2588 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2589 // And not a FEC-FR group for FlexFEC.
2590 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2591 std::vector<uint32_t> primary_ssrcs;
2592 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2593 EXPECT_EQ(3u, primary_ssrcs.size());
2594 for (uint32_t primary_ssrc : primary_ssrcs) {
2595 uint32_t flexfec_ssrc;
2596 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2597 }
2598}
2599
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002600// Create an updated offer after creating an answer to the original offer and
2601// verify that the RTP header extensions that were part of the original answer
2602// are not changed in the updated offer.
2603TEST_F(MediaSessionDescriptionFactoryTest,
2604 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2605 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002607
2608 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2609 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2610 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2611 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2612
Steve Anton6fe1fba2018-12-11 10:15:23 -08002613 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2614 std::unique_ptr<SessionDescription> answer =
2615 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002616
Yves Gerey665174f2018-06-19 15:03:05 +02002617 EXPECT_EQ(
2618 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2619 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2620 EXPECT_EQ(
2621 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2622 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002623
kwiberg31022942016-03-11 14:18:21 -08002624 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002625 f2_.CreateOffer(opts, answer.get()));
2626
2627 // The expected RTP header extensions in the new offer are the resulting
2628 // extensions from the first offer/answer exchange plus the extensions only
2629 // |f2_| offer.
2630 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002631 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002632 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2633 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2634 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002635 };
2636
2637 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002638 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002639 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2640 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2641 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642 };
2643
2644 const AudioContentDescription* updated_acd =
2645 GetFirstAudioContentDescription(updated_offer.get());
2646 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2647 updated_acd->rtp_header_extensions());
2648
2649 const VideoContentDescription* updated_vcd =
2650 GetFirstVideoContentDescription(updated_offer.get());
2651 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2652 updated_vcd->rtp_header_extensions());
2653}
2654
deadbeefa5b273a2015-08-20 17:30:13 -07002655// Verify that if the same RTP extension URI is used for audio and video, the
2656// same ID is used. Also verify that the ID isn't changed when creating an
2657// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002658TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002659 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002660 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002661
2662 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2663 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2664
Steve Anton6fe1fba2018-12-11 10:15:23 -08002665 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07002666
2667 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2668 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002669 const RtpExtension kExpectedVideoRtpExtension[] = {
2670 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002671 };
2672
Yves Gerey665174f2018-06-19 15:03:05 +02002673 EXPECT_EQ(
2674 MAKE_VECTOR(kAudioRtpExtension3),
2675 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2676 EXPECT_EQ(
2677 MAKE_VECTOR(kExpectedVideoRtpExtension),
2678 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002679
2680 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002681 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002682 f1_.CreateOffer(opts, offer.get()));
2683
2684 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02002685 GetFirstAudioContentDescription(updated_offer.get())
2686 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002687 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002688 GetFirstVideoContentDescription(updated_offer.get())
2689 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002690}
2691
jbauch5869f502017-06-29 12:31:36 -07002692// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2693TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2694 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002695 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002696
2697 f1_.set_enable_encrypted_rtp_header_extensions(true);
2698 f2_.set_enable_encrypted_rtp_header_extensions(true);
2699
2700 f1_.set_audio_rtp_header_extensions(
2701 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2702 f1_.set_video_rtp_header_extensions(
2703 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2704
Steve Anton6fe1fba2018-12-11 10:15:23 -08002705 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002706
2707 // The extensions that are shared between audio and video should use the same
2708 // id.
2709 const RtpExtension kExpectedVideoRtpExtension[] = {
2710 kVideoRtpExtension3ForEncryption[0],
2711 kAudioRtpExtension3ForEncryptionOffer[1],
2712 kAudioRtpExtension3ForEncryptionOffer[2],
2713 };
2714
Yves Gerey665174f2018-06-19 15:03:05 +02002715 EXPECT_EQ(
2716 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2717 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2718 EXPECT_EQ(
2719 MAKE_VECTOR(kExpectedVideoRtpExtension),
2720 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002721
2722 // Nothing should change when creating a new offer
2723 std::unique_ptr<SessionDescription> updated_offer(
2724 f1_.CreateOffer(opts, offer.get()));
2725
2726 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02002727 GetFirstAudioContentDescription(updated_offer.get())
2728 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002729 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002730 GetFirstVideoContentDescription(updated_offer.get())
2731 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002732}
2733
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002734TEST(MediaSessionDescription, CopySessionDescription) {
2735 SessionDescription source;
2736 cricket::ContentGroup group(cricket::CN_AUDIO);
2737 source.AddGroup(group);
2738 AudioContentDescription* acd(new AudioContentDescription());
2739 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2740 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08002741 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002742 VideoContentDescription* vcd(new VideoContentDescription());
2743 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2744 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08002745 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002746
kwiberg31022942016-03-11 14:18:21 -08002747 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002748 ASSERT_TRUE(copy.get() != NULL);
2749 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2750 const ContentInfo* ac = copy->GetContentByName("audio");
2751 const ContentInfo* vc = copy->GetContentByName("video");
2752 ASSERT_TRUE(ac != NULL);
2753 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08002754 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002755 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002756 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2757 EXPECT_EQ(1u, acd->first_ssrc());
2758
Steve Anton5adfafd2017-12-20 16:34:00 -08002759 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002760 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002761 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2762 EXPECT_EQ(2u, vcd->first_ssrc());
2763}
2764
2765// The below TestTransportInfoXXX tests create different offers/answers, and
2766// ensure the TransportInfo in the SessionDescription matches what we expect.
2767TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2768 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002769 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2770 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002771 TestTransportInfo(true, options, false);
2772}
2773
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002774TEST_F(MediaSessionDescriptionFactoryTest,
2775 TestTransportInfoOfferIceRenomination) {
2776 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002777 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2778 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002779 options.media_description_options[0]
2780 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002781 TestTransportInfo(true, options, false);
2782}
2783
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002784TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2785 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002786 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2787 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002788 TestTransportInfo(true, options, true);
2789}
2790
2791TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2792 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002793 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2794 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2795 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002796 TestTransportInfo(true, options, false);
2797}
2798
2799TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002800 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002801 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002802 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2803 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2804 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805 TestTransportInfo(true, options, true);
2806}
2807
2808TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2809 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002810 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2811 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2812 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002813 options.bundle_enabled = true;
2814 TestTransportInfo(true, options, false);
2815}
2816
2817TEST_F(MediaSessionDescriptionFactoryTest,
2818 TestTransportInfoOfferBundleCurrent) {
2819 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002820 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2821 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2822 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002823 options.bundle_enabled = true;
2824 TestTransportInfo(true, options, true);
2825}
2826
2827TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2828 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002829 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2830 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002831 TestTransportInfo(false, options, false);
2832}
2833
2834TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002835 TestTransportInfoAnswerIceRenomination) {
2836 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002837 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2838 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002839 options.media_description_options[0]
2840 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002841 TestTransportInfo(false, options, false);
2842}
2843
2844TEST_F(MediaSessionDescriptionFactoryTest,
2845 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002846 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002847 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2848 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002849 TestTransportInfo(false, options, true);
2850}
2851
2852TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2853 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002854 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2855 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2856 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002857 TestTransportInfo(false, options, false);
2858}
2859
2860TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002861 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002862 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002863 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2864 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2865 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002866 TestTransportInfo(false, options, true);
2867}
2868
2869TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2870 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002871 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2872 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2873 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874 options.bundle_enabled = true;
2875 TestTransportInfo(false, options, false);
2876}
2877
2878TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002879 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002880 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002881 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2882 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2883 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002884 options.bundle_enabled = true;
2885 TestTransportInfo(false, options, true);
2886}
2887
2888// Create an offer with bundle enabled and verify the crypto parameters are
2889// the common set of the available cryptos.
2890TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2891 TestCryptoWithBundle(true);
2892}
2893
2894// Create an answer with bundle enabled and verify the crypto parameters are
2895// the common set of the available cryptos.
2896TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2897 TestCryptoWithBundle(false);
2898}
2899
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002900// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2901// DTLS is not enabled locally.
2902TEST_F(MediaSessionDescriptionFactoryTest,
2903 TestOfferDtlsSavpfWithoutDtlsFailed) {
2904 f1_.set_secure(SEC_ENABLED);
2905 f2_.set_secure(SEC_ENABLED);
2906 tdf1_.set_secure(SEC_DISABLED);
2907 tdf2_.set_secure(SEC_DISABLED);
2908
Steve Anton6fe1fba2018-12-11 10:15:23 -08002909 std::unique_ptr<SessionDescription> offer =
2910 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002911 ASSERT_TRUE(offer.get() != NULL);
2912 ContentInfo* offer_content = offer->GetContentByName("audio");
2913 ASSERT_TRUE(offer_content != NULL);
2914 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002915 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002916 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2917
Steve Anton6fe1fba2018-12-11 10:15:23 -08002918 std::unique_ptr<SessionDescription> answer =
2919 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002920 ASSERT_TRUE(answer != NULL);
2921 ContentInfo* answer_content = answer->GetContentByName("audio");
2922 ASSERT_TRUE(answer_content != NULL);
2923
2924 ASSERT_TRUE(answer_content->rejected);
2925}
2926
2927// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2928// UDP/TLS/RTP/SAVPF.
2929TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2930 f1_.set_secure(SEC_ENABLED);
2931 f2_.set_secure(SEC_ENABLED);
2932 tdf1_.set_secure(SEC_ENABLED);
2933 tdf2_.set_secure(SEC_ENABLED);
2934
Steve Anton6fe1fba2018-12-11 10:15:23 -08002935 std::unique_ptr<SessionDescription> offer =
2936 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002937 ASSERT_TRUE(offer.get() != NULL);
2938 ContentInfo* offer_content = offer->GetContentByName("audio");
2939 ASSERT_TRUE(offer_content != NULL);
2940 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002941 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002942 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2943
Steve Anton6fe1fba2018-12-11 10:15:23 -08002944 std::unique_ptr<SessionDescription> answer =
2945 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002946 ASSERT_TRUE(answer != NULL);
2947
2948 const ContentInfo* answer_content = answer->GetContentByName("audio");
2949 ASSERT_TRUE(answer_content != NULL);
2950 ASSERT_FALSE(answer_content->rejected);
2951
2952 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002953 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08002954 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002955}
2956
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002957// Test that we include both SDES and DTLS in the offer, but only include SDES
2958// in the answer if DTLS isn't negotiated.
2959TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2960 f1_.set_secure(SEC_ENABLED);
2961 f2_.set_secure(SEC_ENABLED);
2962 tdf1_.set_secure(SEC_ENABLED);
2963 tdf2_.set_secure(SEC_DISABLED);
2964 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002965 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002966 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002967 const cricket::MediaContentDescription* audio_media_desc;
2968 const cricket::MediaContentDescription* video_media_desc;
2969 const cricket::TransportDescription* audio_trans_desc;
2970 const cricket::TransportDescription* video_trans_desc;
2971
2972 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002973 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974 ASSERT_TRUE(offer.get() != NULL);
2975
Steve Antonb1c1de12017-12-21 15:14:30 -08002976 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002977 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002978 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002979 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002980 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002981 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2982
2983 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2984 ASSERT_TRUE(audio_trans_desc != NULL);
2985 video_trans_desc = offer->GetTransportDescriptionByName("video");
2986 ASSERT_TRUE(video_trans_desc != NULL);
2987 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2988 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2989
2990 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002991 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002992 ASSERT_TRUE(answer.get() != NULL);
2993
Steve Antonb1c1de12017-12-21 15:14:30 -08002994 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002995 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002996 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002997 ASSERT_TRUE(video_media_desc != NULL);
2998 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2999 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3000
3001 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3002 ASSERT_TRUE(audio_trans_desc != NULL);
3003 video_trans_desc = answer->GetTransportDescriptionByName("video");
3004 ASSERT_TRUE(video_trans_desc != NULL);
3005 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3006 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3007
3008 // Enable DTLS; the answer should now only have DTLS support.
3009 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003010 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003011 ASSERT_TRUE(answer.get() != NULL);
3012
Steve Antonb1c1de12017-12-21 15:14:30 -08003013 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003014 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003015 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003016 ASSERT_TRUE(video_media_desc != NULL);
3017 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3018 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003019 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3020 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003021
3022 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3023 ASSERT_TRUE(audio_trans_desc != NULL);
3024 video_trans_desc = answer->GetTransportDescriptionByName("video");
3025 ASSERT_TRUE(video_trans_desc != NULL);
3026 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3027 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003028
3029 // Try creating offer again. DTLS enabled now, crypto's should be empty
3030 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003031 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003032 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003033 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003034 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003035 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003036 ASSERT_TRUE(video_media_desc != NULL);
3037 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3038 EXPECT_TRUE(video_media_desc->cryptos().empty());
3039
3040 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3041 ASSERT_TRUE(audio_trans_desc != NULL);
3042 video_trans_desc = offer->GetTransportDescriptionByName("video");
3043 ASSERT_TRUE(video_trans_desc != NULL);
3044 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3045 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003046}
3047
3048// Test that an answer can't be created if cryptos are required but the offer is
3049// unsecure.
3050TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003051 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003052 f1_.set_secure(SEC_DISABLED);
3053 tdf1_.set_secure(SEC_DISABLED);
3054 f2_.set_secure(SEC_REQUIRED);
3055 tdf1_.set_secure(SEC_ENABLED);
3056
Steve Anton6fe1fba2018-12-11 10:15:23 -08003057 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003058 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003059 std::unique_ptr<SessionDescription> answer =
3060 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003061 EXPECT_TRUE(answer.get() == NULL);
3062}
3063
3064// Test that we accept a DTLS offer without SDES and create an appropriate
3065// answer.
3066TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3067 f1_.set_secure(SEC_DISABLED);
3068 f2_.set_secure(SEC_ENABLED);
3069 tdf1_.set_secure(SEC_ENABLED);
3070 tdf2_.set_secure(SEC_ENABLED);
3071 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003072 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3073 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3074 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003075
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003076 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003077 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003078 ASSERT_TRUE(offer.get() != NULL);
3079
3080 const AudioContentDescription* audio_offer =
3081 GetFirstAudioContentDescription(offer.get());
3082 ASSERT_TRUE(audio_offer->cryptos().empty());
3083 const VideoContentDescription* video_offer =
3084 GetFirstVideoContentDescription(offer.get());
3085 ASSERT_TRUE(video_offer->cryptos().empty());
3086 const DataContentDescription* data_offer =
3087 GetFirstDataContentDescription(offer.get());
3088 ASSERT_TRUE(data_offer->cryptos().empty());
3089
3090 const cricket::TransportDescription* audio_offer_trans_desc =
3091 offer->GetTransportDescriptionByName("audio");
3092 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3093 const cricket::TransportDescription* video_offer_trans_desc =
3094 offer->GetTransportDescriptionByName("video");
3095 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3096 const cricket::TransportDescription* data_offer_trans_desc =
3097 offer->GetTransportDescriptionByName("data");
3098 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3099
3100 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003101 std::unique_ptr<SessionDescription> answer =
3102 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003103 ASSERT_TRUE(answer.get() != NULL);
3104
3105 const cricket::TransportDescription* audio_answer_trans_desc =
3106 answer->GetTransportDescriptionByName("audio");
3107 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3108 const cricket::TransportDescription* video_answer_trans_desc =
3109 answer->GetTransportDescriptionByName("video");
3110 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3111 const cricket::TransportDescription* data_answer_trans_desc =
3112 answer->GetTransportDescriptionByName("data");
3113 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3114}
3115
3116// Verifies if vad_enabled option is set to false, CN codecs are not present in
3117// offer or answer.
3118TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3119 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003120 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003121 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003122 ASSERT_TRUE(offer.get() != NULL);
3123 const ContentInfo* audio_content = offer->GetContentByName("audio");
3124 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3125
3126 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003127 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003128 ASSERT_TRUE(offer.get() != NULL);
3129 audio_content = offer->GetContentByName("audio");
3130 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003131 std::unique_ptr<SessionDescription> answer =
3132 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003133 ASSERT_TRUE(answer.get() != NULL);
3134 audio_content = answer->GetContentByName("audio");
3135 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3136}
deadbeef44f08192015-12-15 16:20:09 -08003137
zhihuang1c378ed2017-08-17 14:10:50 -07003138// Test that the generated MIDs match the existing offer.
3139TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003140 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003141 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
3142 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
3143 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
3144 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08003145 opts.data_channel_type = cricket::DCT_SCTP;
Steve Anton4e70a722017-11-28 14:57:10 -08003146 AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
3147 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003148 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003149 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003150 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003151 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003152
deadbeef44f08192015-12-15 16:20:09 -08003153 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3154 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3155 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3156 ASSERT_TRUE(audio_content != nullptr);
3157 ASSERT_TRUE(video_content != nullptr);
3158 ASSERT_TRUE(data_content != nullptr);
3159 EXPECT_EQ("audio_modified", audio_content->name);
3160 EXPECT_EQ("video_modified", video_content->name);
3161 EXPECT_EQ("data_modified", data_content->name);
3162}
zhihuangcf5b37c2016-05-05 11:44:35 -07003163
zhihuang1c378ed2017-08-17 14:10:50 -07003164// The following tests verify that the unified plan SDP is supported.
3165// Test that we can create an offer with multiple media sections of same media
3166// type.
3167TEST_F(MediaSessionDescriptionFactoryTest,
3168 CreateOfferWithMultipleAVMediaSections) {
3169 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003170 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3171 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003172 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003173 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003174
Steve Anton4e70a722017-11-28 14:57:10 -08003175 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3176 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003177 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003178 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003179
Steve Anton4e70a722017-11-28 14:57:10 -08003180 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3181 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003182 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003183 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003184
Steve Anton4e70a722017-11-28 14:57:10 -08003185 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3186 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003187 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003188 {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003189 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003190 ASSERT_TRUE(offer);
3191
3192 ASSERT_EQ(4u, offer->contents().size());
3193 EXPECT_FALSE(offer->contents()[0].rejected);
3194 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003195 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003196 ASSERT_EQ(1u, acd->streams().size());
3197 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003198 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003199
3200 EXPECT_FALSE(offer->contents()[1].rejected);
3201 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003202 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003203 ASSERT_EQ(1u, vcd->streams().size());
3204 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003205 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003206
3207 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003208 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003209 ASSERT_EQ(1u, acd->streams().size());
3210 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003211 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003212
3213 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003214 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003215 ASSERT_EQ(1u, vcd->streams().size());
3216 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003217 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003218}
3219
3220// Test that we can create an answer with multiple media sections of same media
3221// type.
3222TEST_F(MediaSessionDescriptionFactoryTest,
3223 CreateAnswerWithMultipleAVMediaSections) {
3224 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003225 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3226 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003227 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003228 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003229
Steve Anton4e70a722017-11-28 14:57:10 -08003230 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3231 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003232 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003233 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003234
Steve Anton4e70a722017-11-28 14:57:10 -08003235 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3236 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003237 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003238 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003239
Steve Anton4e70a722017-11-28 14:57:10 -08003240 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3241 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003242 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003243 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003244
Steve Anton6fe1fba2018-12-11 10:15:23 -08003245 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003246 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003247 std::unique_ptr<SessionDescription> answer =
3248 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003249
3250 ASSERT_EQ(4u, answer->contents().size());
3251 EXPECT_FALSE(answer->contents()[0].rejected);
3252 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003253 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003254 ASSERT_EQ(1u, acd->streams().size());
3255 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003256 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003257
3258 EXPECT_FALSE(answer->contents()[1].rejected);
3259 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003260 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003261 ASSERT_EQ(1u, vcd->streams().size());
3262 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003263 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003264
3265 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003266 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003267 ASSERT_EQ(1u, acd->streams().size());
3268 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003269 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003270
3271 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003272 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003273 ASSERT_EQ(1u, vcd->streams().size());
3274 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003275 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003276}
3277
3278// Test that the media section will be rejected in offer if the corresponding
3279// MediaDescriptionOptions is stopped by the offerer.
3280TEST_F(MediaSessionDescriptionFactoryTest,
3281 CreateOfferWithMediaSectionStoppedByOfferer) {
3282 // Create an offer with two audio sections and one of them is stopped.
3283 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003284 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3285 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3286 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3287 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003288 std::unique_ptr<SessionDescription> offer =
3289 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003290 ASSERT_TRUE(offer);
3291 ASSERT_EQ(2u, offer->contents().size());
3292 EXPECT_FALSE(offer->contents()[0].rejected);
3293 EXPECT_TRUE(offer->contents()[1].rejected);
3294}
3295
3296// Test that the media section will be rejected in answer if the corresponding
3297// MediaDescriptionOptions is stopped by the offerer.
3298TEST_F(MediaSessionDescriptionFactoryTest,
3299 CreateAnswerWithMediaSectionStoppedByOfferer) {
3300 // Create an offer with two audio sections and one of them is stopped.
3301 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003302 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3303 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3304 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3305 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003306 std::unique_ptr<SessionDescription> offer =
3307 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003308 ASSERT_TRUE(offer);
3309 ASSERT_EQ(2u, offer->contents().size());
3310 EXPECT_FALSE(offer->contents()[0].rejected);
3311 EXPECT_TRUE(offer->contents()[1].rejected);
3312
3313 // Create an answer based on the offer.
3314 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003315 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3316 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3317 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3318 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003319 std::unique_ptr<SessionDescription> answer =
3320 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003321 ASSERT_EQ(2u, answer->contents().size());
3322 EXPECT_FALSE(answer->contents()[0].rejected);
3323 EXPECT_TRUE(answer->contents()[1].rejected);
3324}
3325
3326// Test that the media section will be rejected in answer if the corresponding
3327// MediaDescriptionOptions is stopped by the answerer.
3328TEST_F(MediaSessionDescriptionFactoryTest,
3329 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3330 // Create an offer with two audio sections.
3331 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003332 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3333 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3334 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3335 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003336 std::unique_ptr<SessionDescription> offer =
3337 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003338 ASSERT_TRUE(offer);
3339 ASSERT_EQ(2u, offer->contents().size());
3340 ASSERT_FALSE(offer->contents()[0].rejected);
3341 ASSERT_FALSE(offer->contents()[1].rejected);
3342
3343 // The answerer rejects one of the audio sections.
3344 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003345 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3346 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3347 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3348 RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003349 std::unique_ptr<SessionDescription> answer =
3350 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003351 ASSERT_EQ(2u, answer->contents().size());
3352 EXPECT_FALSE(answer->contents()[0].rejected);
3353 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003354
3355 // The TransportInfo of the rejected m= section is expected to be added in the
3356 // answer.
3357 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003358}
3359
3360// Test the generated media sections has the same order of the
3361// corresponding MediaDescriptionOptions.
3362TEST_F(MediaSessionDescriptionFactoryTest,
3363 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3364 MediaSessionOptions opts;
3365 // This tests put video section first because normally audio comes first by
3366 // default.
Steve Anton4e70a722017-11-28 14:57:10 -08003367 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3368 kActive, &opts);
3369 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3370 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003371 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003372
3373 ASSERT_TRUE(offer);
3374 ASSERT_EQ(2u, offer->contents().size());
3375 EXPECT_EQ("video", offer->contents()[0].name);
3376 EXPECT_EQ("audio", offer->contents()[1].name);
3377}
3378
3379// Test that different media sections using the same codec have same payload
3380// type.
3381TEST_F(MediaSessionDescriptionFactoryTest,
3382 PayloadTypesSharedByMediaSectionsOfSameType) {
3383 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003384 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3385 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3386 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3387 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003388 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003389 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003390 ASSERT_TRUE(offer);
3391 ASSERT_EQ(2u, offer->contents().size());
3392 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003393 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003394 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003395 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003396 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3397 ASSERT_EQ(2u, vcd1->codecs().size());
3398 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3399 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3400 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3401 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3402
3403 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003404 std::unique_ptr<SessionDescription> answer =
3405 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003406 ASSERT_TRUE(answer);
3407 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003408 vcd1 = answer->contents()[0].media_description()->as_video();
3409 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003410 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3411 ASSERT_EQ(1u, vcd1->codecs().size());
3412 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3413 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3414}
3415
3416// Test that the codec preference order per media section is respected in
3417// subsequent offer.
3418TEST_F(MediaSessionDescriptionFactoryTest,
3419 CreateOfferRespectsCodecPreferenceOrder) {
3420 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003421 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3422 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3423 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3424 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003425 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003426 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003427 ASSERT_TRUE(offer);
3428 ASSERT_EQ(2u, offer->contents().size());
3429 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003430 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003431 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003432 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003433 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3434 EXPECT_EQ(video_codecs, vcd1->codecs());
3435 EXPECT_EQ(video_codecs, vcd2->codecs());
3436
3437 // Change the codec preference of the first video section and create a
3438 // follow-up offer.
3439 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3440 vcd1->set_codecs(video_codecs_reverse);
3441 std::unique_ptr<SessionDescription> updated_offer(
3442 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003443 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3444 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003445 // The video codec preference order should be respected.
3446 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3447 EXPECT_EQ(video_codecs, vcd2->codecs());
3448}
3449
3450// Test that the codec preference order per media section is respected in
3451// the answer.
3452TEST_F(MediaSessionDescriptionFactoryTest,
3453 CreateAnswerRespectsCodecPreferenceOrder) {
3454 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003455 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3456 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3457 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3458 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003459 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003460 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003461 ASSERT_TRUE(offer);
3462 ASSERT_EQ(2u, offer->contents().size());
3463 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003464 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003465 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003466 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003467 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3468 EXPECT_EQ(video_codecs, vcd1->codecs());
3469 EXPECT_EQ(video_codecs, vcd2->codecs());
3470
3471 // Change the codec preference of the first video section and create an
3472 // answer.
3473 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3474 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003475 std::unique_ptr<SessionDescription> answer =
3476 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003477 vcd1 = answer->contents()[0].media_description()->as_video();
3478 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003479 // The video codec preference order should be respected.
3480 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3481 EXPECT_EQ(video_codecs, vcd2->codecs());
3482}
3483
Zhi Huang6f367472017-11-22 13:20:02 -08003484// Test that when creating an answer, the codecs use local parameters instead of
3485// the remote ones.
3486TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3487 const std::string audio_param_name = "audio_param";
3488 const std::string audio_value1 = "audio_v1";
3489 const std::string audio_value2 = "audio_v2";
3490 const std::string video_param_name = "video_param";
3491 const std::string video_value1 = "video_v1";
3492 const std::string video_value2 = "video_v2";
3493
3494 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3495 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3496 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3497 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3498
3499 // Set the parameters for codecs.
3500 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3501 video_codecs1[0].SetParam(video_param_name, video_value1);
3502 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3503 video_codecs2[0].SetParam(video_param_name, video_value2);
3504
3505 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3506 f1_.set_video_codecs(video_codecs1);
3507 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3508 f2_.set_video_codecs(video_codecs2);
3509
3510 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003511 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3512 kActive, &opts);
3513 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3514 kActive, &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003515
Steve Anton6fe1fba2018-12-11 10:15:23 -08003516 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003517 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003518 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3519 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003520 std::string value;
3521 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3522 EXPECT_EQ(audio_value1, value);
3523 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3524 EXPECT_EQ(video_value1, value);
3525
Steve Anton6fe1fba2018-12-11 10:15:23 -08003526 std::unique_ptr<SessionDescription> answer =
3527 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003528 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003529 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3530 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003531 // Use the parameters from the local codecs.
3532 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3533 EXPECT_EQ(audio_value2, value);
3534 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3535 EXPECT_EQ(video_value2, value);
3536}
3537
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003538// Test that matching packetization-mode is part of the criteria for matching
3539// H264 codecs (in addition to profile-level-id). Previously, this was not the
3540// case, so the first H264 codec with the same profile-level-id would match and
3541// the payload type in the answer would be incorrect.
3542// This is a regression test for bugs.webrtc.org/8808
3543TEST_F(MediaSessionDescriptionFactoryTest,
3544 H264MatchCriteriaIncludesPacketizationMode) {
3545 // Create two H264 codecs with the same profile level ID and different
3546 // packetization modes.
3547 VideoCodec h264_pm0(96, "H264");
3548 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3549 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3550 VideoCodec h264_pm1(97, "H264");
3551 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3552 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3553
3554 // Offerer will send both codecs, answerer should choose the one with matching
3555 // packetization mode (and not the first one it sees).
3556 f1_.set_video_codecs({h264_pm0, h264_pm1});
3557 f2_.set_video_codecs({h264_pm1});
3558
3559 MediaSessionOptions opts;
3560 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3561 kActive, &opts);
3562
Steve Anton6fe1fba2018-12-11 10:15:23 -08003563 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003564 ASSERT_TRUE(offer);
3565
Steve Anton6fe1fba2018-12-11 10:15:23 -08003566 std::unique_ptr<SessionDescription> answer =
3567 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003568 ASSERT_TRUE(answer);
3569
3570 // Answer should have one negotiated codec with packetization-mode=1 using the
3571 // offered payload type.
3572 ASSERT_EQ(1u, answer->contents().size());
3573 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3574 ASSERT_EQ(1u, answer_vcd->codecs().size());
3575 auto answer_codec = answer_vcd->codecs()[0];
3576 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3577}
3578
zhihuangcf5b37c2016-05-05 11:44:35 -07003579class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3580 public:
3581 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003582 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3583 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003584 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3585 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003586 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3587 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003588 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3589 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3590 f1_.set_secure(SEC_ENABLED);
3591 f2_.set_secure(SEC_ENABLED);
3592 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003593 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003594 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003595 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003596 tdf1_.set_secure(SEC_ENABLED);
3597 tdf2_.set_secure(SEC_ENABLED);
3598 }
3599
3600 protected:
3601 MediaSessionDescriptionFactory f1_;
3602 MediaSessionDescriptionFactory f2_;
3603 TransportDescriptionFactory tdf1_;
3604 TransportDescriptionFactory tdf2_;
3605};
3606
3607TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3608 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003609 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003610 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07003611 ASSERT_TRUE(offer.get() != nullptr);
3612 // Set the protocol for all the contents.
3613 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003614 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07003615 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08003616 std::unique_ptr<SessionDescription> answer =
3617 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07003618 const ContentInfo* ac = answer->GetContentByName("audio");
3619 const ContentInfo* vc = answer->GetContentByName("video");
3620 ASSERT_TRUE(ac != nullptr);
3621 ASSERT_TRUE(vc != nullptr);
3622 EXPECT_FALSE(ac->rejected); // the offer is accepted
3623 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003624 const AudioContentDescription* acd = ac->media_description()->as_audio();
3625 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07003626 EXPECT_EQ(GetParam(), acd->protocol());
3627 EXPECT_EQ(GetParam(), vcd->protocol());
3628}
3629
3630INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3631 MediaProtocolTest,
3632 ::testing::ValuesIn(kMediaProtocols));
3633INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3634 MediaProtocolTest,
3635 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003636
3637TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3638 TransportDescriptionFactory tdf;
3639 MediaSessionDescriptionFactory sf(&tdf);
3640 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3641 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3642
3643 // The merged list of codecs should contain any send codecs that are also
3644 // nominally in the recieve codecs list. Payload types should be picked from
3645 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3646 // (set to 1). This equals what happens when the send codecs are used in an
3647 // offer and the receive codecs are used in the following answer.
3648 const std::vector<AudioCodec> sendrecv_codecs =
3649 MAKE_VECTOR(kAudioCodecsAnswer);
3650 const std::vector<AudioCodec> no_codecs;
3651
3652 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3653 << "Please don't change shared test data!";
3654 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3655 << "Please don't change shared test data!";
3656 // Alter iLBC send codec to have zero channels, to test that that is handled
3657 // properly.
3658 send_codecs[1].channels = 0;
3659
3660 // Alther iLBC receive codec to be lowercase, to test that case conversions
3661 // are handled properly.
3662 recv_codecs[2].name = "ilbc";
3663
3664 // Test proper merge
3665 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003666 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3667 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3668 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003669
3670 // Test empty send codecs list
3671 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003672 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3673 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3674 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003675
3676 // Test empty recv codecs list
3677 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003678 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3679 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3680 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003681
3682 // Test all empty codec lists
3683 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003684 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3685 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3686 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003687}
3688
3689namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003690// Compare the two vectors of codecs ignoring the payload type.
3691template <class Codec>
3692bool CodecsMatch(const std::vector<Codec>& codecs1,
3693 const std::vector<Codec>& codecs2) {
3694 if (codecs1.size() != codecs2.size()) {
3695 return false;
3696 }
3697
3698 for (size_t i = 0; i < codecs1.size(); ++i) {
3699 if (!codecs1[i].Matches(codecs2[i])) {
3700 return false;
3701 }
3702 }
3703 return true;
3704}
3705
Steve Anton4e70a722017-11-28 14:57:10 -08003706void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07003707 TransportDescriptionFactory tdf;
3708 MediaSessionDescriptionFactory sf(&tdf);
3709 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3710 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3711 const std::vector<AudioCodec> sendrecv_codecs =
3712 MAKE_VECTOR(kAudioCodecsAnswer);
3713 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003714
3715 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003716 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3717
Steve Anton4e70a722017-11-28 14:57:10 -08003718 if (direction == RtpTransceiverDirection::kSendRecv ||
3719 direction == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003720 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003721 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003722 }
ossu075af922016-06-14 03:29:38 -07003723
Steve Anton6fe1fba2018-12-11 10:15:23 -08003724 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07003725 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003726 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07003727
3728 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003729 // that the codecs put in are right. This happens when we neither want to
3730 // send nor receive audio. The checks are still in place if at some point
3731 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003732 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003733 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003734 // sendrecv and inactive should both present lists as if the channel was
3735 // to be used for sending and receiving. Inactive essentially means it
3736 // might eventually be used anything, but we don't know more at this
3737 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08003738 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003739 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08003740 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003741 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003742 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003743 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003744 }
3745 }
3746}
3747
3748static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003749 AudioCodec(0, "codec0", 16000, -1, 1),
3750 AudioCodec(1, "codec1", 8000, 13300, 1),
3751 AudioCodec(2, "codec2", 8000, 64000, 1),
3752 AudioCodec(3, "codec3", 8000, 64000, 1),
3753 AudioCodec(4, "codec4", 8000, 0, 2),
3754 AudioCodec(5, "codec5", 32000, 0, 1),
3755 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003756
zhihuang1c378ed2017-08-17 14:10:50 -07003757/* The codecs groups below are chosen as per the matrix below. The objective
3758 * is to have different sets of codecs in the inputs, to get unique sets of
3759 * codecs after negotiation, depending on offer and answer communication
3760 * directions. One-way directions in the offer should either result in the
3761 * opposite direction in the answer, or an inactive answer. Regardless, the
3762 * choice of codecs should be as if the answer contained the opposite
3763 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003764 *
3765 * | Offer | Answer | Result
3766 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3767 * 0 | x - - | - x - | x - - - -
3768 * 1 | x x x | - x - | x - - x -
3769 * 2 | - x - | x - - | - x - - -
3770 * 3 | x x x | x - - | - x x - -
3771 * 4 | - x - | x x x | - x - - -
3772 * 5 | x - - | x x x | x - - - -
3773 * 6 | x x x | x x x | x x x x x
3774 */
3775// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003776static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3777static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003778// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3779// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003780static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3781static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003782// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003783static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3784static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3785static const int kResultSendrecv_SendCodecs[] = {3, 6};
3786static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3787static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003788
3789template <typename T, int IDXS>
3790std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3791 std::vector<T> out;
3792 out.reserve(IDXS);
3793 for (int idx : indices)
3794 out.push_back(array[idx]);
3795
3796 return out;
3797}
3798
Steve Anton4e70a722017-11-28 14:57:10 -08003799void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
3800 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07003801 bool add_legacy_stream) {
3802 TransportDescriptionFactory offer_tdf;
3803 TransportDescriptionFactory answer_tdf;
3804 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3805 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3806 offer_factory.set_audio_codecs(
3807 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3808 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3809 answer_factory.set_audio_codecs(
3810 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3811 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3812
ossu075af922016-06-14 03:29:38 -07003813 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003814 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3815 &offer_opts);
3816
Steve Anton4e70a722017-11-28 14:57:10 -08003817 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003818 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003819 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003820 }
3821
Steve Anton6fe1fba2018-12-11 10:15:23 -08003822 std::unique_ptr<SessionDescription> offer =
3823 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07003824 ASSERT_TRUE(offer.get() != NULL);
3825
3826 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003827 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3828 &answer_opts);
3829
Steve Anton4e70a722017-11-28 14:57:10 -08003830 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003831 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003832 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003833 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08003834 std::unique_ptr<SessionDescription> answer =
3835 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07003836 const ContentInfo* ac = answer->GetContentByName("audio");
3837
zhihuang1c378ed2017-08-17 14:10:50 -07003838 // If the factory didn't add any audio content to the answer, we cannot
3839 // check that the codecs put in are right. This happens when we neither want
3840 // to send nor receive audio. The checks are still in place if at some point
3841 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003842 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003843 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
3844 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07003845
ossu075af922016-06-14 03:29:38 -07003846 std::vector<AudioCodec> target_codecs;
3847 // For offers with sendrecv or inactive, we should never reply with more
3848 // codecs than offered, with these codec sets.
3849 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08003850 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07003851 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3852 kResultSendrecv_SendrecvCodecs);
3853 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003854 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003855 target_codecs =
3856 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003857 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003858 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003859 target_codecs =
3860 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003861 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003862 case RtpTransceiverDirection::kSendRecv:
3863 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003864 target_codecs =
3865 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08003866 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003867 target_codecs =
3868 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003869 } else {
3870 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3871 kResultSendrecv_SendrecvCodecs);
3872 }
3873 break;
3874 }
3875
zhihuang1c378ed2017-08-17 14:10:50 -07003876 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02003877 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07003878 bool first = true;
3879 os << "{";
3880 for (const auto& c : codecs) {
3881 os << (first ? " " : ", ") << c.id;
3882 first = false;
3883 }
3884 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02003885 return os.Release();
ossu075af922016-06-14 03:29:38 -07003886 };
3887
3888 EXPECT_TRUE(acd->codecs() == target_codecs)
3889 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08003890 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
3891 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07003892 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08003893 << webrtc::RtpTransceiverDirectionToString(answer_direction)
3894 << "; got: "
3895 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07003896 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08003897 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07003898 << "Only inactive offers are allowed to not generate any audio "
3899 "content";
ossu075af922016-06-14 03:29:38 -07003900 }
3901}
brandtr03d5fb12016-11-22 03:37:59 -08003902
3903} // namespace
ossu075af922016-06-14 03:29:38 -07003904
3905class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08003906 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07003907
3908TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003909 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003910}
3911
3912INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3913 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003914 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3915 RtpTransceiverDirection::kRecvOnly,
3916 RtpTransceiverDirection::kSendRecv,
3917 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07003918
3919class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08003920 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
3921 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003922 bool>> {};
ossu075af922016-06-14 03:29:38 -07003923
3924TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003925 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3926 ::testing::get<1>(GetParam()),
3927 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003928}
3929
zhihuang1c378ed2017-08-17 14:10:50 -07003930INSTANTIATE_TEST_CASE_P(
3931 MediaSessionDescriptionFactoryTest,
3932 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003933 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
3934 RtpTransceiverDirection::kRecvOnly,
3935 RtpTransceiverDirection::kSendRecv,
3936 RtpTransceiverDirection::kInactive),
3937 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3938 RtpTransceiverDirection::kRecvOnly,
3939 RtpTransceiverDirection::kSendRecv,
3940 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07003941 ::testing::Bool()));