blob: db325ed2ef167ebf9b3ade832cb4ccdbf7f73c16 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "media/base/codec.h"
16#include "media/base/testutils.h"
17#include "p2p/base/p2pconstants.h"
18#include "p2p/base/transportdescription.h"
19#include "p2p/base/transportinfo.h"
20#include "pc/mediasession.h"
Steve Anton1d03a752017-11-27 14:30:09 -080021#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "pc/srtpfilter.h"
23#include "rtc_base/checks.h"
24#include "rtc_base/fakesslidentity.h"
25#include "rtc_base/gunit.h"
26#include "rtc_base/messagedigest.h"
27#include "rtc_base/ssladapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020028#include "rtc_base/strings/string_builder.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029
Yves Gerey665174f2018-06-19 15:03:05 +020030#define ASSERT_CRYPTO(cd, s, cs) \
31 ASSERT_EQ(s, cd->cryptos().size()); \
32 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000033
34typedef std::vector<cricket::Candidate> Candidates;
35
36using cricket::MediaContentDescription;
37using cricket::MediaSessionDescriptionFactory;
zhihuang1c378ed2017-08-17 14:10:50 -070038using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039using cricket::MediaSessionOptions;
40using cricket::MediaType;
Steve Anton5adfafd2017-12-20 16:34:00 -080041using cricket::MediaProtocolType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042using cricket::SessionDescription;
43using cricket::SsrcGroup;
44using cricket::StreamParams;
45using cricket::StreamParamsVec;
46using cricket::TransportDescription;
47using cricket::TransportDescriptionFactory;
48using cricket::TransportInfo;
49using cricket::ContentInfo;
50using cricket::CryptoParamsVec;
51using cricket::AudioContentDescription;
52using cricket::VideoContentDescription;
53using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080054using cricket::GetFirstAudioContent;
55using cricket::GetFirstVideoContent;
56using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057using cricket::GetFirstAudioContentDescription;
58using cricket::GetFirstVideoContentDescription;
59using cricket::GetFirstDataContentDescription;
60using cricket::kAutoBandwidth;
61using cricket::AudioCodec;
62using cricket::VideoCodec;
63using cricket::DataCodec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064using cricket::MEDIA_TYPE_AUDIO;
65using cricket::MEDIA_TYPE_VIDEO;
66using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067using cricket::SEC_DISABLED;
68using cricket::SEC_ENABLED;
69using cricket::SEC_REQUIRED;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070070using rtc::CS_AES_CM_128_HMAC_SHA1_32;
71using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070072using rtc::CS_AEAD_AES_128_GCM;
73using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070074using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080075using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076
77static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070078 AudioCodec(103, "ISAC", 16000, -1, 1),
79 AudioCodec(102, "iLBC", 8000, 13300, 1),
80 AudioCodec(0, "PCMU", 8000, 64000, 1),
81 AudioCodec(8, "PCMA", 8000, 64000, 1),
82 AudioCodec(117, "red", 8000, 0, 1),
83 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000084
85static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +020086 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -070087 AudioCodec(0, "PCMU", 8000, 64000, 1),
88 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089};
90
91static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070092 AudioCodec(102, "iLBC", 8000, 13300, 1),
93 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000094};
95
perkj26752742016-10-24 01:21:16 -070096static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
97 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098
zhihuang1c378ed2017-08-17 14:10:50 -070099static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
100 VideoCodec(96, "H264-SVC")};
101
perkj26752742016-10-24 01:21:16 -0700102static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
103 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104
perkj26752742016-10-24 01:21:16 -0700105static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106
deadbeef67cf2c12016-04-13 10:07:16 -0700107static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
108 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109
deadbeef67cf2c12016-04-13 10:07:16 -0700110static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
111 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
deadbeef67cf2c12016-04-13 10:07:16 -0700113static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
114 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115
isheriff6f8d6862016-05-26 11:24:55 -0700116static const RtpExtension kAudioRtpExtension1[] = {
117 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
118 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119};
120
jbauch5869f502017-06-29 12:31:36 -0700121static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
122 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
123 RtpExtension("http://google.com/testing/audio_something", 10),
124 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
125};
126
isheriff6f8d6862016-05-26 11:24:55 -0700127static const RtpExtension kAudioRtpExtension2[] = {
128 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
129 RtpExtension("http://google.com/testing/audio_something_else", 8),
130 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131};
132
isheriff6f8d6862016-05-26 11:24:55 -0700133static const RtpExtension kAudioRtpExtension3[] = {
134 RtpExtension("http://google.com/testing/audio_something", 2),
135 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700136};
137
jbauch5869f502017-06-29 12:31:36 -0700138static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
139 RtpExtension("http://google.com/testing/audio_something", 2),
140 // Use RTP extension that supports encryption.
141 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
142};
143
144static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
145 RtpExtension("http://google.com/testing/audio_something", 2),
146 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
147 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
148};
149
isheriff6f8d6862016-05-26 11:24:55 -0700150static const RtpExtension kAudioRtpExtensionAnswer[] = {
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000152};
153
jbauch5869f502017-06-29 12:31:36 -0700154static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
155 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
156};
157
isheriff6f8d6862016-05-26 11:24:55 -0700158static const RtpExtension kVideoRtpExtension1[] = {
159 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
160 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000161};
162
jbauch5869f502017-06-29 12:31:36 -0700163static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
164 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
165 RtpExtension("http://google.com/testing/video_something", 13),
166 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
167};
168
isheriff6f8d6862016-05-26 11:24:55 -0700169static const RtpExtension kVideoRtpExtension2[] = {
170 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
171 RtpExtension("http://google.com/testing/video_something_else", 14),
172 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000173};
174
isheriff6f8d6862016-05-26 11:24:55 -0700175static const RtpExtension kVideoRtpExtension3[] = {
176 RtpExtension("http://google.com/testing/video_something", 4),
177 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700178};
179
jbauch5869f502017-06-29 12:31:36 -0700180static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
181 RtpExtension("http://google.com/testing/video_something", 4),
182 // Use RTP extension that supports encryption.
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
184};
185
isheriff6f8d6862016-05-26 11:24:55 -0700186static const RtpExtension kVideoRtpExtensionAnswer[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188};
189
jbauch5869f502017-06-29 12:31:36 -0700190static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
192};
193
Peter Boström0c4e06b2015-10-07 12:23:21 +0200194static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
195static const uint32_t kSimSsrc[] = {10, 20, 30};
196static const uint32_t kFec1Ssrc[] = {10, 11};
197static const uint32_t kFec2Ssrc[] = {20, 21};
198static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199
200static const char kMediaStream1[] = "stream_1";
201static const char kMediaStream2[] = "stream_2";
202static const char kVideoTrack1[] = "video_1";
203static const char kVideoTrack2[] = "video_2";
204static const char kAudioTrack1[] = "audio_1";
205static const char kAudioTrack2[] = "audio_2";
206static const char kAudioTrack3[] = "audio_3";
207static const char kDataTrack1[] = "data_1";
208static const char kDataTrack2[] = "data_2";
209static const char kDataTrack3[] = "data_3";
210
zhihuangcf5b37c2016-05-05 11:44:35 -0700211static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
212 "RTP/SAVPF"};
213static const char* kMediaProtocolsDtls[] = {
214 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
215 "UDP/TLS/RTP/SAVP"};
216
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700217// SRTP cipher name negotiated by the tests. This must be updated if the
218// default changes.
219static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
220static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
221
zhihuang1c378ed2017-08-17 14:10:50 -0700222// These constants are used to make the code using "AddMediaSection" more
223// readable.
224static constexpr bool kStopped = true;
225static constexpr bool kActive = false;
226
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000227static bool IsMediaContentOfType(const ContentInfo* content,
228 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800229 RTC_DCHECK(content);
230 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000231}
232
Steve Anton4e70a722017-11-28 14:57:10 -0800233static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800234 RTC_DCHECK(content);
235 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000236}
237
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000238static void AddRtxCodec(const VideoCodec& rtx_codec,
239 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800240 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000241 codecs->push_back(rtx_codec);
242}
243
244template <class T>
245static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
246 std::vector<std::string> codec_names;
247 for (const auto& codec : codecs) {
248 codec_names.push_back(codec.name);
249 }
250 return codec_names;
251}
252
zhihuang1c378ed2017-08-17 14:10:50 -0700253// This is used for test only. MIDs are not the identification of the
254// MediaDescriptionOptions since some end points may not support MID and the SDP
255// may not contain 'mid'.
256std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
257 const std::string& mid,
258 MediaSessionOptions* opts) {
259 return std::find_if(
260 opts->media_description_options.begin(),
261 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700262 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
263}
264
265std::vector<MediaDescriptionOptions>::const_iterator
266FindFirstMediaDescriptionByMid(const std::string& mid,
267 const MediaSessionOptions& opts) {
268 return std::find_if(
269 opts.media_description_options.begin(),
270 opts.media_description_options.end(),
271 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700272}
273
274// Add a media section to the |session_options|.
275static void AddMediaSection(MediaType type,
276 const std::string& mid,
Steve Anton4e70a722017-11-28 14:57:10 -0800277 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700278 bool stopped,
279 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800280 opts->media_description_options.push_back(
281 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700282}
283
Steve Anton4e70a722017-11-28 14:57:10 -0800284static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700285 MediaSessionOptions* opts) {
286 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
287 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
288}
289
290static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800291 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700292 MediaSessionOptions* opts) {
293 opts->data_channel_type = dct;
294 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
295}
296
Steve Anton8ffb9c32017-08-31 15:45:38 -0700297static void AttachSenderToMediaSection(
298 const std::string& mid,
299 MediaType type,
300 const std::string& track_id,
301 const std::vector<std::string>& stream_ids,
302 int num_sim_layer,
303 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700304 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
305 switch (type) {
306 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700307 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700308 break;
309 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700310 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700311 break;
312 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700313 RTC_CHECK(stream_ids.size() == 1U);
314 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700315 break;
316 default:
317 RTC_NOTREACHED();
318 }
319}
320
321static void DetachSenderFromMediaSection(const std::string& mid,
322 const std::string& track_id,
323 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700324 std::vector<cricket::SenderOptions>& sender_options_list =
325 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
326 auto sender_it =
327 std::find_if(sender_options_list.begin(), sender_options_list.end(),
328 [track_id](const cricket::SenderOptions& sender_options) {
329 return sender_options.track_id == track_id;
330 });
331 RTC_DCHECK(sender_it != sender_options_list.end());
332 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700333}
334
335// Helper function used to create a default MediaSessionOptions for Plan B SDP.
336// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
337static MediaSessionOptions CreatePlanBMediaSessionOptions() {
338 MediaSessionOptions session_options;
Steve Anton4e70a722017-11-28 14:57:10 -0800339 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
340 kActive, &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700341 return session_options;
342}
343
344// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
345// was designed for Plan B SDP, where only one audio "m=" section and one video
346// "m=" section could be generated, and ordering couldn't be controlled. Many of
347// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000348class MediaSessionDescriptionFactoryTest : public testing::Test {
349 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700350 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700351 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
352 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000353 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
354 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700355 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
356 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
358 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200359 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700360 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200361 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700362 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000363 }
364
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000365 // Create a video StreamParamsVec object with:
366 // - one video stream with 3 simulcast streams and FEC,
367 StreamParamsVec CreateComplexVideoStreamParamsVec() {
368 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
369 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
370 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
371 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
372
373 std::vector<SsrcGroup> ssrc_groups;
374 ssrc_groups.push_back(sim_group);
375 ssrc_groups.push_back(fec_group1);
376 ssrc_groups.push_back(fec_group2);
377 ssrc_groups.push_back(fec_group3);
378
379 StreamParams simulcast_params;
380 simulcast_params.id = kVideoTrack1;
381 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
382 simulcast_params.ssrc_groups = ssrc_groups;
383 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800384 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000385
386 StreamParamsVec video_streams;
387 video_streams.push_back(simulcast_params);
388
389 return video_streams;
390 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000391
392 bool CompareCryptoParams(const CryptoParamsVec& c1,
393 const CryptoParamsVec& c2) {
394 if (c1.size() != c2.size())
395 return false;
396 for (size_t i = 0; i < c1.size(); ++i)
397 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
398 c1[i].key_params != c2[i].key_params ||
399 c1[i].session_params != c2[i].session_params)
400 return false;
401 return true;
402 }
403
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700404 // Returns true if the transport info contains "renomination" as an
405 // ICE option.
406 bool GetIceRenomination(const TransportInfo* transport_info) {
407 const std::vector<std::string>& ice_options =
408 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700409 auto iter =
410 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700411 return iter != ice_options.end();
412 }
413
zhihuang1c378ed2017-08-17 14:10:50 -0700414 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700415 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416 bool has_current_desc) {
417 const std::string current_audio_ufrag = "current_audio_ufrag";
418 const std::string current_audio_pwd = "current_audio_pwd";
419 const std::string current_video_ufrag = "current_video_ufrag";
420 const std::string current_video_pwd = "current_video_pwd";
421 const std::string current_data_ufrag = "current_data_ufrag";
422 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800423 std::unique_ptr<SessionDescription> current_desc;
424 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 if (has_current_desc) {
426 current_desc.reset(new SessionDescription());
Yves Gerey665174f2018-06-19 15:03:05 +0200427 EXPECT_TRUE(current_desc->AddTransportInfo(TransportInfo(
428 "audio",
429 TransportDescription(current_audio_ufrag, current_audio_pwd))));
430 EXPECT_TRUE(current_desc->AddTransportInfo(TransportInfo(
431 "video",
432 TransportDescription(current_video_ufrag, current_video_pwd))));
433 EXPECT_TRUE(current_desc->AddTransportInfo(TransportInfo(
434 "data", TransportDescription(current_data_ufrag, current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 }
436 if (offer) {
437 desc.reset(f1_.CreateOffer(options, current_desc.get()));
438 } else {
kwiberg31022942016-03-11 14:18:21 -0800439 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440 offer.reset(f1_.CreateOffer(options, NULL));
441 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
442 }
443 ASSERT_TRUE(desc.get() != NULL);
444 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000445 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 EXPECT_TRUE(ti_audio != NULL);
447 if (has_current_desc) {
448 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
449 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
450 } else {
451 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
452 ti_audio->description.ice_ufrag.size());
453 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
454 ti_audio->description.ice_pwd.size());
455 }
zhihuang1c378ed2017-08-17 14:10:50 -0700456 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700457 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700458 EXPECT_EQ(
459 media_desc_options_it->transport_options.enable_ice_renomination,
460 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461
462 } else {
463 EXPECT_TRUE(ti_audio == NULL);
464 }
465 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000466 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000467 EXPECT_TRUE(ti_video != NULL);
468 if (options.bundle_enabled) {
469 EXPECT_EQ(ti_audio->description.ice_ufrag,
470 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200471 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000472 } else {
473 if (has_current_desc) {
474 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
475 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
476 } else {
477 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
478 ti_video->description.ice_ufrag.size());
479 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
480 ti_video->description.ice_pwd.size());
481 }
482 }
zhihuang1c378ed2017-08-17 14:10:50 -0700483 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700484 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700485 EXPECT_EQ(
486 media_desc_options_it->transport_options.enable_ice_renomination,
487 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000488 } else {
489 EXPECT_TRUE(ti_video == NULL);
490 }
491 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
492 if (options.has_data()) {
493 EXPECT_TRUE(ti_data != NULL);
494 if (options.bundle_enabled) {
495 EXPECT_EQ(ti_audio->description.ice_ufrag,
496 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200497 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498 } else {
499 if (has_current_desc) {
500 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
501 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
502 } else {
503 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
504 ti_data->description.ice_ufrag.size());
505 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
506 ti_data->description.ice_pwd.size());
507 }
508 }
zhihuang1c378ed2017-08-17 14:10:50 -0700509 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700510 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700511 EXPECT_EQ(
512 media_desc_options_it->transport_options.enable_ice_renomination,
513 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700514
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 } else {
516 EXPECT_TRUE(ti_video == NULL);
517 }
518 }
519
520 void TestCryptoWithBundle(bool offer) {
521 f1_.set_secure(SEC_ENABLED);
522 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800523 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
524 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
525 &options);
kwiberg31022942016-03-11 14:18:21 -0800526 std::unique_ptr<SessionDescription> ref_desc;
527 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000528 if (offer) {
529 options.bundle_enabled = false;
530 ref_desc.reset(f1_.CreateOffer(options, NULL));
531 options.bundle_enabled = true;
532 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
533 } else {
534 options.bundle_enabled = true;
535 ref_desc.reset(f1_.CreateOffer(options, NULL));
536 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
537 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800538 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800540 desc->GetContentDescriptionByName("audio");
541 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000542 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800543 desc->GetContentDescriptionByName("video");
544 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
546 video_media_desc->cryptos()));
547 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700548 EXPECT_EQ(std::string(kDefaultSrtpCryptoSuite),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 audio_media_desc->cryptos()[0].cipher_suite);
550
551 // Verify the selected crypto is one from the reference audio
552 // media content.
553 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800554 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 bool found = false;
556 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
557 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200558 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 found = true;
560 break;
561 }
562 }
563 EXPECT_TRUE(found);
564 }
565
566 // This test that the audio and video media direction is set to
567 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700568 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800570 RtpTransceiverDirection direction_in_offer,
571 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700572 MediaSessionOptions offer_opts;
573 AddAudioVideoSections(direction_in_offer, &offer_opts);
574
575 std::unique_ptr<SessionDescription> offer(
576 f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700578 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700580 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582
zhihuang1c378ed2017-08-17 14:10:50 -0700583 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800584 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -0800585 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700586 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 const AudioContentDescription* acd_answer =
588 GetFirstAudioContentDescription(answer.get());
589 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
590 const VideoContentDescription* vcd_answer =
591 GetFirstVideoContentDescription(answer.get());
592 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
593 }
594
595 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800596 RTC_DCHECK(content);
597 RTC_CHECK(content->media_description());
598 const cricket::AudioContentDescription* audio_desc =
599 content->media_description()->as_audio();
600 RTC_CHECK(audio_desc);
601 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
602 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800604 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 }
606 return true;
607 }
608
jbauchcb560652016-08-04 05:20:32 -0700609 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
610 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800611 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
jbauchcb560652016-08-04 05:20:32 -0700612 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700613
jbauchcb560652016-08-04 05:20:32 -0700614 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800615 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
jbauchcb560652016-08-04 05:20:32 -0700616 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700617
jbauchcb560652016-08-04 05:20:32 -0700618 f1_.set_secure(SEC_ENABLED);
619 f2_.set_secure(SEC_ENABLED);
620 std::unique_ptr<SessionDescription> offer(
621 f1_.CreateOffer(offer_opts, NULL));
622 ASSERT_TRUE(offer.get() != NULL);
623 std::unique_ptr<SessionDescription> answer(
624 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
625 const ContentInfo* ac = answer->GetContentByName("audio");
626 const ContentInfo* vc = answer->GetContentByName("video");
627 ASSERT_TRUE(ac != NULL);
628 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800629 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
630 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800631 const AudioContentDescription* acd = ac->media_description()->as_audio();
632 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700633 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
634 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
635 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700636 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700637 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
638 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700639 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700640 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700641 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700642 }
643 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
644 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
Yves Gerey665174f2018-06-19 15:03:05 +0200645 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
646 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700647 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700648 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700649 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700650 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700651 }
652 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
653 }
654
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 protected:
656 MediaSessionDescriptionFactory f1_;
657 MediaSessionDescriptionFactory f2_;
658 TransportDescriptionFactory tdf1_;
659 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660};
661
662// Create a typical audio offer, and ensure it matches what we expect.
663TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
664 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800665 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700666 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667 ASSERT_TRUE(offer.get() != NULL);
668 const ContentInfo* ac = offer->GetContentByName("audio");
669 const ContentInfo* vc = offer->GetContentByName("video");
670 ASSERT_TRUE(ac != NULL);
671 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800672 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800673 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000674 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700675 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700676 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
678 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700679 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
681}
682
683// Create a typical video offer, and ensure it matches what we expect.
684TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
685 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800686 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800688 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689 ASSERT_TRUE(offer.get() != NULL);
690 const ContentInfo* ac = offer->GetContentByName("audio");
691 const ContentInfo* vc = offer->GetContentByName("video");
692 ASSERT_TRUE(ac != NULL);
693 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800694 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
695 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800696 const AudioContentDescription* acd = ac->media_description()->as_audio();
697 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700699 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700700 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
702 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700703 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000704 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
705 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
706 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700707 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000708 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
709 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700710 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
712}
713
714// Test creating an offer with bundle where the Codecs have the same dynamic
715// RTP playlod type. The test verifies that the offer don't contain the
716// duplicate RTP payload types.
717TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
718 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700719 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
721 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
722 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
723
724 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800725 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
726 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800728 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 const VideoContentDescription* vcd =
730 GetFirstVideoContentDescription(offer.get());
731 const AudioContentDescription* acd =
732 GetFirstAudioContentDescription(offer.get());
733 const DataContentDescription* dcd =
734 GetFirstDataContentDescription(offer.get());
735 ASSERT_TRUE(NULL != vcd);
736 ASSERT_TRUE(NULL != acd);
737 ASSERT_TRUE(NULL != dcd);
738 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
739 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
740 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
741 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
742 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
743 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
744}
745
zhihuang1c378ed2017-08-17 14:10:50 -0700746// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747// after an audio only session has been negotiated.
748TEST_F(MediaSessionDescriptionFactoryTest,
749 TestCreateUpdatedVideoOfferWithBundle) {
750 f1_.set_secure(SEC_ENABLED);
751 f2_.set_secure(SEC_ENABLED);
752 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800753 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
754 kActive, &opts);
755 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kInactive,
756 kStopped, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757 opts.data_channel_type = cricket::DCT_NONE;
758 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800759 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
760 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 f2_.CreateAnswer(offer.get(), opts, NULL));
762
763 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800764 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
765 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
766 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800768 std::unique_ptr<SessionDescription> updated_offer(
769 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770
771 const AudioContentDescription* acd =
772 GetFirstAudioContentDescription(updated_offer.get());
773 const VideoContentDescription* vcd =
774 GetFirstVideoContentDescription(updated_offer.get());
775 const DataContentDescription* dcd =
776 GetFirstDataContentDescription(updated_offer.get());
777 EXPECT_TRUE(NULL != vcd);
778 EXPECT_TRUE(NULL != acd);
779 EXPECT_TRUE(NULL != dcd);
780
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700781 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700783 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000784 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700785 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
787}
deadbeef44f08192015-12-15 16:20:09 -0800788
wu@webrtc.org78187522013-10-07 23:32:02 +0000789// Create a RTP data offer, and ensure it matches what we expect.
790TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800792 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
793 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800795 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 ASSERT_TRUE(offer.get() != NULL);
797 const ContentInfo* ac = offer->GetContentByName("audio");
798 const ContentInfo* dc = offer->GetContentByName("data");
799 ASSERT_TRUE(ac != NULL);
800 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800801 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
802 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800803 const AudioContentDescription* acd = ac->media_description()->as_audio();
804 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700806 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700807 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
809 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700810 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
812 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
813 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700814 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200816 dcd->bandwidth()); // default bandwidth (auto)
817 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700818 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
820}
821
wu@webrtc.org78187522013-10-07 23:32:02 +0000822// Create an SCTP data offer with bundle without error.
823TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
824 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000825 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800826 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000827 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800828 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000829 EXPECT_TRUE(offer.get() != NULL);
830 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
831}
832
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000833// Test creating an sctp data channel from an already generated offer.
834TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
835 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000836 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800837 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000838 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800839 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000840 ASSERT_TRUE(offer1.get() != NULL);
841 const ContentInfo* data = offer1->GetContentByName("data");
842 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800843 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000844
845 // Now set data_channel_type to 'none' (default) and make sure that the
846 // datachannel type that gets generated from the previous offer, is of the
847 // same type.
848 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800849 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000850 f1_.CreateOffer(opts, offer1.get()));
851 data = offer2->GetContentByName("data");
852 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800853 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000854}
855
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856// Create an audio, video offer without legacy StreamParams.
857TEST_F(MediaSessionDescriptionFactoryTest,
858 TestCreateOfferWithoutLegacyStreams) {
859 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800860 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -0800861 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 ASSERT_TRUE(offer.get() != NULL);
863 const ContentInfo* ac = offer->GetContentByName("audio");
864 const ContentInfo* vc = offer->GetContentByName("video");
865 ASSERT_TRUE(ac != NULL);
866 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800867 const AudioContentDescription* acd = ac->media_description()->as_audio();
868 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869
Yves Gerey665174f2018-06-19 15:03:05 +0200870 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
871 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872}
873
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000874// Creates an audio+video sendonly offer.
875TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700876 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800877 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700878 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700879 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700880 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700881 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000882
zhihuang1c378ed2017-08-17 14:10:50 -0700883 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000884 ASSERT_TRUE(offer.get() != NULL);
885 EXPECT_EQ(2u, offer->contents().size());
886 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
887 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
888
Steve Anton4e70a722017-11-28 14:57:10 -0800889 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
890 GetMediaDirection(&offer->contents()[0]));
891 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
892 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000893}
894
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000895// Verifies that the order of the media contents in the current
896// SessionDescription is preserved in the new SessionDescription.
897TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
898 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800899 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000900
kwiberg31022942016-03-11 14:18:21 -0800901 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000902 ASSERT_TRUE(offer1.get() != NULL);
903 EXPECT_EQ(1u, offer1->contents().size());
904 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
905
Steve Anton4e70a722017-11-28 14:57:10 -0800906 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
907 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800908 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000909 f1_.CreateOffer(opts, offer1.get()));
910 ASSERT_TRUE(offer2.get() != NULL);
911 EXPECT_EQ(2u, offer2->contents().size());
912 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
913 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
914
Steve Anton4e70a722017-11-28 14:57:10 -0800915 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
916 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800917 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000918 f1_.CreateOffer(opts, offer2.get()));
919 ASSERT_TRUE(offer3.get() != NULL);
920 EXPECT_EQ(3u, offer3->contents().size());
921 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
922 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
923 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000924}
925
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000926// Create a typical audio answer, and ensure it matches what we expect.
927TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
928 f1_.set_secure(SEC_ENABLED);
929 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800930 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700931 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000932 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800933 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700934 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000935 const ContentInfo* ac = answer->GetContentByName("audio");
936 const ContentInfo* vc = answer->GetContentByName("video");
937 ASSERT_TRUE(ac != NULL);
938 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800939 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800940 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000941 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
942 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700943 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
945 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700946 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
948}
949
jbauchcb560652016-08-04 05:20:32 -0700950// Create a typical audio answer with GCM ciphers enabled, and ensure it
951// matches what we expect.
952TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
953 f1_.set_secure(SEC_ENABLED);
954 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700955 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
956 opts.crypto_options.enable_gcm_crypto_suites = true;
957 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700958 ASSERT_TRUE(offer.get() != NULL);
959 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700960 f2_.CreateAnswer(offer.get(), opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700961 const ContentInfo* ac = answer->GetContentByName("audio");
962 const ContentInfo* vc = answer->GetContentByName("video");
963 ASSERT_TRUE(ac != NULL);
964 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800965 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800966 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -0700967 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
968 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700969 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700970 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
971 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700972 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700973 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
974}
975
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000976// Create a typical video answer, and ensure it matches what we expect.
977TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
978 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800979 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 f1_.set_secure(SEC_ENABLED);
981 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800982 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800984 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 f2_.CreateAnswer(offer.get(), opts, NULL));
986 const ContentInfo* ac = answer->GetContentByName("audio");
987 const ContentInfo* vc = answer->GetContentByName("video");
988 ASSERT_TRUE(ac != NULL);
989 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800990 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
991 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800992 const AudioContentDescription* acd = ac->media_description()->as_audio();
993 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000994 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
995 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
996 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700997 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700999 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1001 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
Yves Gerey665174f2018-06-19 15:03:05 +02001002 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1003 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001004 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001005 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
1006}
1007
jbauchcb560652016-08-04 05:20:32 -07001008// Create a typical video answer with GCM ciphers enabled, and ensure it
1009// matches what we expect.
1010TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1011 TestVideoGcmCipher(true, true);
1012}
1013
1014// Create a typical video answer with GCM ciphers enabled for the offer only,
1015// and ensure it matches what we expect.
1016TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1017 TestVideoGcmCipher(true, false);
1018}
1019
1020// Create a typical video answer with GCM ciphers enabled for the answer only,
1021// and ensure it matches what we expect.
1022TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1023 TestVideoGcmCipher(false, true);
1024}
1025
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001026TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001027 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001028 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029 f1_.set_secure(SEC_ENABLED);
1030 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001031 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001032 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001033 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001034 f2_.CreateAnswer(offer.get(), opts, NULL));
1035 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001036 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001038 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001039 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1040 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001041 const AudioContentDescription* acd = ac->media_description()->as_audio();
1042 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001043 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1044 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1045 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001046 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001048 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001049 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1050 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001051 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001052 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001053 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001054 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055}
1056
jbauchcb560652016-08-04 05:20:32 -07001057TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001058 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001059 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
jbauchcb560652016-08-04 05:20:32 -07001060 opts.crypto_options.enable_gcm_crypto_suites = true;
1061 f1_.set_secure(SEC_ENABLED);
1062 f2_.set_secure(SEC_ENABLED);
1063 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1064 ASSERT_TRUE(offer.get() != NULL);
1065 std::unique_ptr<SessionDescription> answer(
1066 f2_.CreateAnswer(offer.get(), opts, NULL));
1067 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001068 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001069 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001070 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001071 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1072 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001073 const AudioContentDescription* acd = ac->media_description()->as_audio();
1074 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001075 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1076 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1077 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001078 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001079 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001080 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001081 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1082 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001083 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001084 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001085 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001086 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
1087}
1088
1089// The use_sctpmap flag should be set in a DataContentDescription by default.
1090// The answer's use_sctpmap flag should match the offer's.
1091TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1092 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001093 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001094 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1095 ASSERT_TRUE(offer.get() != NULL);
1096 ContentInfo* dc_offer = offer->GetContentByName("data");
1097 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001098 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001099 EXPECT_TRUE(dcd_offer->use_sctpmap());
1100
1101 std::unique_ptr<SessionDescription> answer(
1102 f2_.CreateAnswer(offer.get(), opts, NULL));
1103 const ContentInfo* dc_answer = answer->GetContentByName("data");
1104 ASSERT_TRUE(dc_answer != NULL);
1105 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001106 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001107 EXPECT_TRUE(dcd_answer->use_sctpmap());
1108}
1109
1110// The answer's use_sctpmap flag should match the offer's.
1111TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1112 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001113 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001114 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1115 ASSERT_TRUE(offer.get() != NULL);
1116 ContentInfo* dc_offer = offer->GetContentByName("data");
1117 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001118 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001119 dcd_offer->set_use_sctpmap(false);
1120
1121 std::unique_ptr<SessionDescription> answer(
1122 f2_.CreateAnswer(offer.get(), opts, NULL));
1123 const ContentInfo* dc_answer = answer->GetContentByName("data");
1124 ASSERT_TRUE(dc_answer != NULL);
1125 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001126 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001127 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001128}
1129
deadbeef8b7e9ad2017-05-25 09:38:55 -07001130// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1131// and "TCP/DTLS/SCTP" offers.
1132TEST_F(MediaSessionDescriptionFactoryTest,
1133 TestCreateDataAnswerToDifferentOfferedProtos) {
1134 // Need to enable DTLS offer/answer generation (disabled by default in this
1135 // test).
1136 f1_.set_secure(SEC_ENABLED);
1137 f2_.set_secure(SEC_ENABLED);
1138 tdf1_.set_secure(SEC_ENABLED);
1139 tdf2_.set_secure(SEC_ENABLED);
1140
1141 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001142 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001143 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1144 ASSERT_TRUE(offer.get() != nullptr);
1145 ContentInfo* dc_offer = offer->GetContentByName("data");
1146 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001147 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001148
1149 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1150 "TCP/DTLS/SCTP"};
1151 for (const std::string& proto : protos) {
1152 dcd_offer->set_protocol(proto);
1153 std::unique_ptr<SessionDescription> answer(
1154 f2_.CreateAnswer(offer.get(), opts, nullptr));
1155 const ContentInfo* dc_answer = answer->GetContentByName("data");
1156 ASSERT_TRUE(dc_answer != nullptr);
1157 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001158 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001159 EXPECT_FALSE(dc_answer->rejected);
1160 EXPECT_EQ(proto, dcd_answer->protocol());
1161 }
1162}
1163
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001164// Verifies that the order of the media contents in the offer is preserved in
1165// the answer.
1166TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1167 MediaSessionOptions opts;
1168
1169 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001170 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001171 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001172 ASSERT_TRUE(offer1.get() != NULL);
1173
1174 // Appends audio to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001175 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1176 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001177 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001178 f1_.CreateOffer(opts, offer1.get()));
1179 ASSERT_TRUE(offer2.get() != NULL);
1180
1181 // Appends video to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001182 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1183 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001184 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001185 f1_.CreateOffer(opts, offer2.get()));
1186 ASSERT_TRUE(offer3.get() != NULL);
1187
kwiberg31022942016-03-11 14:18:21 -08001188 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001189 f2_.CreateAnswer(offer3.get(), opts, NULL));
1190 ASSERT_TRUE(answer.get() != NULL);
1191 EXPECT_EQ(3u, answer->contents().size());
1192 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1193 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1194 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1195}
1196
ossu075af922016-06-14 03:29:38 -07001197// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1198// answerer settings.
1199
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001200// This test that the media direction is set to send/receive in an answer if
1201// the offer is send receive.
1202TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001203 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1204 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205}
1206
1207// This test that the media direction is set to receive only in an answer if
1208// the offer is send only.
1209TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001210 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1211 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212}
1213
1214// This test that the media direction is set to send only in an answer if
1215// the offer is recv only.
1216TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001217 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1218 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219}
1220
1221// This test that the media direction is set to inactive in an answer if
1222// the offer is inactive.
1223TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001224 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1225 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226}
1227
1228// Test that a data content with an unknown protocol is rejected in an answer.
1229TEST_F(MediaSessionDescriptionFactoryTest,
1230 CreateDataAnswerToOfferWithUnknownProtocol) {
1231 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001232 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001233 f1_.set_secure(SEC_ENABLED);
1234 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001235 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001236 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001238 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 ASSERT_TRUE(dcd_offer != NULL);
1240 std::string protocol = "a weird unknown protocol";
1241 dcd_offer->set_protocol(protocol);
1242
kwiberg31022942016-03-11 14:18:21 -08001243 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 f2_.CreateAnswer(offer.get(), opts, NULL));
1245
1246 const ContentInfo* dc_answer = answer->GetContentByName("data");
1247 ASSERT_TRUE(dc_answer != NULL);
1248 EXPECT_TRUE(dc_answer->rejected);
1249 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001250 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 ASSERT_TRUE(dcd_answer != NULL);
1252 EXPECT_EQ(protocol, dcd_answer->protocol());
1253}
1254
1255// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1256TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001257 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 f1_.set_secure(SEC_DISABLED);
1259 f2_.set_secure(SEC_DISABLED);
1260 tdf1_.set_secure(SEC_DISABLED);
1261 tdf2_.set_secure(SEC_DISABLED);
1262
kwiberg31022942016-03-11 14:18:21 -08001263 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 const AudioContentDescription* offer_acd =
1265 GetFirstAudioContentDescription(offer.get());
1266 ASSERT_TRUE(offer_acd != NULL);
1267 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1268
kwiberg31022942016-03-11 14:18:21 -08001269 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270 f2_.CreateAnswer(offer.get(), opts, NULL));
1271
1272 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1273 ASSERT_TRUE(ac_answer != NULL);
1274 EXPECT_FALSE(ac_answer->rejected);
1275
1276 const AudioContentDescription* answer_acd =
1277 GetFirstAudioContentDescription(answer.get());
1278 ASSERT_TRUE(answer_acd != NULL);
1279 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1280}
1281
1282// Create a video offer and answer and ensure the RTP header extensions
1283// matches what we expect.
1284TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1285 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001286 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1288 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1289 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1290 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1291
kwiberg31022942016-03-11 14:18:21 -08001292 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001293 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001294 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 f2_.CreateAnswer(offer.get(), opts, NULL));
1296
Yves Gerey665174f2018-06-19 15:03:05 +02001297 EXPECT_EQ(
1298 MAKE_VECTOR(kAudioRtpExtension1),
1299 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1300 EXPECT_EQ(
1301 MAKE_VECTOR(kVideoRtpExtension1),
1302 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1303 EXPECT_EQ(
1304 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1305 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1306 EXPECT_EQ(
1307 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1308 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309}
1310
jbauch5869f502017-06-29 12:31:36 -07001311TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001312 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001313 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001314 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001315
1316 f1_.set_enable_encrypted_rtp_header_extensions(true);
1317 f2_.set_enable_encrypted_rtp_header_extensions(true);
1318
Yves Gerey665174f2018-06-19 15:03:05 +02001319 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1320 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1321 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1322 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001323
1324 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1325 ASSERT_TRUE(offer.get() != NULL);
1326 std::unique_ptr<SessionDescription> answer(
1327 f2_.CreateAnswer(offer.get(), opts, NULL));
1328
Yves Gerey665174f2018-06-19 15:03:05 +02001329 EXPECT_EQ(
1330 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1331 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1332 EXPECT_EQ(
1333 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1334 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1335 EXPECT_EQ(
1336 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1337 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1338 EXPECT_EQ(
1339 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1340 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001341}
1342
1343TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001344 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001345 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001346 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001347
1348 f1_.set_enable_encrypted_rtp_header_extensions(true);
1349
Yves Gerey665174f2018-06-19 15:03:05 +02001350 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1351 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1352 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1353 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001354
1355 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1356 ASSERT_TRUE(offer.get() != NULL);
1357 std::unique_ptr<SessionDescription> answer(
1358 f2_.CreateAnswer(offer.get(), opts, NULL));
1359
Yves Gerey665174f2018-06-19 15:03:05 +02001360 EXPECT_EQ(
1361 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1362 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1363 EXPECT_EQ(
1364 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1365 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1366 EXPECT_EQ(
1367 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1368 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1369 EXPECT_EQ(
1370 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1371 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001372}
1373
1374TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001375 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001376 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001377 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001378
1379 f2_.set_enable_encrypted_rtp_header_extensions(true);
1380
Yves Gerey665174f2018-06-19 15:03:05 +02001381 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1382 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1383 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1384 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001385
1386 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1387 ASSERT_TRUE(offer.get() != NULL);
1388 std::unique_ptr<SessionDescription> answer(
1389 f2_.CreateAnswer(offer.get(), opts, NULL));
1390
Yves Gerey665174f2018-06-19 15:03:05 +02001391 EXPECT_EQ(
1392 MAKE_VECTOR(kAudioRtpExtension1),
1393 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1394 EXPECT_EQ(
1395 MAKE_VECTOR(kVideoRtpExtension1),
1396 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1397 EXPECT_EQ(
1398 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1399 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1400 EXPECT_EQ(
1401 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1402 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001403}
1404
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001405// Create an audio, video, data answer without legacy StreamParams.
1406TEST_F(MediaSessionDescriptionFactoryTest,
1407 TestCreateAnswerWithoutLegacyStreams) {
1408 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001409 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1410 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001411 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001412 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001413 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001414 f2_.CreateAnswer(offer.get(), opts, NULL));
1415 const ContentInfo* ac = answer->GetContentByName("audio");
1416 const ContentInfo* vc = answer->GetContentByName("video");
1417 const ContentInfo* dc = answer->GetContentByName("data");
1418 ASSERT_TRUE(ac != NULL);
1419 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001420 const AudioContentDescription* acd = ac->media_description()->as_audio();
1421 const VideoContentDescription* vcd = vc->media_description()->as_video();
1422 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001423
1424 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1425 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1426 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1427}
1428
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001429// Create a typical video answer, and ensure it matches what we expect.
1430TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1431 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001432 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1433 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1434 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001435
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001436 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001437 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1438 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1439 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001440
kwiberg31022942016-03-11 14:18:21 -08001441 std::unique_ptr<SessionDescription> offer;
1442 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001443
1444 offer_opts.rtcp_mux_enabled = true;
1445 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001446 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1447 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1448 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1449 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1450 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1451 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1452 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1453 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1454 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1455 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1456 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1457 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1458 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1459 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1460
1461 offer_opts.rtcp_mux_enabled = true;
1462 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001463 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1464 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1465 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1466 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1467 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1468 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1469 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1470 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1471 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1472 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1473 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1474 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1475 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1476 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1477
1478 offer_opts.rtcp_mux_enabled = false;
1479 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001480 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1481 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1482 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1483 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1484 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1485 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1486 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1487 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1488 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1489 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1490 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1491 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1492 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1493 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1494
1495 offer_opts.rtcp_mux_enabled = false;
1496 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001497 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1498 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1499 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1500 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1501 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1502 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1503 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1504 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1505 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1506 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1507 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1508 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1509 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1510 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1511}
1512
1513// Create an audio-only answer to a video offer.
1514TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1515 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001516 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1517 kActive, &opts);
1518 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1519 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001520 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001521 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001522
1523 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001524 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001525 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526 const ContentInfo* ac = answer->GetContentByName("audio");
1527 const ContentInfo* vc = answer->GetContentByName("video");
1528 ASSERT_TRUE(ac != NULL);
1529 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001530 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001531 EXPECT_TRUE(vc->rejected);
1532}
1533
1534// Create an audio-only answer to an offer with data.
1535TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001536 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537 opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001538 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1539 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001540 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001541 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001542
1543 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001544 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001545 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001546 const ContentInfo* ac = answer->GetContentByName("audio");
1547 const ContentInfo* dc = answer->GetContentByName("data");
1548 ASSERT_TRUE(ac != NULL);
1549 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001550 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001551 EXPECT_TRUE(dc->rejected);
1552}
1553
1554// Create an answer that rejects the contents which are rejected in the offer.
1555TEST_F(MediaSessionDescriptionFactoryTest,
1556 CreateAnswerToOfferWithRejectedMedia) {
1557 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001558 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1559 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001560 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001561 ASSERT_TRUE(offer.get() != NULL);
1562 ContentInfo* ac = offer->GetContentByName("audio");
1563 ContentInfo* vc = offer->GetContentByName("video");
1564 ContentInfo* dc = offer->GetContentByName("data");
1565 ASSERT_TRUE(ac != NULL);
1566 ASSERT_TRUE(vc != NULL);
1567 ASSERT_TRUE(dc != NULL);
1568 ac->rejected = true;
1569 vc->rejected = true;
1570 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001571 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001572 f2_.CreateAnswer(offer.get(), opts, NULL));
1573 ac = answer->GetContentByName("audio");
1574 vc = answer->GetContentByName("video");
1575 dc = answer->GetContentByName("data");
1576 ASSERT_TRUE(ac != NULL);
1577 ASSERT_TRUE(vc != NULL);
1578 ASSERT_TRUE(dc != NULL);
1579 EXPECT_TRUE(ac->rejected);
1580 EXPECT_TRUE(vc->rejected);
1581 EXPECT_TRUE(dc->rejected);
1582}
1583
1584// Create an audio and video offer with:
1585// - one video track
1586// - two audio tracks
1587// - two data tracks
1588// and ensure it matches what we expect. Also updates the initial offer by
1589// adding a new video track and replaces one of the audio tracks.
1590TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1591 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001592 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001593 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001594 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001595 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001596 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001597 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001598 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001599
Steve Anton4e70a722017-11-28 14:57:10 -08001600 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001601 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001602 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001603 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001604 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605
1606 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001607 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001608
1609 ASSERT_TRUE(offer.get() != NULL);
1610 const ContentInfo* ac = offer->GetContentByName("audio");
1611 const ContentInfo* vc = offer->GetContentByName("video");
1612 const ContentInfo* dc = offer->GetContentByName("data");
1613 ASSERT_TRUE(ac != NULL);
1614 ASSERT_TRUE(vc != NULL);
1615 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001616 const AudioContentDescription* acd = ac->media_description()->as_audio();
1617 const VideoContentDescription* vcd = vc->media_description()->as_video();
1618 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001619 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001620 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001621
1622 const StreamParamsVec& audio_streams = acd->streams();
1623 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001624 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001625 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1626 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1627 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1628 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1629 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1630 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1631
1632 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1633 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001634 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635
1636 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1637 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001638 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639
1640 const StreamParamsVec& video_streams = vcd->streams();
1641 ASSERT_EQ(1U, video_streams.size());
1642 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1643 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1644 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1645 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1646
1647 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1648 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001649 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650
1651 const StreamParamsVec& data_streams = dcd->streams();
1652 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001653 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001654 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1655 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1656 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1657 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1658 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1659 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1660
1661 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001662 dcd->bandwidth()); // default bandwidth (auto)
1663 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001664 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001665
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001666 // Update the offer. Add a new video track that is not synched to the
1667 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001668 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001669 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001670 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1671 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001672 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001673 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1674 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001675 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001676 std::unique_ptr<SessionDescription> updated_offer(
1677 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001678
1679 ASSERT_TRUE(updated_offer.get() != NULL);
1680 ac = updated_offer->GetContentByName("audio");
1681 vc = updated_offer->GetContentByName("video");
1682 dc = updated_offer->GetContentByName("data");
1683 ASSERT_TRUE(ac != NULL);
1684 ASSERT_TRUE(vc != NULL);
1685 ASSERT_TRUE(dc != NULL);
1686 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001687 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001688 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001689 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001690 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001691 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001692
1693 EXPECT_EQ(acd->type(), updated_acd->type());
1694 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1695 EXPECT_EQ(vcd->type(), updated_vcd->type());
1696 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1697 EXPECT_EQ(dcd->type(), updated_dcd->type());
1698 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001699 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001700 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001701 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001702 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001703 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001704 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1705
1706 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1707 ASSERT_EQ(2U, updated_audio_streams.size());
1708 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1709 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1710 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1711 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1712 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1713
1714 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1715 ASSERT_EQ(2U, updated_video_streams.size());
1716 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1717 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001718 // All the media streams in one PeerConnection share one RTCP CNAME.
1719 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001720
1721 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1722 ASSERT_EQ(2U, updated_data_streams.size());
1723 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1724 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1725 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1726 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1727 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001728 // The stream correctly got the CNAME from the MediaSessionOptions.
1729 // The Expected RTCP CNAME is the default one as we are using the default
1730 // MediaSessionOptions.
1731 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732}
1733
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001734// Create an offer with simulcast video stream.
1735TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1736 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001737 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1738 kActive, &opts);
1739 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1740 kActive, &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001741 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001742 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001743 {kMediaStream1}, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001744 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001745
1746 ASSERT_TRUE(offer.get() != NULL);
1747 const ContentInfo* vc = offer->GetContentByName("video");
1748 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001749 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001750
1751 const StreamParamsVec& video_streams = vcd->streams();
1752 ASSERT_EQ(1U, video_streams.size());
1753 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1754 const SsrcGroup* sim_ssrc_group =
1755 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1756 ASSERT_TRUE(sim_ssrc_group != NULL);
1757 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1758}
1759
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001760// Create an audio and video answer to a standard video offer with:
1761// - one video track
1762// - two audio tracks
1763// - two data tracks
1764// and ensure it matches what we expect. Also updates the initial answer by
1765// adding a new video track and removes one of the audio tracks.
1766TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1767 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001768 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1769 kActive, &offer_opts);
1770 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1771 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001772 offer_opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001773 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1774 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775 f1_.set_secure(SEC_ENABLED);
1776 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001777 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001778
zhihuang1c378ed2017-08-17 14:10:50 -07001779 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001780 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
1781 kActive, &answer_opts);
1782 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1783 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001784 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001785 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001786 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001787 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001788 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001789 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001790
Steve Anton4e70a722017-11-28 14:57:10 -08001791 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
1792 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001793 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001794 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001795 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001796 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001797 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001798
kwiberg31022942016-03-11 14:18:21 -08001799 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001800 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001801
1802 ASSERT_TRUE(answer.get() != NULL);
1803 const ContentInfo* ac = answer->GetContentByName("audio");
1804 const ContentInfo* vc = answer->GetContentByName("video");
1805 const ContentInfo* dc = answer->GetContentByName("data");
1806 ASSERT_TRUE(ac != NULL);
1807 ASSERT_TRUE(vc != NULL);
1808 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001809 const AudioContentDescription* acd = ac->media_description()->as_audio();
1810 const VideoContentDescription* vcd = vc->media_description()->as_video();
1811 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001812 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1813 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1814 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001815
1816 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1817 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1818
1819 const StreamParamsVec& audio_streams = acd->streams();
1820 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001821 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001822 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1823 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1824 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1825 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1826 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1827 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1828
1829 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1830 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1831
1832 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1833 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1834
1835 const StreamParamsVec& video_streams = vcd->streams();
1836 ASSERT_EQ(1U, video_streams.size());
1837 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1838 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1839 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1840 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1841
1842 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1843 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1844
1845 const StreamParamsVec& data_streams = dcd->streams();
1846 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001847 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001848 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1849 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1850 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1851 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1852 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1853 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1854
1855 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001856 dcd->bandwidth()); // default bandwidth (auto)
1857 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001858
1859 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001860 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001861 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001862 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001863 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1864 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001865 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001866 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001867
1868 ASSERT_TRUE(updated_answer.get() != NULL);
1869 ac = updated_answer->GetContentByName("audio");
1870 vc = updated_answer->GetContentByName("video");
1871 dc = updated_answer->GetContentByName("data");
1872 ASSERT_TRUE(ac != NULL);
1873 ASSERT_TRUE(vc != NULL);
1874 ASSERT_TRUE(dc != NULL);
1875 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001876 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001877 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001878 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001879 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001880 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001881
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001882 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001883 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001884 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001885 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001886 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001887 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1888
1889 EXPECT_EQ(acd->type(), updated_acd->type());
1890 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1891 EXPECT_EQ(vcd->type(), updated_vcd->type());
1892 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1893 EXPECT_EQ(dcd->type(), updated_dcd->type());
1894 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1895
1896 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1897 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001898 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001899
1900 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1901 ASSERT_EQ(2U, updated_video_streams.size());
1902 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1903 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001904 // All media streams in one PeerConnection share one CNAME.
1905 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001906
1907 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1908 ASSERT_EQ(1U, updated_data_streams.size());
1909 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1910}
1911
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001912// Create an updated offer after creating an answer to the original offer and
1913// verify that the codecs that were part of the original answer are not changed
1914// in the updated offer.
1915TEST_F(MediaSessionDescriptionFactoryTest,
1916 RespondentCreatesOfferAfterCreatingAnswer) {
1917 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001918 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919
kwiberg31022942016-03-11 14:18:21 -08001920 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1921 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001922 f2_.CreateAnswer(offer.get(), opts, NULL));
1923
1924 const AudioContentDescription* acd =
1925 GetFirstAudioContentDescription(answer.get());
1926 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1927
1928 const VideoContentDescription* vcd =
1929 GetFirstVideoContentDescription(answer.get());
1930 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1931
kwiberg31022942016-03-11 14:18:21 -08001932 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001933 f2_.CreateOffer(opts, answer.get()));
1934
1935 // The expected audio codecs are the common audio codecs from the first
1936 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1937 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001938 // TODO(wu): |updated_offer| should not include the codec
1939 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001940 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02001941 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942 };
1943
1944 // The expected video codecs are the common video codecs from the first
1945 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1946 // preference order.
1947 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02001948 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001949 };
1950
1951 const AudioContentDescription* updated_acd =
1952 GetFirstAudioContentDescription(updated_offer.get());
1953 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1954
1955 const VideoContentDescription* updated_vcd =
1956 GetFirstVideoContentDescription(updated_offer.get());
1957 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1958}
1959
1960// Create an updated offer after creating an answer to the original offer and
1961// verify that the codecs that were part of the original answer are not changed
1962// in the updated offer. In this test Rtx is enabled.
1963TEST_F(MediaSessionDescriptionFactoryTest,
1964 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1965 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001966 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1967 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001968 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001969 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001970 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971 f1_.set_video_codecs(f1_codecs);
1972
1973 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001974 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001975 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976 f2_.set_video_codecs(f2_codecs);
1977
kwiberg31022942016-03-11 14:18:21 -08001978 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001979 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001980 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001981 f2_.CreateAnswer(offer.get(), opts, NULL));
1982
1983 const VideoContentDescription* vcd =
1984 GetFirstVideoContentDescription(answer.get());
1985
1986 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001987 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1988 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001989
1990 EXPECT_EQ(expected_codecs, vcd->codecs());
1991
deadbeef67cf2c12016-04-13 10:07:16 -07001992 // Now, make sure we get same result (except for the order) if |f2_| creates
1993 // an updated offer even though the default payload types between |f1_| and
1994 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08001995 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001996 f2_.CreateOffer(opts, answer.get()));
1997 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08001998 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2000
2001 const VideoContentDescription* updated_vcd =
2002 GetFirstVideoContentDescription(updated_answer.get());
2003
2004 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2005}
2006
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002007// Regression test for:
2008// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2009// Existing codecs should always appear before new codecs in re-offers. But
2010// under a specific set of circumstances, the existing RTX codec was ending up
2011// added to the end of the list.
2012TEST_F(MediaSessionDescriptionFactoryTest,
2013 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2014 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002015 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2016 kActive, &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002017 // We specifically choose different preferred payload types for VP8 to
2018 // trigger the issue.
2019 cricket::VideoCodec vp8_offerer(100, "VP8");
2020 cricket::VideoCodec vp8_offerer_rtx =
2021 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2022 cricket::VideoCodec vp8_answerer(110, "VP8");
2023 cricket::VideoCodec vp8_answerer_rtx =
2024 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2025 cricket::VideoCodec vp9(120, "VP9");
2026 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2027
2028 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2029 // We also specifically cause the answerer to prefer VP9, such that if it
2030 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2031 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2032 vp8_answerer_rtx};
2033
2034 f1_.set_video_codecs(f1_codecs);
2035 f2_.set_video_codecs(f2_codecs);
2036 std::vector<AudioCodec> audio_codecs;
2037 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2038 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2039
2040 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
2041 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2042 ASSERT_TRUE(offer.get() != NULL);
2043 std::unique_ptr<SessionDescription> answer(
2044 f2_.CreateAnswer(offer.get(), opts, NULL));
2045
2046 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2047 // But if the bug is triggered, RTX for VP8 ends up last.
2048 std::unique_ptr<SessionDescription> updated_offer(
2049 f2_.CreateOffer(opts, answer.get()));
2050
2051 const VideoContentDescription* vcd =
2052 GetFirstVideoContentDescription(updated_offer.get());
2053 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2054 ASSERT_EQ(4u, codecs.size());
2055 EXPECT_EQ(vp8_offerer, codecs[0]);
2056 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2057 EXPECT_EQ(vp9, codecs[2]);
2058 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002059}
2060
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002061// Create an updated offer that adds video after creating an audio only answer
2062// to the original offer. This test verifies that if a video codec and the RTX
2063// codec have the same default payload type as an audio codec that is already in
2064// use, the added codecs payload types are changed.
2065TEST_F(MediaSessionDescriptionFactoryTest,
2066 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2067 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002068 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002069 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002070 f1_.set_video_codecs(f1_codecs);
2071
2072 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002073 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2074 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002075
kwiberg31022942016-03-11 14:18:21 -08002076 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2077 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002078 f2_.CreateAnswer(offer.get(), opts, NULL));
2079
2080 const AudioContentDescription* acd =
2081 GetFirstAudioContentDescription(answer.get());
2082 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2083
2084 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2085 // reference be the same as an audio codec that was negotiated in the
2086 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002087 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002088 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002089
2090 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2091 int used_pl_type = acd->codecs()[0].id;
2092 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002093 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002094 f2_.set_video_codecs(f2_codecs);
2095
kwiberg31022942016-03-11 14:18:21 -08002096 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002097 f2_.CreateOffer(opts, answer.get()));
2098 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002099 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002100 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2101
2102 const AudioContentDescription* updated_acd =
2103 GetFirstAudioContentDescription(answer.get());
2104 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2105
2106 const VideoContentDescription* updated_vcd =
2107 GetFirstVideoContentDescription(updated_answer.get());
2108
2109 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002110 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002111 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002112 EXPECT_NE(used_pl_type, new_h264_pl_type);
2113 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002114 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002115 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2116 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2117}
2118
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002119// Create an updated offer with RTX after creating an answer to an offer
2120// without RTX, and with different default payload types.
2121// Verify that the added RTX codec references the correct payload type.
2122TEST_F(MediaSessionDescriptionFactoryTest,
2123 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2124 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002125 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002126
2127 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2128 // This creates rtx for H264 with the payload type |f2_| uses.
2129 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2130 f2_.set_video_codecs(f2_codecs);
2131
kwiberg31022942016-03-11 14:18:21 -08002132 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002133 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002134 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002135 f2_.CreateAnswer(offer.get(), opts, nullptr));
2136
2137 const VideoContentDescription* vcd =
2138 GetFirstVideoContentDescription(answer.get());
2139
2140 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2141 EXPECT_EQ(expected_codecs, vcd->codecs());
2142
2143 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2144 // updated offer, even though the default payload types are different from
2145 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002146 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002147 f2_.CreateOffer(opts, answer.get()));
2148 ASSERT_TRUE(updated_offer);
2149
2150 const VideoContentDescription* updated_vcd =
2151 GetFirstVideoContentDescription(updated_offer.get());
2152
2153 // New offer should attempt to add H263, and RTX for H264.
2154 expected_codecs.push_back(kVideoCodecs2[1]);
2155 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2156 &expected_codecs);
2157 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2158}
2159
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002160// Test that RTX is ignored when there is no associated payload type parameter.
2161TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2162 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002163 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2164 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002165 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002166 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002167 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002168 f1_.set_video_codecs(f1_codecs);
2169
2170 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002171 // This creates RTX for H264 with the payload type |f2_| uses.
2172 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002173 f2_.set_video_codecs(f2_codecs);
2174
kwiberg31022942016-03-11 14:18:21 -08002175 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002176 ASSERT_TRUE(offer.get() != NULL);
2177 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2178 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2179 // is possible to test that that RTX is dropped when
2180 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002181 MediaContentDescription* media_desc =
2182 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2183 ASSERT_TRUE(media_desc);
2184 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002185 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002186 for (VideoCodec& codec : codecs) {
2187 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2188 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002189 }
2190 }
2191 desc->set_codecs(codecs);
2192
kwiberg31022942016-03-11 14:18:21 -08002193 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002194 f2_.CreateAnswer(offer.get(), opts, NULL));
2195
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002196 std::vector<std::string> codec_names =
2197 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2198 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2199 cricket::kRtxCodecName));
2200}
2201
2202// Test that RTX will be filtered out in the answer if its associated payload
2203// type doesn't match the local value.
2204TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2205 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002206 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2207 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002208 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2209 // This creates RTX for H264 in sender.
2210 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2211 f1_.set_video_codecs(f1_codecs);
2212
2213 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2214 // This creates RTX for H263 in receiver.
2215 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2216 f2_.set_video_codecs(f2_codecs);
2217
kwiberg31022942016-03-11 14:18:21 -08002218 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002219 ASSERT_TRUE(offer.get() != NULL);
2220 // Associated payload type doesn't match, therefore, RTX codec is removed in
2221 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002222 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002223 f2_.CreateAnswer(offer.get(), opts, NULL));
2224
2225 std::vector<std::string> codec_names =
2226 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2227 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2228 cricket::kRtxCodecName));
2229}
2230
2231// Test that when multiple RTX codecs are offered, only the matched RTX codec
2232// is added in the answer, and the unsupported RTX codec is filtered out.
2233TEST_F(MediaSessionDescriptionFactoryTest,
2234 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2235 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002236 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2237 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002238 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2239 // This creates RTX for H264-SVC in sender.
2240 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2241 f1_.set_video_codecs(f1_codecs);
2242
2243 // This creates RTX for H264 in sender.
2244 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2245 f1_.set_video_codecs(f1_codecs);
2246
2247 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2248 // This creates RTX for H264 in receiver.
2249 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2250 f2_.set_video_codecs(f2_codecs);
2251
2252 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2253 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002254 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002255 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002256 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002257 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002258 const VideoContentDescription* vcd =
2259 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002260 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2261 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2262 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002263
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002264 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002265}
2266
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002267// Test that after one RTX codec has been negotiated, a new offer can attempt
2268// to add another.
2269TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2270 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002271 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2272 kActive, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002273 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2274 // This creates RTX for H264 for the offerer.
2275 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2276 f1_.set_video_codecs(f1_codecs);
2277
kwiberg31022942016-03-11 14:18:21 -08002278 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002279 ASSERT_TRUE(offer);
2280 const VideoContentDescription* vcd =
2281 GetFirstVideoContentDescription(offer.get());
2282
2283 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2284 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2285 &expected_codecs);
2286 EXPECT_EQ(expected_codecs, vcd->codecs());
2287
2288 // Now, attempt to add RTX for H264-SVC.
2289 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2290 f1_.set_video_codecs(f1_codecs);
2291
kwiberg31022942016-03-11 14:18:21 -08002292 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002293 f1_.CreateOffer(opts, offer.get()));
2294 ASSERT_TRUE(updated_offer);
2295 vcd = GetFirstVideoContentDescription(updated_offer.get());
2296
2297 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2298 &expected_codecs);
2299 EXPECT_EQ(expected_codecs, vcd->codecs());
2300}
2301
Noah Richards2e7a0982015-05-18 14:02:54 -07002302// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2303// generated for each simulcast ssrc and correctly grouped.
2304TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2305 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002306 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2307 kActive, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002308 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002309 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002310 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002311
2312 // Use a single real codec, and then add RTX for it.
2313 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002314 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002315 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2316 f1_.set_video_codecs(f1_codecs);
2317
2318 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2319 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002320 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002321 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002322 MediaContentDescription* media_desc =
2323 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2324 ASSERT_TRUE(media_desc);
2325 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002326 const StreamParamsVec& streams = desc->streams();
2327 // Single stream.
2328 ASSERT_EQ(1u, streams.size());
2329 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2330 EXPECT_EQ(6u, streams[0].ssrcs.size());
2331 // And should have a SIM group for the simulcast.
2332 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2333 // And a FID group for RTX.
2334 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002335 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002336 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2337 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002338 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002339 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2340 EXPECT_EQ(3u, fid_ssrcs.size());
2341}
2342
brandtr03d5fb12016-11-22 03:37:59 -08002343// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2344// together with a FEC-FR grouping.
2345TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2346 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002347 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2348 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002349 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002350 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002351 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002352
2353 // Use a single real codec, and then add FlexFEC for it.
2354 std::vector<VideoCodec> f1_codecs;
2355 f1_codecs.push_back(VideoCodec(97, "H264"));
2356 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2357 f1_.set_video_codecs(f1_codecs);
2358
2359 // Ensure that the offer has a single FlexFEC ssrc and that
2360 // there is no FEC-FR ssrc + grouping for each.
2361 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2362 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002363 MediaContentDescription* media_desc =
2364 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2365 ASSERT_TRUE(media_desc);
2366 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002367 const StreamParamsVec& streams = desc->streams();
2368 // Single stream.
2369 ASSERT_EQ(1u, streams.size());
2370 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2371 EXPECT_EQ(2u, streams[0].ssrcs.size());
2372 // And should have a FEC-FR group for FlexFEC.
2373 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2374 std::vector<uint32_t> primary_ssrcs;
2375 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2376 ASSERT_EQ(1u, primary_ssrcs.size());
2377 uint32_t flexfec_ssrc;
2378 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2379 EXPECT_NE(flexfec_ssrc, 0u);
2380}
2381
2382// Test that FlexFEC is disabled for simulcast.
2383// TODO(brandtr): Remove this test when we support simulcast, either through
2384// multiple FlexfecSenders, or through multistream protection.
2385TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2386 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002387 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2388 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002389 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002390 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002391 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002392
2393 // Use a single real codec, and then add FlexFEC for it.
2394 std::vector<VideoCodec> f1_codecs;
2395 f1_codecs.push_back(VideoCodec(97, "H264"));
2396 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2397 f1_.set_video_codecs(f1_codecs);
2398
2399 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2400 // there is no FEC-FR ssrc + grouping for each.
2401 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2402 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002403 MediaContentDescription* media_desc =
2404 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2405 ASSERT_TRUE(media_desc);
2406 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002407 const StreamParamsVec& streams = desc->streams();
2408 // Single stream.
2409 ASSERT_EQ(1u, streams.size());
2410 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2411 EXPECT_EQ(3u, streams[0].ssrcs.size());
2412 // And should have a SIM group for the simulcast.
2413 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2414 // And not a FEC-FR group for FlexFEC.
2415 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2416 std::vector<uint32_t> primary_ssrcs;
2417 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2418 EXPECT_EQ(3u, primary_ssrcs.size());
2419 for (uint32_t primary_ssrc : primary_ssrcs) {
2420 uint32_t flexfec_ssrc;
2421 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2422 }
2423}
2424
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002425// Create an updated offer after creating an answer to the original offer and
2426// verify that the RTP header extensions that were part of the original answer
2427// are not changed in the updated offer.
2428TEST_F(MediaSessionDescriptionFactoryTest,
2429 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2430 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002431 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432
2433 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2434 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2435 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2436 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2437
kwiberg31022942016-03-11 14:18:21 -08002438 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2439 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002440 f2_.CreateAnswer(offer.get(), opts, NULL));
2441
Yves Gerey665174f2018-06-19 15:03:05 +02002442 EXPECT_EQ(
2443 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2444 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2445 EXPECT_EQ(
2446 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2447 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002448
kwiberg31022942016-03-11 14:18:21 -08002449 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002450 f2_.CreateOffer(opts, answer.get()));
2451
2452 // The expected RTP header extensions in the new offer are the resulting
2453 // extensions from the first offer/answer exchange plus the extensions only
2454 // |f2_| offer.
2455 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002456 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002457 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2458 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2459 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002460 };
2461
2462 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002463 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002464 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2465 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2466 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002467 };
2468
2469 const AudioContentDescription* updated_acd =
2470 GetFirstAudioContentDescription(updated_offer.get());
2471 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2472 updated_acd->rtp_header_extensions());
2473
2474 const VideoContentDescription* updated_vcd =
2475 GetFirstVideoContentDescription(updated_offer.get());
2476 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2477 updated_vcd->rtp_header_extensions());
2478}
2479
deadbeefa5b273a2015-08-20 17:30:13 -07002480// Verify that if the same RTP extension URI is used for audio and video, the
2481// same ID is used. Also verify that the ID isn't changed when creating an
2482// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002483TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002484 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002485 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002486
2487 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2488 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2489
kwiberg31022942016-03-11 14:18:21 -08002490 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002491
2492 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2493 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002494 const RtpExtension kExpectedVideoRtpExtension[] = {
2495 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002496 };
2497
Yves Gerey665174f2018-06-19 15:03:05 +02002498 EXPECT_EQ(
2499 MAKE_VECTOR(kAudioRtpExtension3),
2500 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2501 EXPECT_EQ(
2502 MAKE_VECTOR(kExpectedVideoRtpExtension),
2503 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002504
2505 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002506 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002507 f1_.CreateOffer(opts, offer.get()));
2508
2509 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02002510 GetFirstAudioContentDescription(updated_offer.get())
2511 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002512 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002513 GetFirstVideoContentDescription(updated_offer.get())
2514 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002515}
2516
jbauch5869f502017-06-29 12:31:36 -07002517// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2518TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2519 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002520 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002521
2522 f1_.set_enable_encrypted_rtp_header_extensions(true);
2523 f2_.set_enable_encrypted_rtp_header_extensions(true);
2524
2525 f1_.set_audio_rtp_header_extensions(
2526 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2527 f1_.set_video_rtp_header_extensions(
2528 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2529
2530 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2531
2532 // The extensions that are shared between audio and video should use the same
2533 // id.
2534 const RtpExtension kExpectedVideoRtpExtension[] = {
2535 kVideoRtpExtension3ForEncryption[0],
2536 kAudioRtpExtension3ForEncryptionOffer[1],
2537 kAudioRtpExtension3ForEncryptionOffer[2],
2538 };
2539
Yves Gerey665174f2018-06-19 15:03:05 +02002540 EXPECT_EQ(
2541 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2542 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2543 EXPECT_EQ(
2544 MAKE_VECTOR(kExpectedVideoRtpExtension),
2545 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002546
2547 // Nothing should change when creating a new offer
2548 std::unique_ptr<SessionDescription> updated_offer(
2549 f1_.CreateOffer(opts, offer.get()));
2550
2551 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02002552 GetFirstAudioContentDescription(updated_offer.get())
2553 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002554 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002555 GetFirstVideoContentDescription(updated_offer.get())
2556 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002557}
2558
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002559TEST(MediaSessionDescription, CopySessionDescription) {
2560 SessionDescription source;
2561 cricket::ContentGroup group(cricket::CN_AUDIO);
2562 source.AddGroup(group);
2563 AudioContentDescription* acd(new AudioContentDescription());
2564 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2565 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08002566 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002567 VideoContentDescription* vcd(new VideoContentDescription());
2568 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2569 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08002570 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002571
kwiberg31022942016-03-11 14:18:21 -08002572 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002573 ASSERT_TRUE(copy.get() != NULL);
2574 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2575 const ContentInfo* ac = copy->GetContentByName("audio");
2576 const ContentInfo* vc = copy->GetContentByName("video");
2577 ASSERT_TRUE(ac != NULL);
2578 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08002579 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002580 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002581 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2582 EXPECT_EQ(1u, acd->first_ssrc());
2583
Steve Anton5adfafd2017-12-20 16:34:00 -08002584 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002585 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002586 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2587 EXPECT_EQ(2u, vcd->first_ssrc());
2588}
2589
2590// The below TestTransportInfoXXX tests create different offers/answers, and
2591// ensure the TransportInfo in the SessionDescription matches what we expect.
2592TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2593 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002594 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2595 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002596 TestTransportInfo(true, options, false);
2597}
2598
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002599TEST_F(MediaSessionDescriptionFactoryTest,
2600 TestTransportInfoOfferIceRenomination) {
2601 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002602 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2603 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002604 options.media_description_options[0]
2605 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002606 TestTransportInfo(true, options, false);
2607}
2608
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002609TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2610 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002611 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2612 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002613 TestTransportInfo(true, options, true);
2614}
2615
2616TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2617 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002618 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2619 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2620 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002621 TestTransportInfo(true, options, false);
2622}
2623
2624TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002625 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002626 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002627 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2628 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2629 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002630 TestTransportInfo(true, options, true);
2631}
2632
2633TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2634 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002635 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2636 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2637 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002638 options.bundle_enabled = true;
2639 TestTransportInfo(true, options, false);
2640}
2641
2642TEST_F(MediaSessionDescriptionFactoryTest,
2643 TestTransportInfoOfferBundleCurrent) {
2644 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002645 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2646 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2647 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002648 options.bundle_enabled = true;
2649 TestTransportInfo(true, options, true);
2650}
2651
2652TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2653 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002654 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2655 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002656 TestTransportInfo(false, options, false);
2657}
2658
2659TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002660 TestTransportInfoAnswerIceRenomination) {
2661 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002662 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2663 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002664 options.media_description_options[0]
2665 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002666 TestTransportInfo(false, options, false);
2667}
2668
2669TEST_F(MediaSessionDescriptionFactoryTest,
2670 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002671 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002672 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2673 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002674 TestTransportInfo(false, options, true);
2675}
2676
2677TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2678 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002679 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2680 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2681 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002682 TestTransportInfo(false, options, false);
2683}
2684
2685TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002686 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002687 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002688 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2689 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2690 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002691 TestTransportInfo(false, options, true);
2692}
2693
2694TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2695 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002696 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2697 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2698 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002699 options.bundle_enabled = true;
2700 TestTransportInfo(false, options, false);
2701}
2702
2703TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002704 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002705 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002706 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2707 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2708 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002709 options.bundle_enabled = true;
2710 TestTransportInfo(false, options, true);
2711}
2712
2713// Create an offer with bundle enabled and verify the crypto parameters are
2714// the common set of the available cryptos.
2715TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2716 TestCryptoWithBundle(true);
2717}
2718
2719// Create an answer with bundle enabled and verify the crypto parameters are
2720// the common set of the available cryptos.
2721TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2722 TestCryptoWithBundle(false);
2723}
2724
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002725// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2726// DTLS is not enabled locally.
2727TEST_F(MediaSessionDescriptionFactoryTest,
2728 TestOfferDtlsSavpfWithoutDtlsFailed) {
2729 f1_.set_secure(SEC_ENABLED);
2730 f2_.set_secure(SEC_ENABLED);
2731 tdf1_.set_secure(SEC_DISABLED);
2732 tdf2_.set_secure(SEC_DISABLED);
2733
kwiberg31022942016-03-11 14:18:21 -08002734 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002735 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002736 ASSERT_TRUE(offer.get() != NULL);
2737 ContentInfo* offer_content = offer->GetContentByName("audio");
2738 ASSERT_TRUE(offer_content != NULL);
2739 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002740 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002741 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2742
kwiberg31022942016-03-11 14:18:21 -08002743 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002744 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002745 ASSERT_TRUE(answer != NULL);
2746 ContentInfo* answer_content = answer->GetContentByName("audio");
2747 ASSERT_TRUE(answer_content != NULL);
2748
2749 ASSERT_TRUE(answer_content->rejected);
2750}
2751
2752// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2753// UDP/TLS/RTP/SAVPF.
2754TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2755 f1_.set_secure(SEC_ENABLED);
2756 f2_.set_secure(SEC_ENABLED);
2757 tdf1_.set_secure(SEC_ENABLED);
2758 tdf2_.set_secure(SEC_ENABLED);
2759
kwiberg31022942016-03-11 14:18:21 -08002760 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002761 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002762 ASSERT_TRUE(offer.get() != NULL);
2763 ContentInfo* offer_content = offer->GetContentByName("audio");
2764 ASSERT_TRUE(offer_content != NULL);
2765 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002766 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002767 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2768
kwiberg31022942016-03-11 14:18:21 -08002769 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002770 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002771 ASSERT_TRUE(answer != NULL);
2772
2773 const ContentInfo* answer_content = answer->GetContentByName("audio");
2774 ASSERT_TRUE(answer_content != NULL);
2775 ASSERT_FALSE(answer_content->rejected);
2776
2777 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002778 answer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002779 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
Yves Gerey665174f2018-06-19 15:03:05 +02002780 answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002781}
2782
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783// Test that we include both SDES and DTLS in the offer, but only include SDES
2784// in the answer if DTLS isn't negotiated.
2785TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2786 f1_.set_secure(SEC_ENABLED);
2787 f2_.set_secure(SEC_ENABLED);
2788 tdf1_.set_secure(SEC_ENABLED);
2789 tdf2_.set_secure(SEC_DISABLED);
2790 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002791 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002792 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793 const cricket::MediaContentDescription* audio_media_desc;
2794 const cricket::MediaContentDescription* video_media_desc;
2795 const cricket::TransportDescription* audio_trans_desc;
2796 const cricket::TransportDescription* video_trans_desc;
2797
2798 // Generate an offer with SDES and DTLS support.
2799 offer.reset(f1_.CreateOffer(options, NULL));
2800 ASSERT_TRUE(offer.get() != NULL);
2801
Steve Antonb1c1de12017-12-21 15:14:30 -08002802 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002803 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002804 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002806 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002807 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2808
2809 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2810 ASSERT_TRUE(audio_trans_desc != NULL);
2811 video_trans_desc = offer->GetTransportDescriptionByName("video");
2812 ASSERT_TRUE(video_trans_desc != NULL);
2813 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2814 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2815
2816 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2817 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2818 ASSERT_TRUE(answer.get() != NULL);
2819
Steve Antonb1c1de12017-12-21 15:14:30 -08002820 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002821 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002822 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002823 ASSERT_TRUE(video_media_desc != NULL);
2824 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2825 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2826
2827 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2828 ASSERT_TRUE(audio_trans_desc != NULL);
2829 video_trans_desc = answer->GetTransportDescriptionByName("video");
2830 ASSERT_TRUE(video_trans_desc != NULL);
2831 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2832 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2833
2834 // Enable DTLS; the answer should now only have DTLS support.
2835 tdf2_.set_secure(SEC_ENABLED);
2836 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2837 ASSERT_TRUE(answer.get() != NULL);
2838
Steve Antonb1c1de12017-12-21 15:14:30 -08002839 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002840 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002841 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002842 ASSERT_TRUE(video_media_desc != NULL);
2843 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2844 EXPECT_TRUE(video_media_desc->cryptos().empty());
2845 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2846 audio_media_desc->protocol());
2847 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2848 video_media_desc->protocol());
2849
2850 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2851 ASSERT_TRUE(audio_trans_desc != NULL);
2852 video_trans_desc = answer->GetTransportDescriptionByName("video");
2853 ASSERT_TRUE(video_trans_desc != NULL);
2854 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2855 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002856
2857 // Try creating offer again. DTLS enabled now, crypto's should be empty
2858 // in new offer.
2859 offer.reset(f1_.CreateOffer(options, offer.get()));
2860 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002861 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002862 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002863 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002864 ASSERT_TRUE(video_media_desc != NULL);
2865 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2866 EXPECT_TRUE(video_media_desc->cryptos().empty());
2867
2868 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2869 ASSERT_TRUE(audio_trans_desc != NULL);
2870 video_trans_desc = offer->GetTransportDescriptionByName("video");
2871 ASSERT_TRUE(video_trans_desc != NULL);
2872 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2873 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874}
2875
2876// Test that an answer can't be created if cryptos are required but the offer is
2877// unsecure.
2878TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002879 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002880 f1_.set_secure(SEC_DISABLED);
2881 tdf1_.set_secure(SEC_DISABLED);
2882 f2_.set_secure(SEC_REQUIRED);
2883 tdf1_.set_secure(SEC_ENABLED);
2884
kwiberg31022942016-03-11 14:18:21 -08002885 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002886 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002887 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002888 f2_.CreateAnswer(offer.get(), options, NULL));
2889 EXPECT_TRUE(answer.get() == NULL);
2890}
2891
2892// Test that we accept a DTLS offer without SDES and create an appropriate
2893// answer.
2894TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2895 f1_.set_secure(SEC_DISABLED);
2896 f2_.set_secure(SEC_ENABLED);
2897 tdf1_.set_secure(SEC_ENABLED);
2898 tdf2_.set_secure(SEC_ENABLED);
2899 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002900 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2901 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2902 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002903
kwiberg31022942016-03-11 14:18:21 -08002904 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002905
2906 // Generate an offer with DTLS but without SDES.
2907 offer.reset(f1_.CreateOffer(options, NULL));
2908 ASSERT_TRUE(offer.get() != NULL);
2909
2910 const AudioContentDescription* audio_offer =
2911 GetFirstAudioContentDescription(offer.get());
2912 ASSERT_TRUE(audio_offer->cryptos().empty());
2913 const VideoContentDescription* video_offer =
2914 GetFirstVideoContentDescription(offer.get());
2915 ASSERT_TRUE(video_offer->cryptos().empty());
2916 const DataContentDescription* data_offer =
2917 GetFirstDataContentDescription(offer.get());
2918 ASSERT_TRUE(data_offer->cryptos().empty());
2919
2920 const cricket::TransportDescription* audio_offer_trans_desc =
2921 offer->GetTransportDescriptionByName("audio");
2922 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2923 const cricket::TransportDescription* video_offer_trans_desc =
2924 offer->GetTransportDescriptionByName("video");
2925 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2926 const cricket::TransportDescription* data_offer_trans_desc =
2927 offer->GetTransportDescriptionByName("data");
2928 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2929
2930 // Generate an answer with DTLS.
2931 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2932 ASSERT_TRUE(answer.get() != NULL);
2933
2934 const cricket::TransportDescription* audio_answer_trans_desc =
2935 answer->GetTransportDescriptionByName("audio");
2936 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2937 const cricket::TransportDescription* video_answer_trans_desc =
2938 answer->GetTransportDescriptionByName("video");
2939 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2940 const cricket::TransportDescription* data_answer_trans_desc =
2941 answer->GetTransportDescriptionByName("data");
2942 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2943}
2944
2945// Verifies if vad_enabled option is set to false, CN codecs are not present in
2946// offer or answer.
2947TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2948 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002949 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002950 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002951 ASSERT_TRUE(offer.get() != NULL);
2952 const ContentInfo* audio_content = offer->GetContentByName("audio");
2953 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2954
2955 options.vad_enabled = false;
2956 offer.reset(f1_.CreateOffer(options, NULL));
2957 ASSERT_TRUE(offer.get() != NULL);
2958 audio_content = offer->GetContentByName("audio");
2959 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002960 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002961 f1_.CreateAnswer(offer.get(), options, NULL));
2962 ASSERT_TRUE(answer.get() != NULL);
2963 audio_content = answer->GetContentByName("audio");
2964 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2965}
deadbeef44f08192015-12-15 16:20:09 -08002966
zhihuang1c378ed2017-08-17 14:10:50 -07002967// Test that the generated MIDs match the existing offer.
2968TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08002969 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002970 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
2971 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
2972 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
2973 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08002974 opts.data_channel_type = cricket::DCT_SCTP;
Steve Anton4e70a722017-11-28 14:57:10 -08002975 AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
2976 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002977 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08002978 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08002979 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002980 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07002981
deadbeef44f08192015-12-15 16:20:09 -08002982 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2983 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2984 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2985 ASSERT_TRUE(audio_content != nullptr);
2986 ASSERT_TRUE(video_content != nullptr);
2987 ASSERT_TRUE(data_content != nullptr);
2988 EXPECT_EQ("audio_modified", audio_content->name);
2989 EXPECT_EQ("video_modified", video_content->name);
2990 EXPECT_EQ("data_modified", data_content->name);
2991}
zhihuangcf5b37c2016-05-05 11:44:35 -07002992
zhihuang1c378ed2017-08-17 14:10:50 -07002993// The following tests verify that the unified plan SDP is supported.
2994// Test that we can create an offer with multiple media sections of same media
2995// type.
2996TEST_F(MediaSessionDescriptionFactoryTest,
2997 CreateOfferWithMultipleAVMediaSections) {
2998 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002999 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3000 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003001 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003002 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003003
Steve Anton4e70a722017-11-28 14:57:10 -08003004 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3005 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003006 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003007 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003008
Steve Anton4e70a722017-11-28 14:57:10 -08003009 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3010 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003011 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003012 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003013
Steve Anton4e70a722017-11-28 14:57:10 -08003014 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3015 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003016 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003017 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003018 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3019 ASSERT_TRUE(offer);
3020
3021 ASSERT_EQ(4u, offer->contents().size());
3022 EXPECT_FALSE(offer->contents()[0].rejected);
3023 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003024 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003025 ASSERT_EQ(1u, acd->streams().size());
3026 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003027 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003028
3029 EXPECT_FALSE(offer->contents()[1].rejected);
3030 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003031 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003032 ASSERT_EQ(1u, vcd->streams().size());
3033 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003034 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003035
3036 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003037 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003038 ASSERT_EQ(1u, acd->streams().size());
3039 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003040 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003041
3042 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003043 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003044 ASSERT_EQ(1u, vcd->streams().size());
3045 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003046 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003047}
3048
3049// Test that we can create an answer with multiple media sections of same media
3050// type.
3051TEST_F(MediaSessionDescriptionFactoryTest,
3052 CreateAnswerWithMultipleAVMediaSections) {
3053 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003054 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3055 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003056 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003057 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003058
Steve Anton4e70a722017-11-28 14:57:10 -08003059 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3060 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003061 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003062 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003063
Steve Anton4e70a722017-11-28 14:57:10 -08003064 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3065 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003066 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003067 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003068
Steve Anton4e70a722017-11-28 14:57:10 -08003069 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3070 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003071 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003072 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003073
3074 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3075 ASSERT_TRUE(offer);
3076 std::unique_ptr<SessionDescription> answer(
3077 f2_.CreateAnswer(offer.get(), opts, nullptr));
3078
3079 ASSERT_EQ(4u, answer->contents().size());
3080 EXPECT_FALSE(answer->contents()[0].rejected);
3081 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003082 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003083 ASSERT_EQ(1u, acd->streams().size());
3084 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003085 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003086
3087 EXPECT_FALSE(answer->contents()[1].rejected);
3088 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003089 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003090 ASSERT_EQ(1u, vcd->streams().size());
3091 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003092 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003093
3094 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003095 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003096 ASSERT_EQ(1u, acd->streams().size());
3097 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003098 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003099
3100 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003101 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003102 ASSERT_EQ(1u, vcd->streams().size());
3103 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003104 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003105}
3106
3107// Test that the media section will be rejected in offer if the corresponding
3108// MediaDescriptionOptions is stopped by the offerer.
3109TEST_F(MediaSessionDescriptionFactoryTest,
3110 CreateOfferWithMediaSectionStoppedByOfferer) {
3111 // Create an offer with two audio sections and one of them is stopped.
3112 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003113 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3114 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3115 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3116 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003117 std::unique_ptr<SessionDescription> offer(
3118 f1_.CreateOffer(offer_opts, nullptr));
3119 ASSERT_TRUE(offer);
3120 ASSERT_EQ(2u, offer->contents().size());
3121 EXPECT_FALSE(offer->contents()[0].rejected);
3122 EXPECT_TRUE(offer->contents()[1].rejected);
3123}
3124
3125// Test that the media section will be rejected in answer if the corresponding
3126// MediaDescriptionOptions is stopped by the offerer.
3127TEST_F(MediaSessionDescriptionFactoryTest,
3128 CreateAnswerWithMediaSectionStoppedByOfferer) {
3129 // Create an offer with two audio sections and one of them is stopped.
3130 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003131 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3132 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3133 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3134 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003135 std::unique_ptr<SessionDescription> offer(
3136 f1_.CreateOffer(offer_opts, nullptr));
3137 ASSERT_TRUE(offer);
3138 ASSERT_EQ(2u, offer->contents().size());
3139 EXPECT_FALSE(offer->contents()[0].rejected);
3140 EXPECT_TRUE(offer->contents()[1].rejected);
3141
3142 // Create an answer based on the offer.
3143 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003144 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3145 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3146 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3147 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003148 std::unique_ptr<SessionDescription> answer(
3149 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3150 ASSERT_EQ(2u, answer->contents().size());
3151 EXPECT_FALSE(answer->contents()[0].rejected);
3152 EXPECT_TRUE(answer->contents()[1].rejected);
3153}
3154
3155// Test that the media section will be rejected in answer if the corresponding
3156// MediaDescriptionOptions is stopped by the answerer.
3157TEST_F(MediaSessionDescriptionFactoryTest,
3158 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3159 // Create an offer with two audio sections.
3160 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003161 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3162 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3163 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3164 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003165 std::unique_ptr<SessionDescription> offer(
3166 f1_.CreateOffer(offer_opts, nullptr));
3167 ASSERT_TRUE(offer);
3168 ASSERT_EQ(2u, offer->contents().size());
3169 ASSERT_FALSE(offer->contents()[0].rejected);
3170 ASSERT_FALSE(offer->contents()[1].rejected);
3171
3172 // The answerer rejects one of the audio sections.
3173 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003174 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3175 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3176 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3177 RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003178 std::unique_ptr<SessionDescription> answer(
3179 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3180 ASSERT_EQ(2u, answer->contents().size());
3181 EXPECT_FALSE(answer->contents()[0].rejected);
3182 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003183
3184 // The TransportInfo of the rejected m= section is expected to be added in the
3185 // answer.
3186 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003187}
3188
3189// Test the generated media sections has the same order of the
3190// corresponding MediaDescriptionOptions.
3191TEST_F(MediaSessionDescriptionFactoryTest,
3192 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3193 MediaSessionOptions opts;
3194 // This tests put video section first because normally audio comes first by
3195 // default.
Steve Anton4e70a722017-11-28 14:57:10 -08003196 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3197 kActive, &opts);
3198 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3199 kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003200 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3201
3202 ASSERT_TRUE(offer);
3203 ASSERT_EQ(2u, offer->contents().size());
3204 EXPECT_EQ("video", offer->contents()[0].name);
3205 EXPECT_EQ("audio", offer->contents()[1].name);
3206}
3207
3208// Test that different media sections using the same codec have same payload
3209// type.
3210TEST_F(MediaSessionDescriptionFactoryTest,
3211 PayloadTypesSharedByMediaSectionsOfSameType) {
3212 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003213 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3214 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3215 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3216 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003217 // Create an offer with two video sections using same codecs.
3218 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3219 ASSERT_TRUE(offer);
3220 ASSERT_EQ(2u, offer->contents().size());
3221 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003222 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003223 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003224 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003225 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3226 ASSERT_EQ(2u, vcd1->codecs().size());
3227 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3228 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3229 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3230 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3231
3232 // Create answer and negotiate the codecs.
3233 std::unique_ptr<SessionDescription> answer(
3234 f2_.CreateAnswer(offer.get(), opts, nullptr));
3235 ASSERT_TRUE(answer);
3236 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003237 vcd1 = answer->contents()[0].media_description()->as_video();
3238 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003239 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3240 ASSERT_EQ(1u, vcd1->codecs().size());
3241 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3242 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3243}
3244
3245// Test that the codec preference order per media section is respected in
3246// subsequent offer.
3247TEST_F(MediaSessionDescriptionFactoryTest,
3248 CreateOfferRespectsCodecPreferenceOrder) {
3249 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003250 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3251 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3252 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3253 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003254 // Create an offer with two video sections using same codecs.
3255 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3256 ASSERT_TRUE(offer);
3257 ASSERT_EQ(2u, offer->contents().size());
3258 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003259 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003260 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003261 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003262 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3263 EXPECT_EQ(video_codecs, vcd1->codecs());
3264 EXPECT_EQ(video_codecs, vcd2->codecs());
3265
3266 // Change the codec preference of the first video section and create a
3267 // follow-up offer.
3268 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3269 vcd1->set_codecs(video_codecs_reverse);
3270 std::unique_ptr<SessionDescription> updated_offer(
3271 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003272 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3273 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003274 // The video codec preference order should be respected.
3275 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3276 EXPECT_EQ(video_codecs, vcd2->codecs());
3277}
3278
3279// Test that the codec preference order per media section is respected in
3280// the answer.
3281TEST_F(MediaSessionDescriptionFactoryTest,
3282 CreateAnswerRespectsCodecPreferenceOrder) {
3283 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003284 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3285 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3286 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3287 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003288 // Create an offer with two video sections using same codecs.
3289 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3290 ASSERT_TRUE(offer);
3291 ASSERT_EQ(2u, offer->contents().size());
3292 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003293 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003294 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003295 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003296 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3297 EXPECT_EQ(video_codecs, vcd1->codecs());
3298 EXPECT_EQ(video_codecs, vcd2->codecs());
3299
3300 // Change the codec preference of the first video section and create an
3301 // answer.
3302 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3303 vcd1->set_codecs(video_codecs_reverse);
3304 std::unique_ptr<SessionDescription> answer(
3305 f1_.CreateAnswer(offer.get(), opts, nullptr));
Steve Antonb1c1de12017-12-21 15:14:30 -08003306 vcd1 = answer->contents()[0].media_description()->as_video();
3307 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003308 // The video codec preference order should be respected.
3309 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3310 EXPECT_EQ(video_codecs, vcd2->codecs());
3311}
3312
Zhi Huang6f367472017-11-22 13:20:02 -08003313// Test that when creating an answer, the codecs use local parameters instead of
3314// the remote ones.
3315TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3316 const std::string audio_param_name = "audio_param";
3317 const std::string audio_value1 = "audio_v1";
3318 const std::string audio_value2 = "audio_v2";
3319 const std::string video_param_name = "video_param";
3320 const std::string video_value1 = "video_v1";
3321 const std::string video_value2 = "video_v2";
3322
3323 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3324 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3325 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3326 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3327
3328 // Set the parameters for codecs.
3329 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3330 video_codecs1[0].SetParam(video_param_name, video_value1);
3331 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3332 video_codecs2[0].SetParam(video_param_name, video_value2);
3333
3334 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3335 f1_.set_video_codecs(video_codecs1);
3336 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3337 f2_.set_video_codecs(video_codecs2);
3338
3339 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003340 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3341 kActive, &opts);
3342 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3343 kActive, &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003344
3345 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3346 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003347 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3348 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003349 std::string value;
3350 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3351 EXPECT_EQ(audio_value1, value);
3352 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3353 EXPECT_EQ(video_value1, value);
3354
3355 std::unique_ptr<SessionDescription> answer(
3356 f2_.CreateAnswer(offer.get(), opts, nullptr));
3357 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003358 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3359 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003360 // Use the parameters from the local codecs.
3361 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3362 EXPECT_EQ(audio_value2, value);
3363 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3364 EXPECT_EQ(video_value2, value);
3365}
3366
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003367// Test that matching packetization-mode is part of the criteria for matching
3368// H264 codecs (in addition to profile-level-id). Previously, this was not the
3369// case, so the first H264 codec with the same profile-level-id would match and
3370// the payload type in the answer would be incorrect.
3371// This is a regression test for bugs.webrtc.org/8808
3372TEST_F(MediaSessionDescriptionFactoryTest,
3373 H264MatchCriteriaIncludesPacketizationMode) {
3374 // Create two H264 codecs with the same profile level ID and different
3375 // packetization modes.
3376 VideoCodec h264_pm0(96, "H264");
3377 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3378 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3379 VideoCodec h264_pm1(97, "H264");
3380 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3381 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3382
3383 // Offerer will send both codecs, answerer should choose the one with matching
3384 // packetization mode (and not the first one it sees).
3385 f1_.set_video_codecs({h264_pm0, h264_pm1});
3386 f2_.set_video_codecs({h264_pm1});
3387
3388 MediaSessionOptions opts;
3389 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3390 kActive, &opts);
3391
3392 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3393 ASSERT_TRUE(offer);
3394
3395 std::unique_ptr<SessionDescription> answer(
3396 f2_.CreateAnswer(offer.get(), opts, nullptr));
3397 ASSERT_TRUE(answer);
3398
3399 // Answer should have one negotiated codec with packetization-mode=1 using the
3400 // offered payload type.
3401 ASSERT_EQ(1u, answer->contents().size());
3402 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3403 ASSERT_EQ(1u, answer_vcd->codecs().size());
3404 auto answer_codec = answer_vcd->codecs()[0];
3405 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3406}
3407
zhihuangcf5b37c2016-05-05 11:44:35 -07003408class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3409 public:
3410 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003411 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3412 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003413 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3414 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003415 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3416 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003417 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3418 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3419 f1_.set_secure(SEC_ENABLED);
3420 f2_.set_secure(SEC_ENABLED);
3421 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003422 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003423 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003424 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003425 tdf1_.set_secure(SEC_ENABLED);
3426 tdf2_.set_secure(SEC_ENABLED);
3427 }
3428
3429 protected:
3430 MediaSessionDescriptionFactory f1_;
3431 MediaSessionDescriptionFactory f2_;
3432 TransportDescriptionFactory tdf1_;
3433 TransportDescriptionFactory tdf2_;
3434};
3435
3436TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3437 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003438 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003439 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3440 ASSERT_TRUE(offer.get() != nullptr);
3441 // Set the protocol for all the contents.
3442 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003443 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07003444 }
3445 std::unique_ptr<SessionDescription> answer(
3446 f2_.CreateAnswer(offer.get(), opts, nullptr));
3447 const ContentInfo* ac = answer->GetContentByName("audio");
3448 const ContentInfo* vc = answer->GetContentByName("video");
3449 ASSERT_TRUE(ac != nullptr);
3450 ASSERT_TRUE(vc != nullptr);
3451 EXPECT_FALSE(ac->rejected); // the offer is accepted
3452 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003453 const AudioContentDescription* acd = ac->media_description()->as_audio();
3454 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07003455 EXPECT_EQ(GetParam(), acd->protocol());
3456 EXPECT_EQ(GetParam(), vcd->protocol());
3457}
3458
3459INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3460 MediaProtocolTest,
3461 ::testing::ValuesIn(kMediaProtocols));
3462INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3463 MediaProtocolTest,
3464 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003465
3466TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3467 TransportDescriptionFactory tdf;
3468 MediaSessionDescriptionFactory sf(&tdf);
3469 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3470 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3471
3472 // The merged list of codecs should contain any send codecs that are also
3473 // nominally in the recieve codecs list. Payload types should be picked from
3474 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3475 // (set to 1). This equals what happens when the send codecs are used in an
3476 // offer and the receive codecs are used in the following answer.
3477 const std::vector<AudioCodec> sendrecv_codecs =
3478 MAKE_VECTOR(kAudioCodecsAnswer);
3479 const std::vector<AudioCodec> no_codecs;
3480
3481 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3482 << "Please don't change shared test data!";
3483 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3484 << "Please don't change shared test data!";
3485 // Alter iLBC send codec to have zero channels, to test that that is handled
3486 // properly.
3487 send_codecs[1].channels = 0;
3488
3489 // Alther iLBC receive codec to be lowercase, to test that case conversions
3490 // are handled properly.
3491 recv_codecs[2].name = "ilbc";
3492
3493 // Test proper merge
3494 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003495 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3496 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3497 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003498
3499 // Test empty send codecs list
3500 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003501 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3502 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3503 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003504
3505 // Test empty recv codecs list
3506 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003507 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3508 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3509 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003510
3511 // Test all empty codec lists
3512 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003513 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3514 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3515 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003516}
3517
3518namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003519// Compare the two vectors of codecs ignoring the payload type.
3520template <class Codec>
3521bool CodecsMatch(const std::vector<Codec>& codecs1,
3522 const std::vector<Codec>& codecs2) {
3523 if (codecs1.size() != codecs2.size()) {
3524 return false;
3525 }
3526
3527 for (size_t i = 0; i < codecs1.size(); ++i) {
3528 if (!codecs1[i].Matches(codecs2[i])) {
3529 return false;
3530 }
3531 }
3532 return true;
3533}
3534
Steve Anton4e70a722017-11-28 14:57:10 -08003535void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07003536 TransportDescriptionFactory tdf;
3537 MediaSessionDescriptionFactory sf(&tdf);
3538 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3539 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3540 const std::vector<AudioCodec> sendrecv_codecs =
3541 MAKE_VECTOR(kAudioCodecsAnswer);
3542 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003543
3544 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003545 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3546
Steve Anton4e70a722017-11-28 14:57:10 -08003547 if (direction == RtpTransceiverDirection::kSendRecv ||
3548 direction == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003549 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003550 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003551 }
ossu075af922016-06-14 03:29:38 -07003552
3553 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3554 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003555 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07003556
3557 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003558 // that the codecs put in are right. This happens when we neither want to
3559 // send nor receive audio. The checks are still in place if at some point
3560 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003561 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003562 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003563 // sendrecv and inactive should both present lists as if the channel was
3564 // to be used for sending and receiving. Inactive essentially means it
3565 // might eventually be used anything, but we don't know more at this
3566 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08003567 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003568 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08003569 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003570 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003571 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003572 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003573 }
3574 }
3575}
3576
3577static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003578 AudioCodec(0, "codec0", 16000, -1, 1),
3579 AudioCodec(1, "codec1", 8000, 13300, 1),
3580 AudioCodec(2, "codec2", 8000, 64000, 1),
3581 AudioCodec(3, "codec3", 8000, 64000, 1),
3582 AudioCodec(4, "codec4", 8000, 0, 2),
3583 AudioCodec(5, "codec5", 32000, 0, 1),
3584 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003585
zhihuang1c378ed2017-08-17 14:10:50 -07003586/* The codecs groups below are chosen as per the matrix below. The objective
3587 * is to have different sets of codecs in the inputs, to get unique sets of
3588 * codecs after negotiation, depending on offer and answer communication
3589 * directions. One-way directions in the offer should either result in the
3590 * opposite direction in the answer, or an inactive answer. Regardless, the
3591 * choice of codecs should be as if the answer contained the opposite
3592 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003593 *
3594 * | Offer | Answer | Result
3595 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3596 * 0 | x - - | - x - | x - - - -
3597 * 1 | x x x | - x - | x - - x -
3598 * 2 | - x - | x - - | - x - - -
3599 * 3 | x x x | x - - | - x x - -
3600 * 4 | - x - | x x x | - x - - -
3601 * 5 | x - - | x x x | x - - - -
3602 * 6 | x x x | x x x | x x x x x
3603 */
3604// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003605static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3606static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003607// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3608// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003609static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3610static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003611// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003612static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3613static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3614static const int kResultSendrecv_SendCodecs[] = {3, 6};
3615static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3616static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003617
3618template <typename T, int IDXS>
3619std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3620 std::vector<T> out;
3621 out.reserve(IDXS);
3622 for (int idx : indices)
3623 out.push_back(array[idx]);
3624
3625 return out;
3626}
3627
Steve Anton4e70a722017-11-28 14:57:10 -08003628void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
3629 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07003630 bool add_legacy_stream) {
3631 TransportDescriptionFactory offer_tdf;
3632 TransportDescriptionFactory answer_tdf;
3633 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3634 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3635 offer_factory.set_audio_codecs(
3636 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3637 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3638 answer_factory.set_audio_codecs(
3639 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3640 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3641
ossu075af922016-06-14 03:29:38 -07003642 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003643 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3644 &offer_opts);
3645
Steve Anton4e70a722017-11-28 14:57:10 -08003646 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003647 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003648 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003649 }
3650
3651 std::unique_ptr<SessionDescription> offer(
3652 offer_factory.CreateOffer(offer_opts, NULL));
3653 ASSERT_TRUE(offer.get() != NULL);
3654
3655 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003656 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3657 &answer_opts);
3658
Steve Anton4e70a722017-11-28 14:57:10 -08003659 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003660 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003661 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003662 }
3663 std::unique_ptr<SessionDescription> answer(
3664 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3665 const ContentInfo* ac = answer->GetContentByName("audio");
3666
zhihuang1c378ed2017-08-17 14:10:50 -07003667 // If the factory didn't add any audio content to the answer, we cannot
3668 // check that the codecs put in are right. This happens when we neither want
3669 // to send nor receive audio. The checks are still in place if at some point
3670 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003671 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003672 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
3673 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07003674
ossu075af922016-06-14 03:29:38 -07003675 std::vector<AudioCodec> target_codecs;
3676 // For offers with sendrecv or inactive, we should never reply with more
3677 // codecs than offered, with these codec sets.
3678 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08003679 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07003680 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3681 kResultSendrecv_SendrecvCodecs);
3682 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003683 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003684 target_codecs =
3685 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003686 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003687 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003688 target_codecs =
3689 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003690 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003691 case RtpTransceiverDirection::kSendRecv:
3692 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003693 target_codecs =
3694 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08003695 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003696 target_codecs =
3697 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003698 } else {
3699 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3700 kResultSendrecv_SendrecvCodecs);
3701 }
3702 break;
3703 }
3704
zhihuang1c378ed2017-08-17 14:10:50 -07003705 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02003706 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07003707 bool first = true;
3708 os << "{";
3709 for (const auto& c : codecs) {
3710 os << (first ? " " : ", ") << c.id;
3711 first = false;
3712 }
3713 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02003714 return os.Release();
ossu075af922016-06-14 03:29:38 -07003715 };
3716
3717 EXPECT_TRUE(acd->codecs() == target_codecs)
3718 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08003719 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
3720 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07003721 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08003722 << webrtc::RtpTransceiverDirectionToString(answer_direction)
3723 << "; got: "
3724 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07003725 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08003726 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07003727 << "Only inactive offers are allowed to not generate any audio "
3728 "content";
ossu075af922016-06-14 03:29:38 -07003729 }
3730}
brandtr03d5fb12016-11-22 03:37:59 -08003731
3732} // namespace
ossu075af922016-06-14 03:29:38 -07003733
3734class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08003735 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07003736
3737TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003738 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003739}
3740
3741INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3742 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003743 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3744 RtpTransceiverDirection::kRecvOnly,
3745 RtpTransceiverDirection::kSendRecv,
3746 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07003747
3748class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08003749 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
3750 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003751 bool>> {};
ossu075af922016-06-14 03:29:38 -07003752
3753TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003754 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3755 ::testing::get<1>(GetParam()),
3756 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003757}
3758
zhihuang1c378ed2017-08-17 14:10:50 -07003759INSTANTIATE_TEST_CASE_P(
3760 MediaSessionDescriptionFactoryTest,
3761 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003762 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
3763 RtpTransceiverDirection::kRecvOnly,
3764 RtpTransceiverDirection::kSendRecv,
3765 RtpTransceiverDirection::kInactive),
3766 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3767 RtpTransceiverDirection::kRecvOnly,
3768 RtpTransceiverDirection::kSendRecv,
3769 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07003770 ::testing::Bool()));