blob: 7162a3713c0133ef6c522389cb5ca48db9fc86ff [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
Johannes Kron0854eb62018-10-10 22:33:20 +02001584TEST_F(MediaSessionDescriptionFactoryTest,
1585 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1586 MediaSessionOptions opts;
1587 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1588 // Offer without request of mixed one- and two-byte header extensions.
1589 offer->set_mixed_one_two_byte_header_extensions_supported(false);
1590 ASSERT_TRUE(offer.get() != NULL);
1591 std::unique_ptr<SessionDescription> answer_no_support(
1592 f2_.CreateAnswer(offer.get(), opts, NULL));
1593 EXPECT_FALSE(
1594 answer_no_support->mixed_one_two_byte_header_extensions_supported());
1595
1596 // Offer with request of mixed one- and two-byte header extensions.
1597 offer->set_mixed_one_two_byte_header_extensions_supported(true);
1598 ASSERT_TRUE(offer.get() != NULL);
1599 std::unique_ptr<SessionDescription> answer_support(
1600 f2_.CreateAnswer(offer.get(), opts, NULL));
1601 EXPECT_TRUE(answer_support->mixed_one_two_byte_header_extensions_supported());
1602}
1603
1604TEST_F(MediaSessionDescriptionFactoryTest,
1605 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1606 MediaSessionOptions opts;
1607 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1608 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1609 MediaContentDescription* video_offer =
1610 offer->GetContentDescriptionByName("video");
1611 ASSERT_TRUE(video_offer);
1612 MediaContentDescription* audio_offer =
1613 offer->GetContentDescriptionByName("audio");
1614 ASSERT_TRUE(audio_offer);
1615
1616 // Explicit disable of mixed one-two byte header support in offer.
1617 video_offer->set_mixed_one_two_byte_header_extensions_supported(
1618 MediaContentDescription::kNo);
1619 audio_offer->set_mixed_one_two_byte_header_extensions_supported(
1620 MediaContentDescription::kNo);
1621
1622 ASSERT_TRUE(offer.get() != NULL);
1623 std::unique_ptr<SessionDescription> answer_no_support(
1624 f2_.CreateAnswer(offer.get(), opts, NULL));
1625 MediaContentDescription* video_answer =
1626 answer_no_support->GetContentDescriptionByName("video");
1627 MediaContentDescription* audio_answer =
1628 answer_no_support->GetContentDescriptionByName("audio");
1629 EXPECT_EQ(MediaContentDescription::kNo,
1630 video_answer->mixed_one_two_byte_header_extensions_supported());
1631 EXPECT_EQ(MediaContentDescription::kNo,
1632 audio_answer->mixed_one_two_byte_header_extensions_supported());
1633
1634 // Enable mixed one-two byte header support in offer.
1635 video_offer->set_mixed_one_two_byte_header_extensions_supported(
1636 MediaContentDescription::kMedia);
1637 audio_offer->set_mixed_one_two_byte_header_extensions_supported(
1638 MediaContentDescription::kMedia);
1639 ASSERT_TRUE(offer.get() != NULL);
1640 std::unique_ptr<SessionDescription> answer_support(
1641 f2_.CreateAnswer(offer.get(), opts, NULL));
1642 video_answer = answer_support->GetContentDescriptionByName("video");
1643 audio_answer = answer_support->GetContentDescriptionByName("audio");
1644 EXPECT_EQ(MediaContentDescription::kMedia,
1645 video_answer->mixed_one_two_byte_header_extensions_supported());
1646 EXPECT_EQ(MediaContentDescription::kMedia,
1647 audio_answer->mixed_one_two_byte_header_extensions_supported());
1648}
1649
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650// Create an audio and video offer with:
1651// - one video track
1652// - two audio tracks
1653// - two data tracks
1654// and ensure it matches what we expect. Also updates the initial offer by
1655// adding a new video track and replaces one of the audio tracks.
1656TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1657 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001658 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001659 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001660 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001661 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001662 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001663 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001664 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001665
Steve Anton4e70a722017-11-28 14:57:10 -08001666 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001667 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001668 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001669 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001670 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001671
1672 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001673 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001674
1675 ASSERT_TRUE(offer.get() != NULL);
1676 const ContentInfo* ac = offer->GetContentByName("audio");
1677 const ContentInfo* vc = offer->GetContentByName("video");
1678 const ContentInfo* dc = offer->GetContentByName("data");
1679 ASSERT_TRUE(ac != NULL);
1680 ASSERT_TRUE(vc != NULL);
1681 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001682 const AudioContentDescription* acd = ac->media_description()->as_audio();
1683 const VideoContentDescription* vcd = vc->media_description()->as_video();
1684 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001685 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001686 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001687
1688 const StreamParamsVec& audio_streams = acd->streams();
1689 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001690 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001691 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1692 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1693 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1694 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1695 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1696 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1697
1698 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1699 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001700 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001701
1702 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1703 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001704 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001705
1706 const StreamParamsVec& video_streams = vcd->streams();
1707 ASSERT_EQ(1U, video_streams.size());
1708 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1709 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1710 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1711 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1712
1713 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1714 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001715 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001716
1717 const StreamParamsVec& data_streams = dcd->streams();
1718 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001719 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001720 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1721 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1722 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1723 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1724 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1725 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1726
1727 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001728 dcd->bandwidth()); // default bandwidth (auto)
1729 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001730 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732 // Update the offer. Add a new video track that is not synched to the
1733 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001734 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001735 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001736 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1737 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001738 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001739 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1740 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001741 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001742 std::unique_ptr<SessionDescription> updated_offer(
1743 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744
1745 ASSERT_TRUE(updated_offer.get() != NULL);
1746 ac = updated_offer->GetContentByName("audio");
1747 vc = updated_offer->GetContentByName("video");
1748 dc = updated_offer->GetContentByName("data");
1749 ASSERT_TRUE(ac != NULL);
1750 ASSERT_TRUE(vc != NULL);
1751 ASSERT_TRUE(dc != NULL);
1752 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001753 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001754 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001755 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001756 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001757 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001758
1759 EXPECT_EQ(acd->type(), updated_acd->type());
1760 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1761 EXPECT_EQ(vcd->type(), updated_vcd->type());
1762 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1763 EXPECT_EQ(dcd->type(), updated_dcd->type());
1764 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001765 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001766 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001767 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001768 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001769 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001770 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1771
1772 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1773 ASSERT_EQ(2U, updated_audio_streams.size());
1774 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1775 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1776 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1777 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1778 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1779
1780 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1781 ASSERT_EQ(2U, updated_video_streams.size());
1782 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1783 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001784 // All the media streams in one PeerConnection share one RTCP CNAME.
1785 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001786
1787 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1788 ASSERT_EQ(2U, updated_data_streams.size());
1789 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1790 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1791 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1792 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1793 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001794 // The stream correctly got the CNAME from the MediaSessionOptions.
1795 // The Expected RTCP CNAME is the default one as we are using the default
1796 // MediaSessionOptions.
1797 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001798}
1799
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001800// Create an offer with simulcast video stream.
1801TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1802 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001803 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1804 kActive, &opts);
1805 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1806 kActive, &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001807 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001808 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001809 {kMediaStream1}, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001810 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001811
1812 ASSERT_TRUE(offer.get() != NULL);
1813 const ContentInfo* vc = offer->GetContentByName("video");
1814 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001815 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001816
1817 const StreamParamsVec& video_streams = vcd->streams();
1818 ASSERT_EQ(1U, video_streams.size());
1819 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1820 const SsrcGroup* sim_ssrc_group =
1821 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1822 ASSERT_TRUE(sim_ssrc_group != NULL);
1823 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1824}
1825
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001826// Create an audio and video answer to a standard video offer with:
1827// - one video track
1828// - two audio tracks
1829// - two data tracks
1830// and ensure it matches what we expect. Also updates the initial answer by
1831// adding a new video track and removes one of the audio tracks.
1832TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1833 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001834 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1835 kActive, &offer_opts);
1836 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1837 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001838 offer_opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001839 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1840 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001841 f1_.set_secure(SEC_ENABLED);
1842 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001843 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001844
zhihuang1c378ed2017-08-17 14:10:50 -07001845 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001846 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
1847 kActive, &answer_opts);
1848 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1849 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001850 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001851 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001852 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001853 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001854 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001855 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001856
Steve Anton4e70a722017-11-28 14:57:10 -08001857 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
1858 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001859 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001860 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001861 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001862 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001863 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001864
kwiberg31022942016-03-11 14:18:21 -08001865 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001866 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001867
1868 ASSERT_TRUE(answer.get() != NULL);
1869 const ContentInfo* ac = answer->GetContentByName("audio");
1870 const ContentInfo* vc = answer->GetContentByName("video");
1871 const ContentInfo* dc = answer->GetContentByName("data");
1872 ASSERT_TRUE(ac != NULL);
1873 ASSERT_TRUE(vc != NULL);
1874 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001875 const AudioContentDescription* acd = ac->media_description()->as_audio();
1876 const VideoContentDescription* vcd = vc->media_description()->as_video();
1877 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001878 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1879 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1880 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001881
1882 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1883 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1884
1885 const StreamParamsVec& audio_streams = acd->streams();
1886 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001887 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001888 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1889 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1890 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1891 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1892 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1893 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1894
1895 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1896 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1897
1898 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1899 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1900
1901 const StreamParamsVec& video_streams = vcd->streams();
1902 ASSERT_EQ(1U, video_streams.size());
1903 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1904 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1905 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1906 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1907
1908 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1909 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1910
1911 const StreamParamsVec& data_streams = dcd->streams();
1912 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001913 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001914 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1915 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1916 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1917 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1918 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1919 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1920
1921 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001922 dcd->bandwidth()); // default bandwidth (auto)
1923 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001924
1925 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001926 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001927 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001928 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001929 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1930 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001931 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001932 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001933
1934 ASSERT_TRUE(updated_answer.get() != NULL);
1935 ac = updated_answer->GetContentByName("audio");
1936 vc = updated_answer->GetContentByName("video");
1937 dc = updated_answer->GetContentByName("data");
1938 ASSERT_TRUE(ac != NULL);
1939 ASSERT_TRUE(vc != NULL);
1940 ASSERT_TRUE(dc != NULL);
1941 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001942 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001943 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001944 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001945 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001946 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001947
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001948 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001949 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001950 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001952 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1954
1955 EXPECT_EQ(acd->type(), updated_acd->type());
1956 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1957 EXPECT_EQ(vcd->type(), updated_vcd->type());
1958 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1959 EXPECT_EQ(dcd->type(), updated_dcd->type());
1960 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1961
1962 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1963 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001964 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965
1966 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1967 ASSERT_EQ(2U, updated_video_streams.size());
1968 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1969 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001970 // All media streams in one PeerConnection share one CNAME.
1971 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001972
1973 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1974 ASSERT_EQ(1U, updated_data_streams.size());
1975 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1976}
1977
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001978// Create an updated offer after creating an answer to the original offer and
1979// verify that the codecs that were part of the original answer are not changed
1980// in the updated offer.
1981TEST_F(MediaSessionDescriptionFactoryTest,
1982 RespondentCreatesOfferAfterCreatingAnswer) {
1983 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001984 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001985
kwiberg31022942016-03-11 14:18:21 -08001986 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1987 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001988 f2_.CreateAnswer(offer.get(), opts, NULL));
1989
1990 const AudioContentDescription* acd =
1991 GetFirstAudioContentDescription(answer.get());
1992 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1993
1994 const VideoContentDescription* vcd =
1995 GetFirstVideoContentDescription(answer.get());
1996 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1997
kwiberg31022942016-03-11 14:18:21 -08001998 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999 f2_.CreateOffer(opts, answer.get()));
2000
2001 // The expected audio codecs are the common audio codecs from the first
2002 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2003 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002004 // TODO(wu): |updated_offer| should not include the codec
2005 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002006 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002007 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008 };
2009
2010 // The expected video codecs are the common video codecs from the first
2011 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2012 // preference order.
2013 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002014 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002015 };
2016
2017 const AudioContentDescription* updated_acd =
2018 GetFirstAudioContentDescription(updated_offer.get());
2019 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
2020
2021 const VideoContentDescription* updated_vcd =
2022 GetFirstVideoContentDescription(updated_offer.get());
2023 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
2024}
2025
2026// Create an updated offer after creating an answer to the original offer and
2027// verify that the codecs that were part of the original answer are not changed
2028// in the updated offer. In this test Rtx is enabled.
2029TEST_F(MediaSessionDescriptionFactoryTest,
2030 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2031 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002032 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2033 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002035 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002036 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002037 f1_.set_video_codecs(f1_codecs);
2038
2039 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002040 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002041 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002042 f2_.set_video_codecs(f2_codecs);
2043
kwiberg31022942016-03-11 14:18:21 -08002044 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002045 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002046 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047 f2_.CreateAnswer(offer.get(), opts, NULL));
2048
2049 const VideoContentDescription* vcd =
2050 GetFirstVideoContentDescription(answer.get());
2051
2052 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002053 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2054 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002055
2056 EXPECT_EQ(expected_codecs, vcd->codecs());
2057
deadbeef67cf2c12016-04-13 10:07:16 -07002058 // Now, make sure we get same result (except for the order) if |f2_| creates
2059 // an updated offer even though the default payload types between |f1_| and
2060 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002061 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002062 f2_.CreateOffer(opts, answer.get()));
2063 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002064 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2066
2067 const VideoContentDescription* updated_vcd =
2068 GetFirstVideoContentDescription(updated_answer.get());
2069
2070 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2071}
2072
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002073// Regression test for:
2074// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2075// Existing codecs should always appear before new codecs in re-offers. But
2076// under a specific set of circumstances, the existing RTX codec was ending up
2077// added to the end of the list.
2078TEST_F(MediaSessionDescriptionFactoryTest,
2079 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2080 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002081 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2082 kActive, &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002083 // We specifically choose different preferred payload types for VP8 to
2084 // trigger the issue.
2085 cricket::VideoCodec vp8_offerer(100, "VP8");
2086 cricket::VideoCodec vp8_offerer_rtx =
2087 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2088 cricket::VideoCodec vp8_answerer(110, "VP8");
2089 cricket::VideoCodec vp8_answerer_rtx =
2090 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2091 cricket::VideoCodec vp9(120, "VP9");
2092 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2093
2094 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2095 // We also specifically cause the answerer to prefer VP9, such that if it
2096 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2097 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2098 vp8_answerer_rtx};
2099
2100 f1_.set_video_codecs(f1_codecs);
2101 f2_.set_video_codecs(f2_codecs);
2102 std::vector<AudioCodec> audio_codecs;
2103 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2104 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2105
2106 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
2107 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2108 ASSERT_TRUE(offer.get() != NULL);
2109 std::unique_ptr<SessionDescription> answer(
2110 f2_.CreateAnswer(offer.get(), opts, NULL));
2111
2112 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2113 // But if the bug is triggered, RTX for VP8 ends up last.
2114 std::unique_ptr<SessionDescription> updated_offer(
2115 f2_.CreateOffer(opts, answer.get()));
2116
2117 const VideoContentDescription* vcd =
2118 GetFirstVideoContentDescription(updated_offer.get());
2119 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2120 ASSERT_EQ(4u, codecs.size());
2121 EXPECT_EQ(vp8_offerer, codecs[0]);
2122 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2123 EXPECT_EQ(vp9, codecs[2]);
2124 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002125}
2126
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002127// Create an updated offer that adds video after creating an audio only answer
2128// to the original offer. This test verifies that if a video codec and the RTX
2129// codec have the same default payload type as an audio codec that is already in
2130// use, the added codecs payload types are changed.
2131TEST_F(MediaSessionDescriptionFactoryTest,
2132 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2133 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002134 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002135 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002136 f1_.set_video_codecs(f1_codecs);
2137
2138 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002139 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2140 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002141
kwiberg31022942016-03-11 14:18:21 -08002142 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2143 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002144 f2_.CreateAnswer(offer.get(), opts, NULL));
2145
2146 const AudioContentDescription* acd =
2147 GetFirstAudioContentDescription(answer.get());
2148 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2149
2150 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2151 // reference be the same as an audio codec that was negotiated in the
2152 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002153 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002154 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155
2156 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2157 int used_pl_type = acd->codecs()[0].id;
2158 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002159 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002160 f2_.set_video_codecs(f2_codecs);
2161
kwiberg31022942016-03-11 14:18:21 -08002162 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002163 f2_.CreateOffer(opts, answer.get()));
2164 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002165 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002166 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2167
2168 const AudioContentDescription* updated_acd =
2169 GetFirstAudioContentDescription(answer.get());
2170 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2171
2172 const VideoContentDescription* updated_vcd =
2173 GetFirstVideoContentDescription(updated_answer.get());
2174
2175 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002176 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002177 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178 EXPECT_NE(used_pl_type, new_h264_pl_type);
2179 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002180 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002181 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2182 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2183}
2184
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002185// Create an updated offer with RTX after creating an answer to an offer
2186// without RTX, and with different default payload types.
2187// Verify that the added RTX codec references the correct payload type.
2188TEST_F(MediaSessionDescriptionFactoryTest,
2189 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2190 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002191 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002192
2193 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2194 // This creates rtx for H264 with the payload type |f2_| uses.
2195 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2196 f2_.set_video_codecs(f2_codecs);
2197
kwiberg31022942016-03-11 14:18:21 -08002198 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002199 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002200 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002201 f2_.CreateAnswer(offer.get(), opts, nullptr));
2202
2203 const VideoContentDescription* vcd =
2204 GetFirstVideoContentDescription(answer.get());
2205
2206 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2207 EXPECT_EQ(expected_codecs, vcd->codecs());
2208
2209 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2210 // updated offer, even though the default payload types are different from
2211 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002212 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002213 f2_.CreateOffer(opts, answer.get()));
2214 ASSERT_TRUE(updated_offer);
2215
2216 const VideoContentDescription* updated_vcd =
2217 GetFirstVideoContentDescription(updated_offer.get());
2218
2219 // New offer should attempt to add H263, and RTX for H264.
2220 expected_codecs.push_back(kVideoCodecs2[1]);
2221 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2222 &expected_codecs);
2223 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2224}
2225
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002226// Test that RTX is ignored when there is no associated payload type parameter.
2227TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2228 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002229 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2230 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002231 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002232 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002233 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002234 f1_.set_video_codecs(f1_codecs);
2235
2236 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002237 // This creates RTX for H264 with the payload type |f2_| uses.
2238 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239 f2_.set_video_codecs(f2_codecs);
2240
kwiberg31022942016-03-11 14:18:21 -08002241 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002242 ASSERT_TRUE(offer.get() != NULL);
2243 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2244 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2245 // is possible to test that that RTX is dropped when
2246 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002247 MediaContentDescription* media_desc =
2248 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2249 ASSERT_TRUE(media_desc);
2250 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002251 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002252 for (VideoCodec& codec : codecs) {
2253 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2254 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002255 }
2256 }
2257 desc->set_codecs(codecs);
2258
kwiberg31022942016-03-11 14:18:21 -08002259 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002260 f2_.CreateAnswer(offer.get(), opts, NULL));
2261
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002262 std::vector<std::string> codec_names =
2263 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2264 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2265 cricket::kRtxCodecName));
2266}
2267
2268// Test that RTX will be filtered out in the answer if its associated payload
2269// type doesn't match the local value.
2270TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2271 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002272 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2273 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002274 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2275 // This creates RTX for H264 in sender.
2276 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2277 f1_.set_video_codecs(f1_codecs);
2278
2279 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2280 // This creates RTX for H263 in receiver.
2281 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2282 f2_.set_video_codecs(f2_codecs);
2283
kwiberg31022942016-03-11 14:18:21 -08002284 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002285 ASSERT_TRUE(offer.get() != NULL);
2286 // Associated payload type doesn't match, therefore, RTX codec is removed in
2287 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002288 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002289 f2_.CreateAnswer(offer.get(), opts, NULL));
2290
2291 std::vector<std::string> codec_names =
2292 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2293 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2294 cricket::kRtxCodecName));
2295}
2296
2297// Test that when multiple RTX codecs are offered, only the matched RTX codec
2298// is added in the answer, and the unsupported RTX codec is filtered out.
2299TEST_F(MediaSessionDescriptionFactoryTest,
2300 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2301 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002302 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2303 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002304 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2305 // This creates RTX for H264-SVC in sender.
2306 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2307 f1_.set_video_codecs(f1_codecs);
2308
2309 // This creates RTX for H264 in sender.
2310 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2311 f1_.set_video_codecs(f1_codecs);
2312
2313 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2314 // This creates RTX for H264 in receiver.
2315 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2316 f2_.set_video_codecs(f2_codecs);
2317
2318 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2319 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002320 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002321 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002322 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002323 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002324 const VideoContentDescription* vcd =
2325 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002326 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2327 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2328 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002329
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002330 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002331}
2332
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002333// Test that after one RTX codec has been negotiated, a new offer can attempt
2334// to add another.
2335TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2336 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002337 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2338 kActive, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002339 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2340 // This creates RTX for H264 for the offerer.
2341 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2342 f1_.set_video_codecs(f1_codecs);
2343
kwiberg31022942016-03-11 14:18:21 -08002344 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002345 ASSERT_TRUE(offer);
2346 const VideoContentDescription* vcd =
2347 GetFirstVideoContentDescription(offer.get());
2348
2349 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2350 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2351 &expected_codecs);
2352 EXPECT_EQ(expected_codecs, vcd->codecs());
2353
2354 // Now, attempt to add RTX for H264-SVC.
2355 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2356 f1_.set_video_codecs(f1_codecs);
2357
kwiberg31022942016-03-11 14:18:21 -08002358 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002359 f1_.CreateOffer(opts, offer.get()));
2360 ASSERT_TRUE(updated_offer);
2361 vcd = GetFirstVideoContentDescription(updated_offer.get());
2362
2363 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2364 &expected_codecs);
2365 EXPECT_EQ(expected_codecs, vcd->codecs());
2366}
2367
Noah Richards2e7a0982015-05-18 14:02:54 -07002368// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2369// generated for each simulcast ssrc and correctly grouped.
2370TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2371 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002372 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2373 kActive, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002374 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002375 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002376 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002377
2378 // Use a single real codec, and then add RTX for it.
2379 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002380 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002381 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2382 f1_.set_video_codecs(f1_codecs);
2383
2384 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2385 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002386 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002387 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002388 MediaContentDescription* media_desc =
2389 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2390 ASSERT_TRUE(media_desc);
2391 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002392 const StreamParamsVec& streams = desc->streams();
2393 // Single stream.
2394 ASSERT_EQ(1u, streams.size());
2395 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2396 EXPECT_EQ(6u, streams[0].ssrcs.size());
2397 // And should have a SIM group for the simulcast.
2398 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2399 // And a FID group for RTX.
2400 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002401 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002402 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2403 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002404 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002405 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2406 EXPECT_EQ(3u, fid_ssrcs.size());
2407}
2408
brandtr03d5fb12016-11-22 03:37:59 -08002409// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2410// together with a FEC-FR grouping.
2411TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2412 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002413 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2414 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002415 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002416 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002417 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002418
2419 // Use a single real codec, and then add FlexFEC for it.
2420 std::vector<VideoCodec> f1_codecs;
2421 f1_codecs.push_back(VideoCodec(97, "H264"));
2422 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2423 f1_.set_video_codecs(f1_codecs);
2424
2425 // Ensure that the offer has a single FlexFEC ssrc and that
2426 // there is no FEC-FR ssrc + grouping for each.
2427 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2428 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002429 MediaContentDescription* media_desc =
2430 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2431 ASSERT_TRUE(media_desc);
2432 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002433 const StreamParamsVec& streams = desc->streams();
2434 // Single stream.
2435 ASSERT_EQ(1u, streams.size());
2436 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2437 EXPECT_EQ(2u, streams[0].ssrcs.size());
2438 // And should have a FEC-FR group for FlexFEC.
2439 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2440 std::vector<uint32_t> primary_ssrcs;
2441 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2442 ASSERT_EQ(1u, primary_ssrcs.size());
2443 uint32_t flexfec_ssrc;
2444 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2445 EXPECT_NE(flexfec_ssrc, 0u);
2446}
2447
2448// Test that FlexFEC is disabled for simulcast.
2449// TODO(brandtr): Remove this test when we support simulcast, either through
2450// multiple FlexfecSenders, or through multistream protection.
2451TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2452 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002453 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2454 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002455 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002456 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002457 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002458
2459 // Use a single real codec, and then add FlexFEC for it.
2460 std::vector<VideoCodec> f1_codecs;
2461 f1_codecs.push_back(VideoCodec(97, "H264"));
2462 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2463 f1_.set_video_codecs(f1_codecs);
2464
2465 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2466 // there is no FEC-FR ssrc + grouping for each.
2467 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2468 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002469 MediaContentDescription* media_desc =
2470 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2471 ASSERT_TRUE(media_desc);
2472 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002473 const StreamParamsVec& streams = desc->streams();
2474 // Single stream.
2475 ASSERT_EQ(1u, streams.size());
2476 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2477 EXPECT_EQ(3u, streams[0].ssrcs.size());
2478 // And should have a SIM group for the simulcast.
2479 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2480 // And not a FEC-FR group for FlexFEC.
2481 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2482 std::vector<uint32_t> primary_ssrcs;
2483 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2484 EXPECT_EQ(3u, primary_ssrcs.size());
2485 for (uint32_t primary_ssrc : primary_ssrcs) {
2486 uint32_t flexfec_ssrc;
2487 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2488 }
2489}
2490
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002491// Create an updated offer after creating an answer to the original offer and
2492// verify that the RTP header extensions that were part of the original answer
2493// are not changed in the updated offer.
2494TEST_F(MediaSessionDescriptionFactoryTest,
2495 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2496 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002497 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002498
2499 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2500 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2501 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2502 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2503
kwiberg31022942016-03-11 14:18:21 -08002504 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2505 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002506 f2_.CreateAnswer(offer.get(), opts, NULL));
2507
Yves Gerey665174f2018-06-19 15:03:05 +02002508 EXPECT_EQ(
2509 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2510 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2511 EXPECT_EQ(
2512 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2513 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514
kwiberg31022942016-03-11 14:18:21 -08002515 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002516 f2_.CreateOffer(opts, answer.get()));
2517
2518 // The expected RTP header extensions in the new offer are the resulting
2519 // extensions from the first offer/answer exchange plus the extensions only
2520 // |f2_| offer.
2521 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002522 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002523 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2524 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2525 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526 };
2527
2528 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002529 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002530 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2531 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2532 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002533 };
2534
2535 const AudioContentDescription* updated_acd =
2536 GetFirstAudioContentDescription(updated_offer.get());
2537 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2538 updated_acd->rtp_header_extensions());
2539
2540 const VideoContentDescription* updated_vcd =
2541 GetFirstVideoContentDescription(updated_offer.get());
2542 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2543 updated_vcd->rtp_header_extensions());
2544}
2545
deadbeefa5b273a2015-08-20 17:30:13 -07002546// Verify that if the same RTP extension URI is used for audio and video, the
2547// same ID is used. Also verify that the ID isn't changed when creating an
2548// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002549TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002550 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002551 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002552
2553 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2554 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2555
kwiberg31022942016-03-11 14:18:21 -08002556 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002557
2558 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2559 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002560 const RtpExtension kExpectedVideoRtpExtension[] = {
2561 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002562 };
2563
Yves Gerey665174f2018-06-19 15:03:05 +02002564 EXPECT_EQ(
2565 MAKE_VECTOR(kAudioRtpExtension3),
2566 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2567 EXPECT_EQ(
2568 MAKE_VECTOR(kExpectedVideoRtpExtension),
2569 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002570
2571 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002572 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002573 f1_.CreateOffer(opts, offer.get()));
2574
2575 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02002576 GetFirstAudioContentDescription(updated_offer.get())
2577 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002578 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002579 GetFirstVideoContentDescription(updated_offer.get())
2580 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002581}
2582
jbauch5869f502017-06-29 12:31:36 -07002583// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2584TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2585 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002586 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002587
2588 f1_.set_enable_encrypted_rtp_header_extensions(true);
2589 f2_.set_enable_encrypted_rtp_header_extensions(true);
2590
2591 f1_.set_audio_rtp_header_extensions(
2592 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2593 f1_.set_video_rtp_header_extensions(
2594 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2595
2596 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2597
2598 // The extensions that are shared between audio and video should use the same
2599 // id.
2600 const RtpExtension kExpectedVideoRtpExtension[] = {
2601 kVideoRtpExtension3ForEncryption[0],
2602 kAudioRtpExtension3ForEncryptionOffer[1],
2603 kAudioRtpExtension3ForEncryptionOffer[2],
2604 };
2605
Yves Gerey665174f2018-06-19 15:03:05 +02002606 EXPECT_EQ(
2607 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2608 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2609 EXPECT_EQ(
2610 MAKE_VECTOR(kExpectedVideoRtpExtension),
2611 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002612
2613 // Nothing should change when creating a new offer
2614 std::unique_ptr<SessionDescription> updated_offer(
2615 f1_.CreateOffer(opts, offer.get()));
2616
2617 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02002618 GetFirstAudioContentDescription(updated_offer.get())
2619 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002620 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002621 GetFirstVideoContentDescription(updated_offer.get())
2622 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002623}
2624
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002625TEST(MediaSessionDescription, CopySessionDescription) {
2626 SessionDescription source;
2627 cricket::ContentGroup group(cricket::CN_AUDIO);
2628 source.AddGroup(group);
2629 AudioContentDescription* acd(new AudioContentDescription());
2630 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2631 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08002632 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002633 VideoContentDescription* vcd(new VideoContentDescription());
2634 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2635 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08002636 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002637
kwiberg31022942016-03-11 14:18:21 -08002638 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639 ASSERT_TRUE(copy.get() != NULL);
2640 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2641 const ContentInfo* ac = copy->GetContentByName("audio");
2642 const ContentInfo* vc = copy->GetContentByName("video");
2643 ASSERT_TRUE(ac != NULL);
2644 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08002645 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002646 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002647 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2648 EXPECT_EQ(1u, acd->first_ssrc());
2649
Steve Anton5adfafd2017-12-20 16:34:00 -08002650 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002651 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002652 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2653 EXPECT_EQ(2u, vcd->first_ssrc());
2654}
2655
2656// The below TestTransportInfoXXX tests create different offers/answers, and
2657// ensure the TransportInfo in the SessionDescription matches what we expect.
2658TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2659 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002660 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2661 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002662 TestTransportInfo(true, options, false);
2663}
2664
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002665TEST_F(MediaSessionDescriptionFactoryTest,
2666 TestTransportInfoOfferIceRenomination) {
2667 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002668 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2669 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002670 options.media_description_options[0]
2671 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002672 TestTransportInfo(true, options, false);
2673}
2674
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002675TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2676 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002677 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2678 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002679 TestTransportInfo(true, options, true);
2680}
2681
2682TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2683 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002684 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2685 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2686 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002687 TestTransportInfo(true, options, false);
2688}
2689
2690TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002691 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002692 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002693 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2694 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2695 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696 TestTransportInfo(true, options, true);
2697}
2698
2699TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2700 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002701 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2702 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2703 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002704 options.bundle_enabled = true;
2705 TestTransportInfo(true, options, false);
2706}
2707
2708TEST_F(MediaSessionDescriptionFactoryTest,
2709 TestTransportInfoOfferBundleCurrent) {
2710 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002711 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2712 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2713 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714 options.bundle_enabled = true;
2715 TestTransportInfo(true, options, true);
2716}
2717
2718TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2719 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002720 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2721 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002722 TestTransportInfo(false, options, false);
2723}
2724
2725TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002726 TestTransportInfoAnswerIceRenomination) {
2727 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002728 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2729 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002730 options.media_description_options[0]
2731 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002732 TestTransportInfo(false, options, false);
2733}
2734
2735TEST_F(MediaSessionDescriptionFactoryTest,
2736 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002738 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2739 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002740 TestTransportInfo(false, options, true);
2741}
2742
2743TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2744 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002745 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2746 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2747 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002748 TestTransportInfo(false, options, false);
2749}
2750
2751TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002752 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002753 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002754 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2755 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2756 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002757 TestTransportInfo(false, options, true);
2758}
2759
2760TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2761 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002762 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2763 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2764 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765 options.bundle_enabled = true;
2766 TestTransportInfo(false, options, false);
2767}
2768
2769TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002770 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002771 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002772 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2773 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2774 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002775 options.bundle_enabled = true;
2776 TestTransportInfo(false, options, true);
2777}
2778
2779// Create an offer with bundle enabled and verify the crypto parameters are
2780// the common set of the available cryptos.
2781TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2782 TestCryptoWithBundle(true);
2783}
2784
2785// Create an answer with bundle enabled and verify the crypto parameters are
2786// the common set of the available cryptos.
2787TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2788 TestCryptoWithBundle(false);
2789}
2790
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002791// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2792// DTLS is not enabled locally.
2793TEST_F(MediaSessionDescriptionFactoryTest,
2794 TestOfferDtlsSavpfWithoutDtlsFailed) {
2795 f1_.set_secure(SEC_ENABLED);
2796 f2_.set_secure(SEC_ENABLED);
2797 tdf1_.set_secure(SEC_DISABLED);
2798 tdf2_.set_secure(SEC_DISABLED);
2799
kwiberg31022942016-03-11 14:18:21 -08002800 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002801 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002802 ASSERT_TRUE(offer.get() != NULL);
2803 ContentInfo* offer_content = offer->GetContentByName("audio");
2804 ASSERT_TRUE(offer_content != NULL);
2805 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002806 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002807 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2808
kwiberg31022942016-03-11 14:18:21 -08002809 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002810 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002811 ASSERT_TRUE(answer != NULL);
2812 ContentInfo* answer_content = answer->GetContentByName("audio");
2813 ASSERT_TRUE(answer_content != NULL);
2814
2815 ASSERT_TRUE(answer_content->rejected);
2816}
2817
2818// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2819// UDP/TLS/RTP/SAVPF.
2820TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2821 f1_.set_secure(SEC_ENABLED);
2822 f2_.set_secure(SEC_ENABLED);
2823 tdf1_.set_secure(SEC_ENABLED);
2824 tdf2_.set_secure(SEC_ENABLED);
2825
kwiberg31022942016-03-11 14:18:21 -08002826 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002827 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002828 ASSERT_TRUE(offer.get() != NULL);
2829 ContentInfo* offer_content = offer->GetContentByName("audio");
2830 ASSERT_TRUE(offer_content != NULL);
2831 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002832 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002833 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2834
kwiberg31022942016-03-11 14:18:21 -08002835 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002836 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002837 ASSERT_TRUE(answer != NULL);
2838
2839 const ContentInfo* answer_content = answer->GetContentByName("audio");
2840 ASSERT_TRUE(answer_content != NULL);
2841 ASSERT_FALSE(answer_content->rejected);
2842
2843 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002844 answer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002845 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
Yves Gerey665174f2018-06-19 15:03:05 +02002846 answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002847}
2848
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002849// Test that we include both SDES and DTLS in the offer, but only include SDES
2850// in the answer if DTLS isn't negotiated.
2851TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2852 f1_.set_secure(SEC_ENABLED);
2853 f2_.set_secure(SEC_ENABLED);
2854 tdf1_.set_secure(SEC_ENABLED);
2855 tdf2_.set_secure(SEC_DISABLED);
2856 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002857 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002858 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002859 const cricket::MediaContentDescription* audio_media_desc;
2860 const cricket::MediaContentDescription* video_media_desc;
2861 const cricket::TransportDescription* audio_trans_desc;
2862 const cricket::TransportDescription* video_trans_desc;
2863
2864 // Generate an offer with SDES and DTLS support.
2865 offer.reset(f1_.CreateOffer(options, NULL));
2866 ASSERT_TRUE(offer.get() != NULL);
2867
Steve Antonb1c1de12017-12-21 15:14:30 -08002868 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002869 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002870 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002871 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002872 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002873 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2874
2875 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2876 ASSERT_TRUE(audio_trans_desc != NULL);
2877 video_trans_desc = offer->GetTransportDescriptionByName("video");
2878 ASSERT_TRUE(video_trans_desc != NULL);
2879 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2880 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2881
2882 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2883 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2884 ASSERT_TRUE(answer.get() != NULL);
2885
Steve Antonb1c1de12017-12-21 15:14:30 -08002886 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002887 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002888 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002889 ASSERT_TRUE(video_media_desc != NULL);
2890 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2891 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2892
2893 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2894 ASSERT_TRUE(audio_trans_desc != NULL);
2895 video_trans_desc = answer->GetTransportDescriptionByName("video");
2896 ASSERT_TRUE(video_trans_desc != NULL);
2897 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2898 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2899
2900 // Enable DTLS; the answer should now only have DTLS support.
2901 tdf2_.set_secure(SEC_ENABLED);
2902 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2903 ASSERT_TRUE(answer.get() != NULL);
2904
Steve Antonb1c1de12017-12-21 15:14:30 -08002905 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002906 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002907 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002908 ASSERT_TRUE(video_media_desc != NULL);
2909 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2910 EXPECT_TRUE(video_media_desc->cryptos().empty());
2911 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2912 audio_media_desc->protocol());
2913 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2914 video_media_desc->protocol());
2915
2916 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2917 ASSERT_TRUE(audio_trans_desc != NULL);
2918 video_trans_desc = answer->GetTransportDescriptionByName("video");
2919 ASSERT_TRUE(video_trans_desc != NULL);
2920 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2921 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002922
2923 // Try creating offer again. DTLS enabled now, crypto's should be empty
2924 // in new offer.
2925 offer.reset(f1_.CreateOffer(options, offer.get()));
2926 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002927 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002928 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002929 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002930 ASSERT_TRUE(video_media_desc != NULL);
2931 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2932 EXPECT_TRUE(video_media_desc->cryptos().empty());
2933
2934 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2935 ASSERT_TRUE(audio_trans_desc != NULL);
2936 video_trans_desc = offer->GetTransportDescriptionByName("video");
2937 ASSERT_TRUE(video_trans_desc != NULL);
2938 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2939 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002940}
2941
2942// Test that an answer can't be created if cryptos are required but the offer is
2943// unsecure.
2944TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002945 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002946 f1_.set_secure(SEC_DISABLED);
2947 tdf1_.set_secure(SEC_DISABLED);
2948 f2_.set_secure(SEC_REQUIRED);
2949 tdf1_.set_secure(SEC_ENABLED);
2950
kwiberg31022942016-03-11 14:18:21 -08002951 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002952 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002953 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002954 f2_.CreateAnswer(offer.get(), options, NULL));
2955 EXPECT_TRUE(answer.get() == NULL);
2956}
2957
2958// Test that we accept a DTLS offer without SDES and create an appropriate
2959// answer.
2960TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2961 f1_.set_secure(SEC_DISABLED);
2962 f2_.set_secure(SEC_ENABLED);
2963 tdf1_.set_secure(SEC_ENABLED);
2964 tdf2_.set_secure(SEC_ENABLED);
2965 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002966 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2967 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2968 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002969
kwiberg31022942016-03-11 14:18:21 -08002970 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002971
2972 // Generate an offer with DTLS but without SDES.
2973 offer.reset(f1_.CreateOffer(options, NULL));
2974 ASSERT_TRUE(offer.get() != NULL);
2975
2976 const AudioContentDescription* audio_offer =
2977 GetFirstAudioContentDescription(offer.get());
2978 ASSERT_TRUE(audio_offer->cryptos().empty());
2979 const VideoContentDescription* video_offer =
2980 GetFirstVideoContentDescription(offer.get());
2981 ASSERT_TRUE(video_offer->cryptos().empty());
2982 const DataContentDescription* data_offer =
2983 GetFirstDataContentDescription(offer.get());
2984 ASSERT_TRUE(data_offer->cryptos().empty());
2985
2986 const cricket::TransportDescription* audio_offer_trans_desc =
2987 offer->GetTransportDescriptionByName("audio");
2988 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2989 const cricket::TransportDescription* video_offer_trans_desc =
2990 offer->GetTransportDescriptionByName("video");
2991 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2992 const cricket::TransportDescription* data_offer_trans_desc =
2993 offer->GetTransportDescriptionByName("data");
2994 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2995
2996 // Generate an answer with DTLS.
2997 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2998 ASSERT_TRUE(answer.get() != NULL);
2999
3000 const cricket::TransportDescription* audio_answer_trans_desc =
3001 answer->GetTransportDescriptionByName("audio");
3002 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3003 const cricket::TransportDescription* video_answer_trans_desc =
3004 answer->GetTransportDescriptionByName("video");
3005 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3006 const cricket::TransportDescription* data_answer_trans_desc =
3007 answer->GetTransportDescriptionByName("data");
3008 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3009}
3010
3011// Verifies if vad_enabled option is set to false, CN codecs are not present in
3012// offer or answer.
3013TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3014 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003015 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003016 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003017 ASSERT_TRUE(offer.get() != NULL);
3018 const ContentInfo* audio_content = offer->GetContentByName("audio");
3019 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3020
3021 options.vad_enabled = false;
3022 offer.reset(f1_.CreateOffer(options, NULL));
3023 ASSERT_TRUE(offer.get() != NULL);
3024 audio_content = offer->GetContentByName("audio");
3025 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08003026 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003027 f1_.CreateAnswer(offer.get(), options, NULL));
3028 ASSERT_TRUE(answer.get() != NULL);
3029 audio_content = answer->GetContentByName("audio");
3030 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3031}
deadbeef44f08192015-12-15 16:20:09 -08003032
zhihuang1c378ed2017-08-17 14:10:50 -07003033// Test that the generated MIDs match the existing offer.
3034TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003035 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003036 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
3037 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
3038 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
3039 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08003040 opts.data_channel_type = cricket::DCT_SCTP;
Steve Anton4e70a722017-11-28 14:57:10 -08003041 AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
3042 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003043 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08003044 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08003045 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003046 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003047
deadbeef44f08192015-12-15 16:20:09 -08003048 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3049 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3050 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3051 ASSERT_TRUE(audio_content != nullptr);
3052 ASSERT_TRUE(video_content != nullptr);
3053 ASSERT_TRUE(data_content != nullptr);
3054 EXPECT_EQ("audio_modified", audio_content->name);
3055 EXPECT_EQ("video_modified", video_content->name);
3056 EXPECT_EQ("data_modified", data_content->name);
3057}
zhihuangcf5b37c2016-05-05 11:44:35 -07003058
zhihuang1c378ed2017-08-17 14:10:50 -07003059// The following tests verify that the unified plan SDP is supported.
3060// Test that we can create an offer with multiple media sections of same media
3061// type.
3062TEST_F(MediaSessionDescriptionFactoryTest,
3063 CreateOfferWithMultipleAVMediaSections) {
3064 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003065 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3066 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003067 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003068 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003069
Steve Anton4e70a722017-11-28 14:57:10 -08003070 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3071 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003072 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003073 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003074
Steve Anton4e70a722017-11-28 14:57:10 -08003075 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3076 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003077 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003078 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003079
Steve Anton4e70a722017-11-28 14:57:10 -08003080 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3081 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003082 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003083 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003084 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3085 ASSERT_TRUE(offer);
3086
3087 ASSERT_EQ(4u, offer->contents().size());
3088 EXPECT_FALSE(offer->contents()[0].rejected);
3089 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003090 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003091 ASSERT_EQ(1u, acd->streams().size());
3092 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003093 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003094
3095 EXPECT_FALSE(offer->contents()[1].rejected);
3096 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003097 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003098 ASSERT_EQ(1u, vcd->streams().size());
3099 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003100 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003101
3102 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003103 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003104 ASSERT_EQ(1u, acd->streams().size());
3105 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003106 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003107
3108 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003109 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003110 ASSERT_EQ(1u, vcd->streams().size());
3111 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003112 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003113}
3114
3115// Test that we can create an answer with multiple media sections of same media
3116// type.
3117TEST_F(MediaSessionDescriptionFactoryTest,
3118 CreateAnswerWithMultipleAVMediaSections) {
3119 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003120 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3121 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003122 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003123 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003124
Steve Anton4e70a722017-11-28 14:57:10 -08003125 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3126 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003127 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003128 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003129
Steve Anton4e70a722017-11-28 14:57:10 -08003130 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3131 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003132 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003133 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003134
Steve Anton4e70a722017-11-28 14:57:10 -08003135 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3136 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003137 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003138 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003139
3140 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3141 ASSERT_TRUE(offer);
3142 std::unique_ptr<SessionDescription> answer(
3143 f2_.CreateAnswer(offer.get(), opts, nullptr));
3144
3145 ASSERT_EQ(4u, answer->contents().size());
3146 EXPECT_FALSE(answer->contents()[0].rejected);
3147 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003148 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003149 ASSERT_EQ(1u, acd->streams().size());
3150 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003151 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003152
3153 EXPECT_FALSE(answer->contents()[1].rejected);
3154 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003155 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003156 ASSERT_EQ(1u, vcd->streams().size());
3157 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003158 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003159
3160 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003161 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003162 ASSERT_EQ(1u, acd->streams().size());
3163 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003164 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003165
3166 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003167 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003168 ASSERT_EQ(1u, vcd->streams().size());
3169 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003170 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003171}
3172
3173// Test that the media section will be rejected in offer if the corresponding
3174// MediaDescriptionOptions is stopped by the offerer.
3175TEST_F(MediaSessionDescriptionFactoryTest,
3176 CreateOfferWithMediaSectionStoppedByOfferer) {
3177 // Create an offer with two audio sections and one of them is stopped.
3178 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003179 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3180 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3181 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3182 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003183 std::unique_ptr<SessionDescription> offer(
3184 f1_.CreateOffer(offer_opts, nullptr));
3185 ASSERT_TRUE(offer);
3186 ASSERT_EQ(2u, offer->contents().size());
3187 EXPECT_FALSE(offer->contents()[0].rejected);
3188 EXPECT_TRUE(offer->contents()[1].rejected);
3189}
3190
3191// Test that the media section will be rejected in answer if the corresponding
3192// MediaDescriptionOptions is stopped by the offerer.
3193TEST_F(MediaSessionDescriptionFactoryTest,
3194 CreateAnswerWithMediaSectionStoppedByOfferer) {
3195 // Create an offer with two audio sections and one of them is stopped.
3196 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003197 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3198 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3199 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3200 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003201 std::unique_ptr<SessionDescription> offer(
3202 f1_.CreateOffer(offer_opts, nullptr));
3203 ASSERT_TRUE(offer);
3204 ASSERT_EQ(2u, offer->contents().size());
3205 EXPECT_FALSE(offer->contents()[0].rejected);
3206 EXPECT_TRUE(offer->contents()[1].rejected);
3207
3208 // Create an answer based on the offer.
3209 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003210 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3211 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3212 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3213 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003214 std::unique_ptr<SessionDescription> answer(
3215 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3216 ASSERT_EQ(2u, answer->contents().size());
3217 EXPECT_FALSE(answer->contents()[0].rejected);
3218 EXPECT_TRUE(answer->contents()[1].rejected);
3219}
3220
3221// Test that the media section will be rejected in answer if the corresponding
3222// MediaDescriptionOptions is stopped by the answerer.
3223TEST_F(MediaSessionDescriptionFactoryTest,
3224 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3225 // Create an offer with two audio sections.
3226 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003227 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3228 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3229 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3230 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003231 std::unique_ptr<SessionDescription> offer(
3232 f1_.CreateOffer(offer_opts, nullptr));
3233 ASSERT_TRUE(offer);
3234 ASSERT_EQ(2u, offer->contents().size());
3235 ASSERT_FALSE(offer->contents()[0].rejected);
3236 ASSERT_FALSE(offer->contents()[1].rejected);
3237
3238 // The answerer rejects one of the audio sections.
3239 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003240 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3241 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3242 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3243 RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003244 std::unique_ptr<SessionDescription> answer(
3245 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3246 ASSERT_EQ(2u, answer->contents().size());
3247 EXPECT_FALSE(answer->contents()[0].rejected);
3248 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003249
3250 // The TransportInfo of the rejected m= section is expected to be added in the
3251 // answer.
3252 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003253}
3254
3255// Test the generated media sections has the same order of the
3256// corresponding MediaDescriptionOptions.
3257TEST_F(MediaSessionDescriptionFactoryTest,
3258 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3259 MediaSessionOptions opts;
3260 // This tests put video section first because normally audio comes first by
3261 // default.
Steve Anton4e70a722017-11-28 14:57:10 -08003262 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3263 kActive, &opts);
3264 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3265 kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003266 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3267
3268 ASSERT_TRUE(offer);
3269 ASSERT_EQ(2u, offer->contents().size());
3270 EXPECT_EQ("video", offer->contents()[0].name);
3271 EXPECT_EQ("audio", offer->contents()[1].name);
3272}
3273
3274// Test that different media sections using the same codec have same payload
3275// type.
3276TEST_F(MediaSessionDescriptionFactoryTest,
3277 PayloadTypesSharedByMediaSectionsOfSameType) {
3278 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003279 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3280 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3281 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3282 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003283 // Create an offer with two video sections using same codecs.
3284 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3285 ASSERT_TRUE(offer);
3286 ASSERT_EQ(2u, offer->contents().size());
3287 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003288 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003289 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003290 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003291 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3292 ASSERT_EQ(2u, vcd1->codecs().size());
3293 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3294 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3295 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3296 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3297
3298 // Create answer and negotiate the codecs.
3299 std::unique_ptr<SessionDescription> answer(
3300 f2_.CreateAnswer(offer.get(), opts, nullptr));
3301 ASSERT_TRUE(answer);
3302 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003303 vcd1 = answer->contents()[0].media_description()->as_video();
3304 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003305 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3306 ASSERT_EQ(1u, vcd1->codecs().size());
3307 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3308 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3309}
3310
3311// Test that the codec preference order per media section is respected in
3312// subsequent offer.
3313TEST_F(MediaSessionDescriptionFactoryTest,
3314 CreateOfferRespectsCodecPreferenceOrder) {
3315 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003316 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3317 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3318 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3319 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003320 // Create an offer with two video sections using same codecs.
3321 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3322 ASSERT_TRUE(offer);
3323 ASSERT_EQ(2u, offer->contents().size());
3324 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003325 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003326 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003327 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003328 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3329 EXPECT_EQ(video_codecs, vcd1->codecs());
3330 EXPECT_EQ(video_codecs, vcd2->codecs());
3331
3332 // Change the codec preference of the first video section and create a
3333 // follow-up offer.
3334 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3335 vcd1->set_codecs(video_codecs_reverse);
3336 std::unique_ptr<SessionDescription> updated_offer(
3337 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003338 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3339 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003340 // The video codec preference order should be respected.
3341 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3342 EXPECT_EQ(video_codecs, vcd2->codecs());
3343}
3344
3345// Test that the codec preference order per media section is respected in
3346// the answer.
3347TEST_F(MediaSessionDescriptionFactoryTest,
3348 CreateAnswerRespectsCodecPreferenceOrder) {
3349 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003350 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3351 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3352 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3353 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003354 // Create an offer with two video sections using same codecs.
3355 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3356 ASSERT_TRUE(offer);
3357 ASSERT_EQ(2u, offer->contents().size());
3358 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003359 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003360 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003361 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003362 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3363 EXPECT_EQ(video_codecs, vcd1->codecs());
3364 EXPECT_EQ(video_codecs, vcd2->codecs());
3365
3366 // Change the codec preference of the first video section and create an
3367 // answer.
3368 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3369 vcd1->set_codecs(video_codecs_reverse);
3370 std::unique_ptr<SessionDescription> answer(
3371 f1_.CreateAnswer(offer.get(), opts, nullptr));
Steve Antonb1c1de12017-12-21 15:14:30 -08003372 vcd1 = answer->contents()[0].media_description()->as_video();
3373 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003374 // The video codec preference order should be respected.
3375 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3376 EXPECT_EQ(video_codecs, vcd2->codecs());
3377}
3378
Zhi Huang6f367472017-11-22 13:20:02 -08003379// Test that when creating an answer, the codecs use local parameters instead of
3380// the remote ones.
3381TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3382 const std::string audio_param_name = "audio_param";
3383 const std::string audio_value1 = "audio_v1";
3384 const std::string audio_value2 = "audio_v2";
3385 const std::string video_param_name = "video_param";
3386 const std::string video_value1 = "video_v1";
3387 const std::string video_value2 = "video_v2";
3388
3389 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3390 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3391 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3392 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3393
3394 // Set the parameters for codecs.
3395 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3396 video_codecs1[0].SetParam(video_param_name, video_value1);
3397 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3398 video_codecs2[0].SetParam(video_param_name, video_value2);
3399
3400 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3401 f1_.set_video_codecs(video_codecs1);
3402 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3403 f2_.set_video_codecs(video_codecs2);
3404
3405 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003406 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3407 kActive, &opts);
3408 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3409 kActive, &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003410
3411 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3412 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003413 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3414 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003415 std::string value;
3416 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3417 EXPECT_EQ(audio_value1, value);
3418 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3419 EXPECT_EQ(video_value1, value);
3420
3421 std::unique_ptr<SessionDescription> answer(
3422 f2_.CreateAnswer(offer.get(), opts, nullptr));
3423 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003424 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3425 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003426 // Use the parameters from the local codecs.
3427 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3428 EXPECT_EQ(audio_value2, value);
3429 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3430 EXPECT_EQ(video_value2, value);
3431}
3432
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003433// Test that matching packetization-mode is part of the criteria for matching
3434// H264 codecs (in addition to profile-level-id). Previously, this was not the
3435// case, so the first H264 codec with the same profile-level-id would match and
3436// the payload type in the answer would be incorrect.
3437// This is a regression test for bugs.webrtc.org/8808
3438TEST_F(MediaSessionDescriptionFactoryTest,
3439 H264MatchCriteriaIncludesPacketizationMode) {
3440 // Create two H264 codecs with the same profile level ID and different
3441 // packetization modes.
3442 VideoCodec h264_pm0(96, "H264");
3443 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3444 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3445 VideoCodec h264_pm1(97, "H264");
3446 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3447 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3448
3449 // Offerer will send both codecs, answerer should choose the one with matching
3450 // packetization mode (and not the first one it sees).
3451 f1_.set_video_codecs({h264_pm0, h264_pm1});
3452 f2_.set_video_codecs({h264_pm1});
3453
3454 MediaSessionOptions opts;
3455 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3456 kActive, &opts);
3457
3458 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3459 ASSERT_TRUE(offer);
3460
3461 std::unique_ptr<SessionDescription> answer(
3462 f2_.CreateAnswer(offer.get(), opts, nullptr));
3463 ASSERT_TRUE(answer);
3464
3465 // Answer should have one negotiated codec with packetization-mode=1 using the
3466 // offered payload type.
3467 ASSERT_EQ(1u, answer->contents().size());
3468 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3469 ASSERT_EQ(1u, answer_vcd->codecs().size());
3470 auto answer_codec = answer_vcd->codecs()[0];
3471 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3472}
3473
zhihuangcf5b37c2016-05-05 11:44:35 -07003474class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3475 public:
3476 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003477 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3478 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003479 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3480 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003481 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3482 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003483 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3484 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3485 f1_.set_secure(SEC_ENABLED);
3486 f2_.set_secure(SEC_ENABLED);
3487 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003488 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003489 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003490 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003491 tdf1_.set_secure(SEC_ENABLED);
3492 tdf2_.set_secure(SEC_ENABLED);
3493 }
3494
3495 protected:
3496 MediaSessionDescriptionFactory f1_;
3497 MediaSessionDescriptionFactory f2_;
3498 TransportDescriptionFactory tdf1_;
3499 TransportDescriptionFactory tdf2_;
3500};
3501
3502TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3503 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003504 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003505 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3506 ASSERT_TRUE(offer.get() != nullptr);
3507 // Set the protocol for all the contents.
3508 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003509 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07003510 }
3511 std::unique_ptr<SessionDescription> answer(
3512 f2_.CreateAnswer(offer.get(), opts, nullptr));
3513 const ContentInfo* ac = answer->GetContentByName("audio");
3514 const ContentInfo* vc = answer->GetContentByName("video");
3515 ASSERT_TRUE(ac != nullptr);
3516 ASSERT_TRUE(vc != nullptr);
3517 EXPECT_FALSE(ac->rejected); // the offer is accepted
3518 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003519 const AudioContentDescription* acd = ac->media_description()->as_audio();
3520 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07003521 EXPECT_EQ(GetParam(), acd->protocol());
3522 EXPECT_EQ(GetParam(), vcd->protocol());
3523}
3524
3525INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3526 MediaProtocolTest,
3527 ::testing::ValuesIn(kMediaProtocols));
3528INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3529 MediaProtocolTest,
3530 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003531
3532TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3533 TransportDescriptionFactory tdf;
3534 MediaSessionDescriptionFactory sf(&tdf);
3535 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3536 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3537
3538 // The merged list of codecs should contain any send codecs that are also
3539 // nominally in the recieve codecs list. Payload types should be picked from
3540 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3541 // (set to 1). This equals what happens when the send codecs are used in an
3542 // offer and the receive codecs are used in the following answer.
3543 const std::vector<AudioCodec> sendrecv_codecs =
3544 MAKE_VECTOR(kAudioCodecsAnswer);
3545 const std::vector<AudioCodec> no_codecs;
3546
3547 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3548 << "Please don't change shared test data!";
3549 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3550 << "Please don't change shared test data!";
3551 // Alter iLBC send codec to have zero channels, to test that that is handled
3552 // properly.
3553 send_codecs[1].channels = 0;
3554
3555 // Alther iLBC receive codec to be lowercase, to test that case conversions
3556 // are handled properly.
3557 recv_codecs[2].name = "ilbc";
3558
3559 // Test proper merge
3560 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003561 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3562 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3563 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003564
3565 // Test empty send codecs list
3566 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003567 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3568 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3569 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003570
3571 // Test empty recv codecs list
3572 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003573 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3574 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3575 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003576
3577 // Test all empty codec lists
3578 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003579 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3580 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3581 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003582}
3583
3584namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003585// Compare the two vectors of codecs ignoring the payload type.
3586template <class Codec>
3587bool CodecsMatch(const std::vector<Codec>& codecs1,
3588 const std::vector<Codec>& codecs2) {
3589 if (codecs1.size() != codecs2.size()) {
3590 return false;
3591 }
3592
3593 for (size_t i = 0; i < codecs1.size(); ++i) {
3594 if (!codecs1[i].Matches(codecs2[i])) {
3595 return false;
3596 }
3597 }
3598 return true;
3599}
3600
Steve Anton4e70a722017-11-28 14:57:10 -08003601void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07003602 TransportDescriptionFactory tdf;
3603 MediaSessionDescriptionFactory sf(&tdf);
3604 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3605 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3606 const std::vector<AudioCodec> sendrecv_codecs =
3607 MAKE_VECTOR(kAudioCodecsAnswer);
3608 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003609
3610 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003611 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3612
Steve Anton4e70a722017-11-28 14:57:10 -08003613 if (direction == RtpTransceiverDirection::kSendRecv ||
3614 direction == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003615 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003616 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003617 }
ossu075af922016-06-14 03:29:38 -07003618
3619 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3620 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003621 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07003622
3623 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003624 // that the codecs put in are right. This happens when we neither want to
3625 // send nor receive audio. The checks are still in place if at some point
3626 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003627 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003628 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003629 // sendrecv and inactive should both present lists as if the channel was
3630 // to be used for sending and receiving. Inactive essentially means it
3631 // might eventually be used anything, but we don't know more at this
3632 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08003633 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003634 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08003635 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003636 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003637 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003638 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003639 }
3640 }
3641}
3642
3643static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003644 AudioCodec(0, "codec0", 16000, -1, 1),
3645 AudioCodec(1, "codec1", 8000, 13300, 1),
3646 AudioCodec(2, "codec2", 8000, 64000, 1),
3647 AudioCodec(3, "codec3", 8000, 64000, 1),
3648 AudioCodec(4, "codec4", 8000, 0, 2),
3649 AudioCodec(5, "codec5", 32000, 0, 1),
3650 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003651
zhihuang1c378ed2017-08-17 14:10:50 -07003652/* The codecs groups below are chosen as per the matrix below. The objective
3653 * is to have different sets of codecs in the inputs, to get unique sets of
3654 * codecs after negotiation, depending on offer and answer communication
3655 * directions. One-way directions in the offer should either result in the
3656 * opposite direction in the answer, or an inactive answer. Regardless, the
3657 * choice of codecs should be as if the answer contained the opposite
3658 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003659 *
3660 * | Offer | Answer | Result
3661 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3662 * 0 | x - - | - x - | x - - - -
3663 * 1 | x x x | - x - | x - - x -
3664 * 2 | - x - | x - - | - x - - -
3665 * 3 | x x x | x - - | - x x - -
3666 * 4 | - x - | x x x | - x - - -
3667 * 5 | x - - | x x x | x - - - -
3668 * 6 | x x x | x x x | x x x x x
3669 */
3670// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003671static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3672static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003673// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3674// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003675static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3676static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003677// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003678static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3679static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3680static const int kResultSendrecv_SendCodecs[] = {3, 6};
3681static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3682static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003683
3684template <typename T, int IDXS>
3685std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3686 std::vector<T> out;
3687 out.reserve(IDXS);
3688 for (int idx : indices)
3689 out.push_back(array[idx]);
3690
3691 return out;
3692}
3693
Steve Anton4e70a722017-11-28 14:57:10 -08003694void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
3695 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07003696 bool add_legacy_stream) {
3697 TransportDescriptionFactory offer_tdf;
3698 TransportDescriptionFactory answer_tdf;
3699 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3700 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3701 offer_factory.set_audio_codecs(
3702 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3703 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3704 answer_factory.set_audio_codecs(
3705 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3706 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3707
ossu075af922016-06-14 03:29:38 -07003708 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003709 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3710 &offer_opts);
3711
Steve Anton4e70a722017-11-28 14:57:10 -08003712 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003713 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003714 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003715 }
3716
3717 std::unique_ptr<SessionDescription> offer(
3718 offer_factory.CreateOffer(offer_opts, NULL));
3719 ASSERT_TRUE(offer.get() != NULL);
3720
3721 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003722 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3723 &answer_opts);
3724
Steve Anton4e70a722017-11-28 14:57:10 -08003725 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003726 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003727 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003728 }
3729 std::unique_ptr<SessionDescription> answer(
3730 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3731 const ContentInfo* ac = answer->GetContentByName("audio");
3732
zhihuang1c378ed2017-08-17 14:10:50 -07003733 // If the factory didn't add any audio content to the answer, we cannot
3734 // check that the codecs put in are right. This happens when we neither want
3735 // to send nor receive audio. The checks are still in place if at some point
3736 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003737 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003738 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
3739 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07003740
ossu075af922016-06-14 03:29:38 -07003741 std::vector<AudioCodec> target_codecs;
3742 // For offers with sendrecv or inactive, we should never reply with more
3743 // codecs than offered, with these codec sets.
3744 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08003745 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07003746 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3747 kResultSendrecv_SendrecvCodecs);
3748 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003749 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003750 target_codecs =
3751 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003752 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003753 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003754 target_codecs =
3755 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003756 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003757 case RtpTransceiverDirection::kSendRecv:
3758 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003759 target_codecs =
3760 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08003761 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003762 target_codecs =
3763 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003764 } else {
3765 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3766 kResultSendrecv_SendrecvCodecs);
3767 }
3768 break;
3769 }
3770
zhihuang1c378ed2017-08-17 14:10:50 -07003771 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02003772 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07003773 bool first = true;
3774 os << "{";
3775 for (const auto& c : codecs) {
3776 os << (first ? " " : ", ") << c.id;
3777 first = false;
3778 }
3779 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02003780 return os.Release();
ossu075af922016-06-14 03:29:38 -07003781 };
3782
3783 EXPECT_TRUE(acd->codecs() == target_codecs)
3784 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08003785 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
3786 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07003787 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08003788 << webrtc::RtpTransceiverDirectionToString(answer_direction)
3789 << "; got: "
3790 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07003791 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08003792 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07003793 << "Only inactive offers are allowed to not generate any audio "
3794 "content";
ossu075af922016-06-14 03:29:38 -07003795 }
3796}
brandtr03d5fb12016-11-22 03:37:59 -08003797
3798} // namespace
ossu075af922016-06-14 03:29:38 -07003799
3800class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08003801 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07003802
3803TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003804 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003805}
3806
3807INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3808 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003809 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3810 RtpTransceiverDirection::kRecvOnly,
3811 RtpTransceiverDirection::kSendRecv,
3812 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07003813
3814class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08003815 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
3816 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003817 bool>> {};
ossu075af922016-06-14 03:29:38 -07003818
3819TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003820 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3821 ::testing::get<1>(GetParam()),
3822 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003823}
3824
zhihuang1c378ed2017-08-17 14:10:50 -07003825INSTANTIATE_TEST_CASE_P(
3826 MediaSessionDescriptionFactoryTest,
3827 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003828 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
3829 RtpTransceiverDirection::kRecvOnly,
3830 RtpTransceiverDirection::kSendRecv,
3831 RtpTransceiverDirection::kInactive),
3832 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3833 RtpTransceiverDirection::kRecvOnly,
3834 RtpTransceiverDirection::kSendRecv,
3835 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07003836 ::testing::Bool()));