blob: 2af14d2df3107263bad47361ae44c208aff5080d [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
Amit Hilbuch77938e62018-12-21 09:23:38 -080011#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080012#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000013#include <string>
14#include <vector>
15
Steve Anton6fe1fba2018-12-11 10:15:23 -080016#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "media/base/codec.h"
18#include "media/base/testutils.h"
19#include "p2p/base/p2pconstants.h"
20#include "p2p/base/transportdescription.h"
21#include "p2p/base/transportinfo.h"
22#include "pc/mediasession.h"
Steve Anton1d03a752017-11-27 14:30:09 -080023#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "pc/srtpfilter.h"
25#include "rtc_base/checks.h"
26#include "rtc_base/fakesslidentity.h"
27#include "rtc_base/gunit.h"
28#include "rtc_base/messagedigest.h"
29#include "rtc_base/ssladapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020030#include "rtc_base/strings/string_builder.h"
Steve Antone38a5a12018-11-21 16:05:15 -080031#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032
Yves Gerey665174f2018-06-19 15:03:05 +020033#define ASSERT_CRYPTO(cd, s, cs) \
34 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080035 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036
37typedef std::vector<cricket::Candidate> Candidates;
38
39using cricket::MediaContentDescription;
40using cricket::MediaSessionDescriptionFactory;
zhihuang1c378ed2017-08-17 14:10:50 -070041using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042using cricket::MediaSessionOptions;
43using cricket::MediaType;
Steve Anton5adfafd2017-12-20 16:34:00 -080044using cricket::MediaProtocolType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045using cricket::SessionDescription;
46using cricket::SsrcGroup;
47using cricket::StreamParams;
48using cricket::StreamParamsVec;
49using cricket::TransportDescription;
50using cricket::TransportDescriptionFactory;
51using cricket::TransportInfo;
52using cricket::ContentInfo;
53using cricket::CryptoParamsVec;
54using cricket::AudioContentDescription;
55using cricket::VideoContentDescription;
56using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080057using cricket::GetFirstAudioContent;
58using cricket::GetFirstVideoContent;
59using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::GetFirstAudioContentDescription;
61using cricket::GetFirstVideoContentDescription;
62using cricket::GetFirstDataContentDescription;
63using cricket::kAutoBandwidth;
64using cricket::AudioCodec;
65using cricket::VideoCodec;
66using cricket::DataCodec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067using cricket::MEDIA_TYPE_AUDIO;
68using cricket::MEDIA_TYPE_VIDEO;
69using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070using cricket::SEC_DISABLED;
71using cricket::SEC_ENABLED;
72using cricket::SEC_REQUIRED;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070073using rtc::CS_AES_CM_128_HMAC_SHA1_32;
74using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070075using rtc::CS_AEAD_AES_128_GCM;
76using rtc::CS_AEAD_AES_256_GCM;
Steve Antone38a5a12018-11-21 16:05:15 -080077using testing::ElementsAreArray;
isheriff6f8d6862016-05-26 11:24:55 -070078using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080079using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080
81static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070082 AudioCodec(103, "ISAC", 16000, -1, 1),
83 AudioCodec(102, "iLBC", 8000, 13300, 1),
84 AudioCodec(0, "PCMU", 8000, 64000, 1),
85 AudioCodec(8, "PCMA", 8000, 64000, 1),
86 AudioCodec(117, "red", 8000, 0, 1),
87 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088
89static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +020090 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -070091 AudioCodec(0, "PCMU", 8000, 64000, 1),
92 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093};
94
95static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070096 AudioCodec(102, "iLBC", 8000, 13300, 1),
97 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098};
99
perkj26752742016-10-24 01:21:16 -0700100static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
101 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102
zhihuang1c378ed2017-08-17 14:10:50 -0700103static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
104 VideoCodec(96, "H264-SVC")};
105
perkj26752742016-10-24 01:21:16 -0700106static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
107 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108
perkj26752742016-10-24 01:21:16 -0700109static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110
deadbeef67cf2c12016-04-13 10:07:16 -0700111static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
112 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113
deadbeef67cf2c12016-04-13 10:07:16 -0700114static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
115 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116
deadbeef67cf2c12016-04-13 10:07:16 -0700117static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
118 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119
isheriff6f8d6862016-05-26 11:24:55 -0700120static const RtpExtension kAudioRtpExtension1[] = {
121 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
122 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123};
124
jbauch5869f502017-06-29 12:31:36 -0700125static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
126 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
127 RtpExtension("http://google.com/testing/audio_something", 10),
128 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
129};
130
isheriff6f8d6862016-05-26 11:24:55 -0700131static const RtpExtension kAudioRtpExtension2[] = {
132 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
133 RtpExtension("http://google.com/testing/audio_something_else", 8),
134 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135};
136
isheriff6f8d6862016-05-26 11:24:55 -0700137static const RtpExtension kAudioRtpExtension3[] = {
138 RtpExtension("http://google.com/testing/audio_something", 2),
139 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700140};
141
jbauch5869f502017-06-29 12:31:36 -0700142static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
143 RtpExtension("http://google.com/testing/audio_something", 2),
144 // Use RTP extension that supports encryption.
145 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
146};
147
148static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
149 RtpExtension("http://google.com/testing/audio_something", 2),
150 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
151 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
152};
153
isheriff6f8d6862016-05-26 11:24:55 -0700154static const RtpExtension kAudioRtpExtensionAnswer[] = {
155 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000156};
157
jbauch5869f502017-06-29 12:31:36 -0700158static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
159 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
160};
161
isheriff6f8d6862016-05-26 11:24:55 -0700162static const RtpExtension kVideoRtpExtension1[] = {
163 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
164 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165};
166
jbauch5869f502017-06-29 12:31:36 -0700167static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
168 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
169 RtpExtension("http://google.com/testing/video_something", 13),
170 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
171};
172
isheriff6f8d6862016-05-26 11:24:55 -0700173static const RtpExtension kVideoRtpExtension2[] = {
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
175 RtpExtension("http://google.com/testing/video_something_else", 14),
176 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000177};
178
isheriff6f8d6862016-05-26 11:24:55 -0700179static const RtpExtension kVideoRtpExtension3[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700182};
183
jbauch5869f502017-06-29 12:31:36 -0700184static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
185 RtpExtension("http://google.com/testing/video_something", 4),
186 // Use RTP extension that supports encryption.
187 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
188};
189
isheriff6f8d6862016-05-26 11:24:55 -0700190static const RtpExtension kVideoRtpExtensionAnswer[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192};
193
jbauch5869f502017-06-29 12:31:36 -0700194static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
195 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
196};
197
Peter Boström0c4e06b2015-10-07 12:23:21 +0200198static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
199static const uint32_t kSimSsrc[] = {10, 20, 30};
200static const uint32_t kFec1Ssrc[] = {10, 11};
201static const uint32_t kFec2Ssrc[] = {20, 21};
202static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000203
204static const char kMediaStream1[] = "stream_1";
205static const char kMediaStream2[] = "stream_2";
206static const char kVideoTrack1[] = "video_1";
207static const char kVideoTrack2[] = "video_2";
208static const char kAudioTrack1[] = "audio_1";
209static const char kAudioTrack2[] = "audio_2";
210static const char kAudioTrack3[] = "audio_3";
211static const char kDataTrack1[] = "data_1";
212static const char kDataTrack2[] = "data_2";
213static const char kDataTrack3[] = "data_3";
214
zhihuangcf5b37c2016-05-05 11:44:35 -0700215static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
216 "RTP/SAVPF"};
217static const char* kMediaProtocolsDtls[] = {
218 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
219 "UDP/TLS/RTP/SAVP"};
220
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700221// SRTP cipher name negotiated by the tests. This must be updated if the
222// default changes.
223static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
224static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
225
zhihuang1c378ed2017-08-17 14:10:50 -0700226// These constants are used to make the code using "AddMediaSection" more
227// readable.
228static constexpr bool kStopped = true;
229static constexpr bool kActive = false;
230
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000231static bool IsMediaContentOfType(const ContentInfo* content,
232 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800233 RTC_DCHECK(content);
234 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000235}
236
Steve Anton4e70a722017-11-28 14:57:10 -0800237static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800238 RTC_DCHECK(content);
239 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000240}
241
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000242static void AddRtxCodec(const VideoCodec& rtx_codec,
243 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800244 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000245 codecs->push_back(rtx_codec);
246}
247
248template <class T>
249static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
250 std::vector<std::string> codec_names;
251 for (const auto& codec : codecs) {
252 codec_names.push_back(codec.name);
253 }
254 return codec_names;
255}
256
zhihuang1c378ed2017-08-17 14:10:50 -0700257// This is used for test only. MIDs are not the identification of the
258// MediaDescriptionOptions since some end points may not support MID and the SDP
259// may not contain 'mid'.
260std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
261 const std::string& mid,
262 MediaSessionOptions* opts) {
263 return std::find_if(
264 opts->media_description_options.begin(),
265 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700266 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
267}
268
269std::vector<MediaDescriptionOptions>::const_iterator
270FindFirstMediaDescriptionByMid(const std::string& mid,
271 const MediaSessionOptions& opts) {
272 return std::find_if(
273 opts.media_description_options.begin(),
274 opts.media_description_options.end(),
275 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700276}
277
278// Add a media section to the |session_options|.
279static void AddMediaSection(MediaType type,
280 const std::string& mid,
Steve Anton4e70a722017-11-28 14:57:10 -0800281 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700282 bool stopped,
283 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800284 opts->media_description_options.push_back(
285 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700286}
287
Steve Anton4e70a722017-11-28 14:57:10 -0800288static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700289 MediaSessionOptions* opts) {
290 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
291 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
292}
293
294static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800295 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700296 MediaSessionOptions* opts) {
297 opts->data_channel_type = dct;
298 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
299}
300
Steve Anton8ffb9c32017-08-31 15:45:38 -0700301static void AttachSenderToMediaSection(
302 const std::string& mid,
303 MediaType type,
304 const std::string& track_id,
305 const std::vector<std::string>& stream_ids,
306 int num_sim_layer,
307 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700308 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
309 switch (type) {
310 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700311 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700312 break;
313 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700314 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700315 break;
316 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700317 RTC_CHECK(stream_ids.size() == 1U);
318 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700319 break;
320 default:
321 RTC_NOTREACHED();
322 }
323}
324
325static void DetachSenderFromMediaSection(const std::string& mid,
326 const std::string& track_id,
327 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700328 std::vector<cricket::SenderOptions>& sender_options_list =
329 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
330 auto sender_it =
331 std::find_if(sender_options_list.begin(), sender_options_list.end(),
332 [track_id](const cricket::SenderOptions& sender_options) {
333 return sender_options.track_id == track_id;
334 });
335 RTC_DCHECK(sender_it != sender_options_list.end());
336 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700337}
338
339// Helper function used to create a default MediaSessionOptions for Plan B SDP.
340// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
341static MediaSessionOptions CreatePlanBMediaSessionOptions() {
342 MediaSessionOptions session_options;
Steve Anton4e70a722017-11-28 14:57:10 -0800343 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
344 kActive, &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700345 return session_options;
346}
347
348// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
349// was designed for Plan B SDP, where only one audio "m=" section and one video
350// "m=" section could be generated, and ordering couldn't be controlled. Many of
351// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000352class MediaSessionDescriptionFactoryTest : public testing::Test {
353 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700354 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700355 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
356 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
358 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700359 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
360 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
362 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200363 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700364 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200365 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700366 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 }
368
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000369 // Create a video StreamParamsVec object with:
370 // - one video stream with 3 simulcast streams and FEC,
371 StreamParamsVec CreateComplexVideoStreamParamsVec() {
372 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
373 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
374 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
375 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
376
377 std::vector<SsrcGroup> ssrc_groups;
378 ssrc_groups.push_back(sim_group);
379 ssrc_groups.push_back(fec_group1);
380 ssrc_groups.push_back(fec_group2);
381 ssrc_groups.push_back(fec_group3);
382
383 StreamParams simulcast_params;
384 simulcast_params.id = kVideoTrack1;
385 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
386 simulcast_params.ssrc_groups = ssrc_groups;
387 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800388 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000389
390 StreamParamsVec video_streams;
391 video_streams.push_back(simulcast_params);
392
393 return video_streams;
394 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395
396 bool CompareCryptoParams(const CryptoParamsVec& c1,
397 const CryptoParamsVec& c2) {
398 if (c1.size() != c2.size())
399 return false;
400 for (size_t i = 0; i < c1.size(); ++i)
401 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
402 c1[i].key_params != c2[i].key_params ||
403 c1[i].session_params != c2[i].session_params)
404 return false;
405 return true;
406 }
407
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700408 // Returns true if the transport info contains "renomination" as an
409 // ICE option.
410 bool GetIceRenomination(const TransportInfo* transport_info) {
411 const std::vector<std::string>& ice_options =
412 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700413 auto iter =
414 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700415 return iter != ice_options.end();
416 }
417
zhihuang1c378ed2017-08-17 14:10:50 -0700418 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700419 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 bool has_current_desc) {
421 const std::string current_audio_ufrag = "current_audio_ufrag";
422 const std::string current_audio_pwd = "current_audio_pwd";
423 const std::string current_video_ufrag = "current_video_ufrag";
424 const std::string current_video_pwd = "current_video_pwd";
425 const std::string current_data_ufrag = "current_data_ufrag";
426 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800427 std::unique_ptr<SessionDescription> current_desc;
428 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800430 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800431 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200432 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800433 TransportDescription(current_audio_ufrag, current_audio_pwd)));
434 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200435 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800436 TransportDescription(current_video_ufrag, current_video_pwd)));
437 current_desc->AddTransportInfo(TransportInfo(
438 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000439 }
440 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800441 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000442 } else {
kwiberg31022942016-03-11 14:18:21 -0800443 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800444 offer = f1_.CreateOffer(options, NULL);
445 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 }
447 ASSERT_TRUE(desc.get() != NULL);
448 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000449 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 EXPECT_TRUE(ti_audio != NULL);
451 if (has_current_desc) {
452 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
453 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
454 } else {
455 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
456 ti_audio->description.ice_ufrag.size());
457 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
458 ti_audio->description.ice_pwd.size());
459 }
zhihuang1c378ed2017-08-17 14:10:50 -0700460 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700461 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700462 EXPECT_EQ(
463 media_desc_options_it->transport_options.enable_ice_renomination,
464 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465
466 } else {
467 EXPECT_TRUE(ti_audio == NULL);
468 }
469 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000470 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 EXPECT_TRUE(ti_video != NULL);
472 if (options.bundle_enabled) {
473 EXPECT_EQ(ti_audio->description.ice_ufrag,
474 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200475 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000476 } else {
477 if (has_current_desc) {
478 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
479 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
480 } else {
481 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
482 ti_video->description.ice_ufrag.size());
483 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
484 ti_video->description.ice_pwd.size());
485 }
486 }
zhihuang1c378ed2017-08-17 14:10:50 -0700487 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700488 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700489 EXPECT_EQ(
490 media_desc_options_it->transport_options.enable_ice_renomination,
491 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 } else {
493 EXPECT_TRUE(ti_video == NULL);
494 }
495 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
496 if (options.has_data()) {
497 EXPECT_TRUE(ti_data != NULL);
498 if (options.bundle_enabled) {
499 EXPECT_EQ(ti_audio->description.ice_ufrag,
500 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200501 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 } else {
503 if (has_current_desc) {
504 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
505 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
506 } else {
507 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
508 ti_data->description.ice_ufrag.size());
509 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
510 ti_data->description.ice_pwd.size());
511 }
512 }
zhihuang1c378ed2017-08-17 14:10:50 -0700513 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700514 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700515 EXPECT_EQ(
516 media_desc_options_it->transport_options.enable_ice_renomination,
517 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700518
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 } else {
520 EXPECT_TRUE(ti_video == NULL);
521 }
522 }
523
524 void TestCryptoWithBundle(bool offer) {
525 f1_.set_secure(SEC_ENABLED);
526 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800527 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
528 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
529 &options);
kwiberg31022942016-03-11 14:18:21 -0800530 std::unique_ptr<SessionDescription> ref_desc;
531 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 if (offer) {
533 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800534 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800536 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 } else {
538 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800539 ref_desc = f1_.CreateOffer(options, NULL);
540 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800542 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800544 desc->GetContentDescriptionByName("audio");
545 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800547 desc->GetContentDescriptionByName("video");
548 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
550 video_media_desc->cryptos()));
551 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800552 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 audio_media_desc->cryptos()[0].cipher_suite);
554
555 // Verify the selected crypto is one from the reference audio
556 // media content.
557 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800558 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 bool found = false;
560 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
561 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200562 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 found = true;
564 break;
565 }
566 }
567 EXPECT_TRUE(found);
568 }
569
570 // This test that the audio and video media direction is set to
571 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700572 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800574 RtpTransceiverDirection direction_in_offer,
575 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700576 MediaSessionOptions offer_opts;
577 AddAudioVideoSections(direction_in_offer, &offer_opts);
578
Steve Anton6fe1fba2018-12-11 10:15:23 -0800579 std::unique_ptr<SessionDescription> offer =
580 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700582 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700584 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586
zhihuang1c378ed2017-08-17 14:10:50 -0700587 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800588 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800589 std::unique_ptr<SessionDescription> answer =
590 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 const AudioContentDescription* acd_answer =
592 GetFirstAudioContentDescription(answer.get());
593 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
594 const VideoContentDescription* vcd_answer =
595 GetFirstVideoContentDescription(answer.get());
596 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
597 }
598
599 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800600 RTC_DCHECK(content);
601 RTC_CHECK(content->media_description());
602 const cricket::AudioContentDescription* audio_desc =
603 content->media_description()->as_audio();
604 RTC_CHECK(audio_desc);
605 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
606 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800608 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609 }
610 return true;
611 }
612
jbauchcb560652016-08-04 05:20:32 -0700613 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
614 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800615 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700616 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700617
jbauchcb560652016-08-04 05:20:32 -0700618 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800619 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700620 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700621
jbauchcb560652016-08-04 05:20:32 -0700622 f1_.set_secure(SEC_ENABLED);
623 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800624 std::unique_ptr<SessionDescription> offer =
625 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700626 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800627 std::unique_ptr<SessionDescription> answer =
628 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700629 const ContentInfo* ac = answer->GetContentByName("audio");
630 const ContentInfo* vc = answer->GetContentByName("video");
631 ASSERT_TRUE(ac != NULL);
632 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800633 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
634 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800635 const AudioContentDescription* acd = ac->media_description()->as_audio();
636 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700637 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800638 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700639 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700640 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700641 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
642 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700643 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700644 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700645 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700646 }
647 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800648 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200649 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
650 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700651 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700652 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700653 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700654 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700655 }
Steve Antone38a5a12018-11-21 16:05:15 -0800656 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700657 }
658
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 protected:
660 MediaSessionDescriptionFactory f1_;
661 MediaSessionDescriptionFactory f2_;
662 TransportDescriptionFactory tdf1_;
663 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664};
665
666// Create a typical audio offer, and ensure it matches what we expect.
667TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
668 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800669 std::unique_ptr<SessionDescription> offer =
670 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671 ASSERT_TRUE(offer.get() != NULL);
672 const ContentInfo* ac = offer->GetContentByName("audio");
673 const ContentInfo* vc = offer->GetContentByName("video");
674 ASSERT_TRUE(ac != NULL);
675 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800676 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800677 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700679 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700680 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000681 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
682 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700683 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800684 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685}
686
687// Create a typical video offer, and ensure it matches what we expect.
688TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
689 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800690 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000691 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800692 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000693 ASSERT_TRUE(offer.get() != NULL);
694 const ContentInfo* ac = offer->GetContentByName("audio");
695 const ContentInfo* vc = offer->GetContentByName("video");
696 ASSERT_TRUE(ac != NULL);
697 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800698 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
699 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800700 const AudioContentDescription* acd = ac->media_description()->as_audio();
701 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000702 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700703 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700704 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000705 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
706 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700707 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800708 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
710 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700711 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000712 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
713 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700714 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800715 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000716}
717
718// Test creating an offer with bundle where the Codecs have the same dynamic
719// RTP playlod type. The test verifies that the offer don't contain the
720// duplicate RTP payload types.
721TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
722 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700723 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
725 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
726 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
727
728 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800729 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
730 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800732 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 const VideoContentDescription* vcd =
734 GetFirstVideoContentDescription(offer.get());
735 const AudioContentDescription* acd =
736 GetFirstAudioContentDescription(offer.get());
737 const DataContentDescription* dcd =
738 GetFirstDataContentDescription(offer.get());
739 ASSERT_TRUE(NULL != vcd);
740 ASSERT_TRUE(NULL != acd);
741 ASSERT_TRUE(NULL != dcd);
742 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
743 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
744 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
745 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
746 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
747 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
748}
749
zhihuang1c378ed2017-08-17 14:10:50 -0700750// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751// after an audio only session has been negotiated.
752TEST_F(MediaSessionDescriptionFactoryTest,
753 TestCreateUpdatedVideoOfferWithBundle) {
754 f1_.set_secure(SEC_ENABLED);
755 f2_.set_secure(SEC_ENABLED);
756 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800757 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
758 kActive, &opts);
759 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kInactive,
760 kStopped, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 opts.data_channel_type = cricket::DCT_NONE;
762 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800763 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
764 std::unique_ptr<SessionDescription> answer =
765 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766
767 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800768 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
769 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
770 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800772 std::unique_ptr<SessionDescription> updated_offer(
773 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774
775 const AudioContentDescription* acd =
776 GetFirstAudioContentDescription(updated_offer.get());
777 const VideoContentDescription* vcd =
778 GetFirstVideoContentDescription(updated_offer.get());
779 const DataContentDescription* dcd =
780 GetFirstDataContentDescription(updated_offer.get());
781 EXPECT_TRUE(NULL != vcd);
782 EXPECT_TRUE(NULL != acd);
783 EXPECT_TRUE(NULL != dcd);
784
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700785 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800786 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700787 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800788 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700789 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800790 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791}
deadbeef44f08192015-12-15 16:20:09 -0800792
wu@webrtc.org78187522013-10-07 23:32:02 +0000793// Create a RTP data offer, and ensure it matches what we expect.
794TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800796 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
797 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800799 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 ASSERT_TRUE(offer.get() != NULL);
801 const ContentInfo* ac = offer->GetContentByName("audio");
802 const ContentInfo* dc = offer->GetContentByName("data");
803 ASSERT_TRUE(ac != NULL);
804 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800805 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
806 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800807 const AudioContentDescription* acd = ac->media_description()->as_audio();
808 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700810 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700811 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
813 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700814 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800815 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
817 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700818 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200820 dcd->bandwidth()); // default bandwidth (auto)
821 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700822 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800823 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000824}
825
wu@webrtc.org78187522013-10-07 23:32:02 +0000826// Create an SCTP data offer with bundle without error.
827TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
828 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000829 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800830 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000831 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800832 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000833 EXPECT_TRUE(offer.get() != NULL);
834 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
835}
836
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000837// Test creating an sctp data channel from an already generated offer.
838TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
839 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000840 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800841 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000842 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800843 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000844 ASSERT_TRUE(offer1.get() != NULL);
845 const ContentInfo* data = offer1->GetContentByName("data");
846 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800847 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000848
849 // Now set data_channel_type to 'none' (default) and make sure that the
850 // datachannel type that gets generated from the previous offer, is of the
851 // same type.
852 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800853 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000854 f1_.CreateOffer(opts, offer1.get()));
855 data = offer2->GetContentByName("data");
856 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800857 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000858}
859
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860// Create an audio, video offer without legacy StreamParams.
861TEST_F(MediaSessionDescriptionFactoryTest,
862 TestCreateOfferWithoutLegacyStreams) {
863 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800864 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800865 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 ASSERT_TRUE(offer.get() != NULL);
867 const ContentInfo* ac = offer->GetContentByName("audio");
868 const ContentInfo* vc = offer->GetContentByName("video");
869 ASSERT_TRUE(ac != NULL);
870 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800871 const AudioContentDescription* acd = ac->media_description()->as_audio();
872 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873
Yves Gerey665174f2018-06-19 15:03:05 +0200874 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
875 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876}
877
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000878// Creates an audio+video sendonly offer.
879TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700880 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800881 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700882 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700883 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700884 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700885 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000886
Steve Anton6fe1fba2018-12-11 10:15:23 -0800887 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000888 ASSERT_TRUE(offer.get() != NULL);
889 EXPECT_EQ(2u, offer->contents().size());
890 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
891 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
892
Steve Anton4e70a722017-11-28 14:57:10 -0800893 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
894 GetMediaDirection(&offer->contents()[0]));
895 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
896 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000897}
898
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000899// Verifies that the order of the media contents in the current
900// SessionDescription is preserved in the new SessionDescription.
901TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
902 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800903 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000904
kwiberg31022942016-03-11 14:18:21 -0800905 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000906 ASSERT_TRUE(offer1.get() != NULL);
907 EXPECT_EQ(1u, offer1->contents().size());
908 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
909
Steve Anton4e70a722017-11-28 14:57:10 -0800910 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
911 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800912 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000913 f1_.CreateOffer(opts, offer1.get()));
914 ASSERT_TRUE(offer2.get() != NULL);
915 EXPECT_EQ(2u, offer2->contents().size());
916 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
917 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
918
Steve Anton4e70a722017-11-28 14:57:10 -0800919 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
920 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800921 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000922 f1_.CreateOffer(opts, offer2.get()));
923 ASSERT_TRUE(offer3.get() != NULL);
924 EXPECT_EQ(3u, offer3->contents().size());
925 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
926 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
927 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000928}
929
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000930// Create a typical audio answer, and ensure it matches what we expect.
931TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
932 f1_.set_secure(SEC_ENABLED);
933 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800934 std::unique_ptr<SessionDescription> offer =
935 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000936 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800937 std::unique_ptr<SessionDescription> answer =
938 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000939 const ContentInfo* ac = answer->GetContentByName("audio");
940 const ContentInfo* vc = answer->GetContentByName("video");
941 ASSERT_TRUE(ac != NULL);
942 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800943 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800944 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000945 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800946 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -0700947 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
949 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700950 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800951 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952}
953
jbauchcb560652016-08-04 05:20:32 -0700954// Create a typical audio answer with GCM ciphers enabled, and ensure it
955// matches what we expect.
956TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
957 f1_.set_secure(SEC_ENABLED);
958 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700959 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700960 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800961 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700962 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800963 std::unique_ptr<SessionDescription> answer =
964 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700965 const ContentInfo* ac = answer->GetContentByName("audio");
966 const ContentInfo* vc = answer->GetContentByName("video");
967 ASSERT_TRUE(ac != NULL);
968 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800969 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800970 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -0700971 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800972 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -0700973 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700974 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
975 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700976 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -0800977 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700978}
979
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980// Create a typical video answer, and ensure it matches what we expect.
981TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
982 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800983 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984 f1_.set_secure(SEC_ENABLED);
985 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800986 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800988 std::unique_ptr<SessionDescription> answer =
989 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 const ContentInfo* ac = answer->GetContentByName("audio");
991 const ContentInfo* vc = answer->GetContentByName("video");
992 ASSERT_TRUE(ac != NULL);
993 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800994 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
995 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800996 const AudioContentDescription* acd = ac->media_description()->as_audio();
997 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800999 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001001 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001002 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001003 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001004 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001005 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001006 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1007 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001008 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001009 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001010}
1011
jbauchcb560652016-08-04 05:20:32 -07001012// Create a typical video answer with GCM ciphers enabled, and ensure it
1013// matches what we expect.
1014TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1015 TestVideoGcmCipher(true, true);
1016}
1017
1018// Create a typical video answer with GCM ciphers enabled for the offer only,
1019// and ensure it matches what we expect.
1020TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1021 TestVideoGcmCipher(true, false);
1022}
1023
1024// Create a typical video answer with GCM ciphers enabled for the answer only,
1025// and ensure it matches what we expect.
1026TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1027 TestVideoGcmCipher(false, true);
1028}
1029
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001030TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001031 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001032 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001033 f1_.set_secure(SEC_ENABLED);
1034 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001035 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001036 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001037 std::unique_ptr<SessionDescription> answer =
1038 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001040 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001041 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001042 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001043 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1044 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001045 const AudioContentDescription* acd = ac->media_description()->as_audio();
1046 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001048 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001050 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001051 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001052 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001053 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001054 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001055 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001056 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001057 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001058 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059}
1060
jbauchcb560652016-08-04 05:20:32 -07001061TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001062 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001063 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001064 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001065 f1_.set_secure(SEC_ENABLED);
1066 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001067 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001068 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001069 std::unique_ptr<SessionDescription> answer =
1070 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001071 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001072 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001073 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001074 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001075 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1076 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001077 const AudioContentDescription* acd = ac->media_description()->as_audio();
1078 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001079 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001080 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001081 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001082 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001083 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001084 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001085 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001086 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001087 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001088 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001089 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001090 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001091}
1092
1093// The use_sctpmap flag should be set in a DataContentDescription by default.
1094// The answer's use_sctpmap flag should match the offer's.
1095TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1096 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001097 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001098 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001099 ASSERT_TRUE(offer.get() != NULL);
1100 ContentInfo* dc_offer = offer->GetContentByName("data");
1101 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001102 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001103 EXPECT_TRUE(dcd_offer->use_sctpmap());
1104
Steve Anton6fe1fba2018-12-11 10:15:23 -08001105 std::unique_ptr<SessionDescription> answer =
1106 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001107 const ContentInfo* dc_answer = answer->GetContentByName("data");
1108 ASSERT_TRUE(dc_answer != NULL);
1109 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001110 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001111 EXPECT_TRUE(dcd_answer->use_sctpmap());
1112}
1113
1114// The answer's use_sctpmap flag should match the offer's.
1115TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1116 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001117 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001118 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001119 ASSERT_TRUE(offer.get() != NULL);
1120 ContentInfo* dc_offer = offer->GetContentByName("data");
1121 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001122 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001123 dcd_offer->set_use_sctpmap(false);
1124
Steve Anton6fe1fba2018-12-11 10:15:23 -08001125 std::unique_ptr<SessionDescription> answer =
1126 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001127 const ContentInfo* dc_answer = answer->GetContentByName("data");
1128 ASSERT_TRUE(dc_answer != NULL);
1129 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001130 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001131 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001132}
1133
deadbeef8b7e9ad2017-05-25 09:38:55 -07001134// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1135// and "TCP/DTLS/SCTP" offers.
1136TEST_F(MediaSessionDescriptionFactoryTest,
1137 TestCreateDataAnswerToDifferentOfferedProtos) {
1138 // Need to enable DTLS offer/answer generation (disabled by default in this
1139 // test).
1140 f1_.set_secure(SEC_ENABLED);
1141 f2_.set_secure(SEC_ENABLED);
1142 tdf1_.set_secure(SEC_ENABLED);
1143 tdf2_.set_secure(SEC_ENABLED);
1144
1145 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001146 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001147 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001148 ASSERT_TRUE(offer.get() != nullptr);
1149 ContentInfo* dc_offer = offer->GetContentByName("data");
1150 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001151 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001152
1153 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1154 "TCP/DTLS/SCTP"};
1155 for (const std::string& proto : protos) {
1156 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001157 std::unique_ptr<SessionDescription> answer =
1158 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001159 const ContentInfo* dc_answer = answer->GetContentByName("data");
1160 ASSERT_TRUE(dc_answer != nullptr);
1161 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001162 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001163 EXPECT_FALSE(dc_answer->rejected);
1164 EXPECT_EQ(proto, dcd_answer->protocol());
1165 }
1166}
1167
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001168// Verifies that the order of the media contents in the offer is preserved in
1169// the answer.
1170TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1171 MediaSessionOptions opts;
1172
1173 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001174 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001175 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001176 ASSERT_TRUE(offer1.get() != NULL);
1177
1178 // Appends audio to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001179 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1180 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001181 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001182 f1_.CreateOffer(opts, offer1.get()));
1183 ASSERT_TRUE(offer2.get() != NULL);
1184
1185 // Appends video to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001186 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1187 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001188 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001189 f1_.CreateOffer(opts, offer2.get()));
1190 ASSERT_TRUE(offer3.get() != NULL);
1191
Steve Anton6fe1fba2018-12-11 10:15:23 -08001192 std::unique_ptr<SessionDescription> answer =
1193 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001194 ASSERT_TRUE(answer.get() != NULL);
1195 EXPECT_EQ(3u, answer->contents().size());
1196 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1197 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1198 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1199}
1200
ossu075af922016-06-14 03:29:38 -07001201// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1202// answerer settings.
1203
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001204// This test that the media direction is set to send/receive in an answer if
1205// the offer is send receive.
1206TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001207 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1208 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001209}
1210
1211// This test that the media direction is set to receive only in an answer if
1212// the offer is send only.
1213TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001214 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1215 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001216}
1217
1218// This test that the media direction is set to send only in an answer if
1219// the offer is recv only.
1220TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001221 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1222 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001223}
1224
1225// This test that the media direction is set to inactive in an answer if
1226// the offer is inactive.
1227TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001228 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1229 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001230}
1231
1232// Test that a data content with an unknown protocol is rejected in an answer.
1233TEST_F(MediaSessionDescriptionFactoryTest,
1234 CreateDataAnswerToOfferWithUnknownProtocol) {
1235 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001236 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237 f1_.set_secure(SEC_ENABLED);
1238 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001239 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001240 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001241 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001242 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243 ASSERT_TRUE(dcd_offer != NULL);
1244 std::string protocol = "a weird unknown protocol";
1245 dcd_offer->set_protocol(protocol);
1246
Steve Anton6fe1fba2018-12-11 10:15:23 -08001247 std::unique_ptr<SessionDescription> answer =
1248 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001249
1250 const ContentInfo* dc_answer = answer->GetContentByName("data");
1251 ASSERT_TRUE(dc_answer != NULL);
1252 EXPECT_TRUE(dc_answer->rejected);
1253 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001254 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001255 ASSERT_TRUE(dcd_answer != NULL);
1256 EXPECT_EQ(protocol, dcd_answer->protocol());
1257}
1258
1259// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1260TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001261 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 f1_.set_secure(SEC_DISABLED);
1263 f2_.set_secure(SEC_DISABLED);
1264 tdf1_.set_secure(SEC_DISABLED);
1265 tdf2_.set_secure(SEC_DISABLED);
1266
Steve Anton6fe1fba2018-12-11 10:15:23 -08001267 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268 const AudioContentDescription* offer_acd =
1269 GetFirstAudioContentDescription(offer.get());
1270 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001271 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272
Steve Anton6fe1fba2018-12-11 10:15:23 -08001273 std::unique_ptr<SessionDescription> answer =
1274 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275
1276 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1277 ASSERT_TRUE(ac_answer != NULL);
1278 EXPECT_FALSE(ac_answer->rejected);
1279
1280 const AudioContentDescription* answer_acd =
1281 GetFirstAudioContentDescription(answer.get());
1282 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001283 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001284}
1285
1286// Create a video offer and answer and ensure the RTP header extensions
1287// matches what we expect.
1288TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1289 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001290 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001291 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1292 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1293 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1294 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1295
Steve Anton6fe1fba2018-12-11 10:15:23 -08001296 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001298 std::unique_ptr<SessionDescription> answer =
1299 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300
Yves Gerey665174f2018-06-19 15:03:05 +02001301 EXPECT_EQ(
1302 MAKE_VECTOR(kAudioRtpExtension1),
1303 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1304 EXPECT_EQ(
1305 MAKE_VECTOR(kVideoRtpExtension1),
1306 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1307 EXPECT_EQ(
1308 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1309 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1310 EXPECT_EQ(
1311 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1312 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001313}
1314
jbauch5869f502017-06-29 12:31:36 -07001315TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001316 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001317 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001318 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001319
1320 f1_.set_enable_encrypted_rtp_header_extensions(true);
1321 f2_.set_enable_encrypted_rtp_header_extensions(true);
1322
Yves Gerey665174f2018-06-19 15:03:05 +02001323 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1324 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1325 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1326 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001327
Steve Anton6fe1fba2018-12-11 10:15:23 -08001328 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001329 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001330 std::unique_ptr<SessionDescription> answer =
1331 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001332
Yves Gerey665174f2018-06-19 15:03:05 +02001333 EXPECT_EQ(
1334 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1335 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1336 EXPECT_EQ(
1337 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1338 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1339 EXPECT_EQ(
1340 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1341 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1342 EXPECT_EQ(
1343 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1344 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001345}
1346
1347TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001348 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001349 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001350 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001351
1352 f1_.set_enable_encrypted_rtp_header_extensions(true);
1353
Yves Gerey665174f2018-06-19 15:03:05 +02001354 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1355 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1356 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1357 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001358
Steve Anton6fe1fba2018-12-11 10:15:23 -08001359 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001360 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001361 std::unique_ptr<SessionDescription> answer =
1362 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001363
Yves Gerey665174f2018-06-19 15:03:05 +02001364 EXPECT_EQ(
1365 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1366 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1367 EXPECT_EQ(
1368 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1369 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1370 EXPECT_EQ(
1371 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1372 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1373 EXPECT_EQ(
1374 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1375 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001376}
1377
1378TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001379 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001380 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001381 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001382
1383 f2_.set_enable_encrypted_rtp_header_extensions(true);
1384
Yves Gerey665174f2018-06-19 15:03:05 +02001385 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1386 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1387 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1388 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001389
Steve Anton6fe1fba2018-12-11 10:15:23 -08001390 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001391 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001392 std::unique_ptr<SessionDescription> answer =
1393 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001394
Yves Gerey665174f2018-06-19 15:03:05 +02001395 EXPECT_EQ(
1396 MAKE_VECTOR(kAudioRtpExtension1),
1397 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1398 EXPECT_EQ(
1399 MAKE_VECTOR(kVideoRtpExtension1),
1400 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1401 EXPECT_EQ(
1402 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1403 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1404 EXPECT_EQ(
1405 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1406 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001407}
1408
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409// Create an audio, video, data answer without legacy StreamParams.
1410TEST_F(MediaSessionDescriptionFactoryTest,
1411 TestCreateAnswerWithoutLegacyStreams) {
1412 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001413 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1414 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001415 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001416 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001417 std::unique_ptr<SessionDescription> answer =
1418 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001419 const ContentInfo* ac = answer->GetContentByName("audio");
1420 const ContentInfo* vc = answer->GetContentByName("video");
1421 const ContentInfo* dc = answer->GetContentByName("data");
1422 ASSERT_TRUE(ac != NULL);
1423 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001424 const AudioContentDescription* acd = ac->media_description()->as_audio();
1425 const VideoContentDescription* vcd = vc->media_description()->as_video();
1426 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001427
1428 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1429 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1430 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1431}
1432
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001433// Create a typical video answer, and ensure it matches what we expect.
1434TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1435 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001436 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1437 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1438 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001439
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001440 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001441 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1442 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1443 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001444
kwiberg31022942016-03-11 14:18:21 -08001445 std::unique_ptr<SessionDescription> offer;
1446 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001447
1448 offer_opts.rtcp_mux_enabled = true;
1449 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001450 offer = f1_.CreateOffer(offer_opts, NULL);
1451 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001452 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1453 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1454 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1455 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1456 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1457 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1458 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1459 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1460 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1461 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1462 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1463 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1464
1465 offer_opts.rtcp_mux_enabled = true;
1466 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001467 offer = f1_.CreateOffer(offer_opts, NULL);
1468 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001469 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1470 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1471 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1472 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1473 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1474 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1475 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1476 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1477 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1478 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1479 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1480 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1481
1482 offer_opts.rtcp_mux_enabled = false;
1483 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001484 offer = f1_.CreateOffer(offer_opts, NULL);
1485 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001486 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1487 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1488 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1489 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1490 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1491 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1492 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1493 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1494 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1495 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1496 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1497 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1498
1499 offer_opts.rtcp_mux_enabled = false;
1500 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001501 offer = f1_.CreateOffer(offer_opts, NULL);
1502 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001503 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1504 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1505 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1506 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1507 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1508 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1509 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1510 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1511 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1512 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1513 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1514 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1515}
1516
1517// Create an audio-only answer to a video offer.
1518TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1519 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001520 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1521 kActive, &opts);
1522 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1523 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001524 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001525 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001526
1527 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001528 std::unique_ptr<SessionDescription> answer =
1529 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001530 const ContentInfo* ac = answer->GetContentByName("audio");
1531 const ContentInfo* vc = answer->GetContentByName("video");
1532 ASSERT_TRUE(ac != NULL);
1533 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001534 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001535 EXPECT_TRUE(vc->rejected);
1536}
1537
1538// Create an audio-only answer to an offer with data.
1539TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001540 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001541 opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001542 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1543 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001544 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001545 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001546
1547 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001548 std::unique_ptr<SessionDescription> answer =
1549 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001550 const ContentInfo* ac = answer->GetContentByName("audio");
1551 const ContentInfo* dc = answer->GetContentByName("data");
1552 ASSERT_TRUE(ac != NULL);
1553 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001554 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001555 EXPECT_TRUE(dc->rejected);
1556}
1557
1558// Create an answer that rejects the contents which are rejected in the offer.
1559TEST_F(MediaSessionDescriptionFactoryTest,
1560 CreateAnswerToOfferWithRejectedMedia) {
1561 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001562 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1563 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001564 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001565 ASSERT_TRUE(offer.get() != NULL);
1566 ContentInfo* ac = offer->GetContentByName("audio");
1567 ContentInfo* vc = offer->GetContentByName("video");
1568 ContentInfo* dc = offer->GetContentByName("data");
1569 ASSERT_TRUE(ac != NULL);
1570 ASSERT_TRUE(vc != NULL);
1571 ASSERT_TRUE(dc != NULL);
1572 ac->rejected = true;
1573 vc->rejected = true;
1574 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001575 std::unique_ptr<SessionDescription> answer =
1576 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001577 ac = answer->GetContentByName("audio");
1578 vc = answer->GetContentByName("video");
1579 dc = answer->GetContentByName("data");
1580 ASSERT_TRUE(ac != NULL);
1581 ASSERT_TRUE(vc != NULL);
1582 ASSERT_TRUE(dc != NULL);
1583 EXPECT_TRUE(ac->rejected);
1584 EXPECT_TRUE(vc->rejected);
1585 EXPECT_TRUE(dc->rejected);
1586}
1587
Johannes Kron0854eb62018-10-10 22:33:20 +02001588TEST_F(MediaSessionDescriptionFactoryTest,
1589 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1590 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001591 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001592 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001593 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001594 ASSERT_TRUE(offer.get() != NULL);
1595 std::unique_ptr<SessionDescription> answer_no_support(
1596 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001597 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001598
1599 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001600 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001601 ASSERT_TRUE(offer.get() != NULL);
1602 std::unique_ptr<SessionDescription> answer_support(
1603 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001604 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001605}
1606
1607TEST_F(MediaSessionDescriptionFactoryTest,
1608 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1609 MediaSessionOptions opts;
1610 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001611 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001612 MediaContentDescription* video_offer =
1613 offer->GetContentDescriptionByName("video");
1614 ASSERT_TRUE(video_offer);
1615 MediaContentDescription* audio_offer =
1616 offer->GetContentDescriptionByName("audio");
1617 ASSERT_TRUE(audio_offer);
1618
1619 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001620 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1621 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001622
1623 ASSERT_TRUE(offer.get() != NULL);
1624 std::unique_ptr<SessionDescription> answer_no_support(
1625 f2_.CreateAnswer(offer.get(), opts, NULL));
1626 MediaContentDescription* video_answer =
1627 answer_no_support->GetContentDescriptionByName("video");
1628 MediaContentDescription* audio_answer =
1629 answer_no_support->GetContentDescriptionByName("audio");
1630 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001631 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001632 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001633 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001634
1635 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001636 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1637 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001638 ASSERT_TRUE(offer.get() != NULL);
1639 std::unique_ptr<SessionDescription> answer_support(
1640 f2_.CreateAnswer(offer.get(), opts, NULL));
1641 video_answer = answer_support->GetContentDescriptionByName("video");
1642 audio_answer = answer_support->GetContentDescriptionByName("audio");
1643 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001644 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001645 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001646 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001647}
1648
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001649// Create an audio and video offer with:
1650// - one video track
1651// - two audio tracks
1652// - two data tracks
1653// and ensure it matches what we expect. Also updates the initial offer by
1654// adding a new video track and replaces one of the audio tracks.
1655TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1656 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001657 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001658 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001659 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001660 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001661 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001662 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001663 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001664
Steve Anton4e70a722017-11-28 14:57:10 -08001665 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001666 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001667 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001668 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001669 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001670
1671 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001672 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001673
1674 ASSERT_TRUE(offer.get() != NULL);
1675 const ContentInfo* ac = offer->GetContentByName("audio");
1676 const ContentInfo* vc = offer->GetContentByName("video");
1677 const ContentInfo* dc = offer->GetContentByName("data");
1678 ASSERT_TRUE(ac != NULL);
1679 ASSERT_TRUE(vc != NULL);
1680 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001681 const AudioContentDescription* acd = ac->media_description()->as_audio();
1682 const VideoContentDescription* vcd = vc->media_description()->as_video();
1683 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001684 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001685 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001686
1687 const StreamParamsVec& audio_streams = acd->streams();
1688 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001689 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001690 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1691 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1692 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1693 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1694 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1695 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1696
1697 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1698 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001699 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001700
1701 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1702 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001703 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001704
1705 const StreamParamsVec& video_streams = vcd->streams();
1706 ASSERT_EQ(1U, video_streams.size());
1707 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1708 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1709 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1710 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1711
1712 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1713 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001714 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001715
1716 const StreamParamsVec& data_streams = dcd->streams();
1717 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001718 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001719 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1720 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1721 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1722 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1723 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1724 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1725
1726 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001727 dcd->bandwidth()); // default bandwidth (auto)
1728 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001729 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 // Update the offer. Add a new video track that is not synched to the
1732 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001733 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001734 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001735 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1736 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001737 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001738 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1739 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001740 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001741 std::unique_ptr<SessionDescription> updated_offer(
1742 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001743
1744 ASSERT_TRUE(updated_offer.get() != NULL);
1745 ac = updated_offer->GetContentByName("audio");
1746 vc = updated_offer->GetContentByName("video");
1747 dc = updated_offer->GetContentByName("data");
1748 ASSERT_TRUE(ac != NULL);
1749 ASSERT_TRUE(vc != NULL);
1750 ASSERT_TRUE(dc != NULL);
1751 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001752 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001754 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001755 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001756 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001757
1758 EXPECT_EQ(acd->type(), updated_acd->type());
1759 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1760 EXPECT_EQ(vcd->type(), updated_vcd->type());
1761 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1762 EXPECT_EQ(dcd->type(), updated_dcd->type());
1763 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001764 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001765 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001766 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001768 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001769 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1770
1771 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1772 ASSERT_EQ(2U, updated_audio_streams.size());
1773 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1774 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1775 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1776 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1777 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1778
1779 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1780 ASSERT_EQ(2U, updated_video_streams.size());
1781 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1782 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001783 // All the media streams in one PeerConnection share one RTCP CNAME.
1784 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001785
1786 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1787 ASSERT_EQ(2U, updated_data_streams.size());
1788 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1789 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1790 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1791 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1792 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001793 // The stream correctly got the CNAME from the MediaSessionOptions.
1794 // The Expected RTCP CNAME is the default one as we are using the default
1795 // MediaSessionOptions.
1796 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001797}
1798
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001799// Create an offer with simulcast video stream.
1800TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1801 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001802 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1803 kActive, &opts);
1804 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1805 kActive, &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001806 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001807 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001808 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001809 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001810
1811 ASSERT_TRUE(offer.get() != NULL);
1812 const ContentInfo* vc = offer->GetContentByName("video");
1813 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001814 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001815
1816 const StreamParamsVec& video_streams = vcd->streams();
1817 ASSERT_EQ(1U, video_streams.size());
1818 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1819 const SsrcGroup* sim_ssrc_group =
1820 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1821 ASSERT_TRUE(sim_ssrc_group != NULL);
1822 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1823}
1824
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825// Create an audio and video answer to a standard video offer with:
1826// - one video track
1827// - two audio tracks
1828// - two data tracks
1829// and ensure it matches what we expect. Also updates the initial answer by
1830// adding a new video track and removes one of the audio tracks.
1831TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1832 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001833 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1834 kActive, &offer_opts);
1835 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1836 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001837 offer_opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001838 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1839 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 f1_.set_secure(SEC_ENABLED);
1841 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001842 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001843
zhihuang1c378ed2017-08-17 14:10:50 -07001844 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001845 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
1846 kActive, &answer_opts);
1847 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1848 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001849 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001850 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001851 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001852 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001853 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001854 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001855
Steve Anton4e70a722017-11-28 14:57:10 -08001856 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
1857 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001858 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001859 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001860 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001861 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001862 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001863
Steve Anton6fe1fba2018-12-11 10:15:23 -08001864 std::unique_ptr<SessionDescription> answer =
1865 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001866
1867 ASSERT_TRUE(answer.get() != NULL);
1868 const ContentInfo* ac = answer->GetContentByName("audio");
1869 const ContentInfo* vc = answer->GetContentByName("video");
1870 const ContentInfo* dc = answer->GetContentByName("data");
1871 ASSERT_TRUE(ac != NULL);
1872 ASSERT_TRUE(vc != NULL);
1873 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001874 const AudioContentDescription* acd = ac->media_description()->as_audio();
1875 const VideoContentDescription* vcd = vc->media_description()->as_video();
1876 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001877 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1878 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1879 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001880
1881 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001882 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001883
1884 const StreamParamsVec& audio_streams = acd->streams();
1885 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001886 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001887 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1888 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1889 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1890 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1891 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1892 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1893
1894 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1895 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1896
1897 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001898 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001899
1900 const StreamParamsVec& video_streams = vcd->streams();
1901 ASSERT_EQ(1U, video_streams.size());
1902 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1903 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1904 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1905 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1906
1907 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001908 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001909
1910 const StreamParamsVec& data_streams = dcd->streams();
1911 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001912 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001913 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1914 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1915 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1916 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1917 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1918 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1919
1920 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001921 dcd->bandwidth()); // default bandwidth (auto)
1922 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001923
1924 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001925 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001926 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001927 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001928 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1929 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001930 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001931 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001932
1933 ASSERT_TRUE(updated_answer.get() != NULL);
1934 ac = updated_answer->GetContentByName("audio");
1935 vc = updated_answer->GetContentByName("video");
1936 dc = updated_answer->GetContentByName("data");
1937 ASSERT_TRUE(ac != NULL);
1938 ASSERT_TRUE(vc != NULL);
1939 ASSERT_TRUE(dc != NULL);
1940 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001941 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001943 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001945 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001946
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001947 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001948 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001949 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001951 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001952 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1953
1954 EXPECT_EQ(acd->type(), updated_acd->type());
1955 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1956 EXPECT_EQ(vcd->type(), updated_vcd->type());
1957 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1958 EXPECT_EQ(dcd->type(), updated_dcd->type());
1959 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1960
1961 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1962 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001963 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001964
1965 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1966 ASSERT_EQ(2U, updated_video_streams.size());
1967 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1968 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001969 // All media streams in one PeerConnection share one CNAME.
1970 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971
1972 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1973 ASSERT_EQ(1U, updated_data_streams.size());
1974 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1975}
1976
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977// Create an updated offer after creating an answer to the original offer and
1978// verify that the codecs that were part of the original answer are not changed
1979// in the updated offer.
1980TEST_F(MediaSessionDescriptionFactoryTest,
1981 RespondentCreatesOfferAfterCreatingAnswer) {
1982 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001983 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001984
Steve Anton6fe1fba2018-12-11 10:15:23 -08001985 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1986 std::unique_ptr<SessionDescription> answer =
1987 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001988
1989 const AudioContentDescription* acd =
1990 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08001991 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001992
1993 const VideoContentDescription* vcd =
1994 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08001995 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001996
kwiberg31022942016-03-11 14:18:21 -08001997 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001998 f2_.CreateOffer(opts, answer.get()));
1999
2000 // The expected audio codecs are the common audio codecs from the first
2001 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2002 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002003 // TODO(wu): |updated_offer| should not include the codec
2004 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002005 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002006 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002007 };
2008
2009 // The expected video codecs are the common video codecs from the first
2010 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2011 // preference order.
2012 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002013 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 };
2015
2016 const AudioContentDescription* updated_acd =
2017 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002018 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002019
2020 const VideoContentDescription* updated_vcd =
2021 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002022 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002023}
2024
Steve Anton5c72e712018-12-10 14:25:30 -08002025// Test that a reoffer does not reuse audio codecs from a previous media section
2026// that is being recycled.
2027TEST_F(MediaSessionDescriptionFactoryTest,
2028 ReOfferDoesNotReUseRecycledAudioCodecs) {
2029 f1_.set_video_codecs({});
2030 f2_.set_video_codecs({});
2031
2032 MediaSessionOptions opts;
2033 AddMediaSection(MEDIA_TYPE_AUDIO, "a0", RtpTransceiverDirection::kSendRecv,
2034 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002035 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2036 std::unique_ptr<SessionDescription> answer =
2037 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002038
2039 // Recycle the media section by changing its mid.
2040 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002041 std::unique_ptr<SessionDescription> reoffer =
2042 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002043
2044 // Expect that the results of the first negotiation are ignored. If the m=
2045 // section was not recycled the payload types would match the initial offerer.
2046 const AudioContentDescription* acd =
2047 GetFirstAudioContentDescription(reoffer.get());
2048 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2049}
2050
2051// Test that a reoffer does not reuse video codecs from a previous media section
2052// that is being recycled.
2053TEST_F(MediaSessionDescriptionFactoryTest,
2054 ReOfferDoesNotReUseRecycledVideoCodecs) {
2055 f1_.set_audio_codecs({}, {});
2056 f2_.set_audio_codecs({}, {});
2057
2058 MediaSessionOptions opts;
2059 AddMediaSection(MEDIA_TYPE_VIDEO, "v0", RtpTransceiverDirection::kSendRecv,
2060 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002061 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2062 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002063
2064 // Recycle the media section by changing its mid.
2065 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002066 std::unique_ptr<SessionDescription> reoffer =
2067 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002068
2069 // Expect that the results of the first negotiation are ignored. If the m=
2070 // section was not recycled the payload types would match the initial offerer.
2071 const VideoContentDescription* vcd =
2072 GetFirstVideoContentDescription(reoffer.get());
2073 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2074}
2075
2076// Test that a reanswer does not reuse audio codecs from a previous media
2077// section that is being recycled.
2078TEST_F(MediaSessionDescriptionFactoryTest,
2079 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2080 f1_.set_video_codecs({});
2081 f2_.set_video_codecs({});
2082
2083 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2084 // second offer/answer is forward (|f1_| as offerer).
2085 MediaSessionOptions opts;
2086 AddMediaSection(MEDIA_TYPE_AUDIO, "a0", RtpTransceiverDirection::kSendRecv,
2087 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002088 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2089 std::unique_ptr<SessionDescription> answer =
2090 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002091
2092 // Recycle the media section by changing its mid.
2093 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002094 std::unique_ptr<SessionDescription> reoffer =
2095 f1_.CreateOffer(opts, answer.get());
2096 std::unique_ptr<SessionDescription> reanswer =
2097 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002098
2099 // Expect that the results of the first negotiation are ignored. If the m=
2100 // section was not recycled the payload types would match the initial offerer.
2101 const AudioContentDescription* acd =
2102 GetFirstAudioContentDescription(reanswer.get());
2103 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2104}
2105
2106// Test that a reanswer does not reuse video codecs from a previous media
2107// section that is being recycled.
2108TEST_F(MediaSessionDescriptionFactoryTest,
2109 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2110 f1_.set_audio_codecs({}, {});
2111 f2_.set_audio_codecs({}, {});
2112
2113 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2114 // second offer/answer is forward (|f1_| as offerer).
2115 MediaSessionOptions opts;
2116 AddMediaSection(MEDIA_TYPE_VIDEO, "v0", RtpTransceiverDirection::kSendRecv,
2117 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002118 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2119 std::unique_ptr<SessionDescription> answer =
2120 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002121
2122 // Recycle the media section by changing its mid.
2123 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002124 std::unique_ptr<SessionDescription> reoffer =
2125 f1_.CreateOffer(opts, answer.get());
2126 std::unique_ptr<SessionDescription> reanswer =
2127 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002128
2129 // Expect that the results of the first negotiation are ignored. If the m=
2130 // section was not recycled the payload types would match the initial offerer.
2131 const VideoContentDescription* vcd =
2132 GetFirstVideoContentDescription(reanswer.get());
2133 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2134}
2135
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002136// Create an updated offer after creating an answer to the original offer and
2137// verify that the codecs that were part of the original answer are not changed
2138// in the updated offer. In this test Rtx is enabled.
2139TEST_F(MediaSessionDescriptionFactoryTest,
2140 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2141 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002142 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2143 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002144 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002145 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002146 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002147 f1_.set_video_codecs(f1_codecs);
2148
2149 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002150 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002151 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002152 f2_.set_video_codecs(f2_codecs);
2153
Steve Anton6fe1fba2018-12-11 10:15:23 -08002154 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002156 std::unique_ptr<SessionDescription> answer =
2157 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002158
2159 const VideoContentDescription* vcd =
2160 GetFirstVideoContentDescription(answer.get());
2161
2162 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002163 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2164 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002165
2166 EXPECT_EQ(expected_codecs, vcd->codecs());
2167
deadbeef67cf2c12016-04-13 10:07:16 -07002168 // Now, make sure we get same result (except for the order) if |f2_| creates
2169 // an updated offer even though the default payload types between |f1_| and
2170 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002171 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002172 f2_.CreateOffer(opts, answer.get()));
2173 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002174 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002175 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2176
2177 const VideoContentDescription* updated_vcd =
2178 GetFirstVideoContentDescription(updated_answer.get());
2179
2180 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2181}
2182
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002183// Regression test for:
2184// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2185// Existing codecs should always appear before new codecs in re-offers. But
2186// under a specific set of circumstances, the existing RTX codec was ending up
2187// added to the end of the list.
2188TEST_F(MediaSessionDescriptionFactoryTest,
2189 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2190 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002191 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2192 kActive, &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002193 // We specifically choose different preferred payload types for VP8 to
2194 // trigger the issue.
2195 cricket::VideoCodec vp8_offerer(100, "VP8");
2196 cricket::VideoCodec vp8_offerer_rtx =
2197 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2198 cricket::VideoCodec vp8_answerer(110, "VP8");
2199 cricket::VideoCodec vp8_answerer_rtx =
2200 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2201 cricket::VideoCodec vp9(120, "VP9");
2202 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2203
2204 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2205 // We also specifically cause the answerer to prefer VP9, such that if it
2206 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2207 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2208 vp8_answerer_rtx};
2209
2210 f1_.set_video_codecs(f1_codecs);
2211 f2_.set_video_codecs(f2_codecs);
2212 std::vector<AudioCodec> audio_codecs;
2213 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2214 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2215
2216 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002217 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002218 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002219 std::unique_ptr<SessionDescription> answer =
2220 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002221
2222 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2223 // But if the bug is triggered, RTX for VP8 ends up last.
2224 std::unique_ptr<SessionDescription> updated_offer(
2225 f2_.CreateOffer(opts, answer.get()));
2226
2227 const VideoContentDescription* vcd =
2228 GetFirstVideoContentDescription(updated_offer.get());
2229 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2230 ASSERT_EQ(4u, codecs.size());
2231 EXPECT_EQ(vp8_offerer, codecs[0]);
2232 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2233 EXPECT_EQ(vp9, codecs[2]);
2234 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002235}
2236
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002237// Create an updated offer that adds video after creating an audio only answer
2238// to the original offer. This test verifies that if a video codec and the RTX
2239// codec have the same default payload type as an audio codec that is already in
2240// use, the added codecs payload types are changed.
2241TEST_F(MediaSessionDescriptionFactoryTest,
2242 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2243 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002245 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002246 f1_.set_video_codecs(f1_codecs);
2247
2248 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002249 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2250 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002251
Steve Anton6fe1fba2018-12-11 10:15:23 -08002252 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2253 std::unique_ptr<SessionDescription> answer =
2254 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002255
2256 const AudioContentDescription* acd =
2257 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002258 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002259
2260 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2261 // reference be the same as an audio codec that was negotiated in the
2262 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002263 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002264 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002265
2266 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2267 int used_pl_type = acd->codecs()[0].id;
2268 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002269 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002270 f2_.set_video_codecs(f2_codecs);
2271
kwiberg31022942016-03-11 14:18:21 -08002272 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002273 f2_.CreateOffer(opts, answer.get()));
2274 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002275 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002276 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2277
2278 const AudioContentDescription* updated_acd =
2279 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002280 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002281
2282 const VideoContentDescription* updated_vcd =
2283 GetFirstVideoContentDescription(updated_answer.get());
2284
2285 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002286 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002287 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002288 EXPECT_NE(used_pl_type, new_h264_pl_type);
2289 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002290 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002291 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2292 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2293}
2294
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002295// Create an updated offer with RTX after creating an answer to an offer
2296// without RTX, and with different default payload types.
2297// Verify that the added RTX codec references the correct payload type.
2298TEST_F(MediaSessionDescriptionFactoryTest,
2299 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2300 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002301 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002302
2303 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2304 // This creates rtx for H264 with the payload type |f2_| uses.
2305 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2306 f2_.set_video_codecs(f2_codecs);
2307
Steve Anton6fe1fba2018-12-11 10:15:23 -08002308 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002309 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002310 std::unique_ptr<SessionDescription> answer =
2311 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002312
2313 const VideoContentDescription* vcd =
2314 GetFirstVideoContentDescription(answer.get());
2315
2316 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2317 EXPECT_EQ(expected_codecs, vcd->codecs());
2318
2319 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2320 // updated offer, even though the default payload types are different from
2321 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002322 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002323 f2_.CreateOffer(opts, answer.get()));
2324 ASSERT_TRUE(updated_offer);
2325
2326 const VideoContentDescription* updated_vcd =
2327 GetFirstVideoContentDescription(updated_offer.get());
2328
2329 // New offer should attempt to add H263, and RTX for H264.
2330 expected_codecs.push_back(kVideoCodecs2[1]);
2331 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2332 &expected_codecs);
2333 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2334}
2335
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002336// Test that RTX is ignored when there is no associated payload type parameter.
2337TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2338 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002339 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2340 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002341 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002342 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002343 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002344 f1_.set_video_codecs(f1_codecs);
2345
2346 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002347 // This creates RTX for H264 with the payload type |f2_| uses.
2348 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002349 f2_.set_video_codecs(f2_codecs);
2350
Steve Anton6fe1fba2018-12-11 10:15:23 -08002351 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002352 ASSERT_TRUE(offer.get() != NULL);
2353 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2354 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2355 // is possible to test that that RTX is dropped when
2356 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002357 MediaContentDescription* media_desc =
2358 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2359 ASSERT_TRUE(media_desc);
2360 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002361 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002362 for (VideoCodec& codec : codecs) {
2363 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2364 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002365 }
2366 }
2367 desc->set_codecs(codecs);
2368
Steve Anton6fe1fba2018-12-11 10:15:23 -08002369 std::unique_ptr<SessionDescription> answer =
2370 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002371
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002372 std::vector<std::string> codec_names =
2373 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2374 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2375 cricket::kRtxCodecName));
2376}
2377
2378// Test that RTX will be filtered out in the answer if its associated payload
2379// type doesn't match the local value.
2380TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2381 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002382 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2383 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002384 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2385 // This creates RTX for H264 in sender.
2386 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2387 f1_.set_video_codecs(f1_codecs);
2388
2389 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2390 // This creates RTX for H263 in receiver.
2391 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2392 f2_.set_video_codecs(f2_codecs);
2393
Steve Anton6fe1fba2018-12-11 10:15:23 -08002394 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002395 ASSERT_TRUE(offer.get() != NULL);
2396 // Associated payload type doesn't match, therefore, RTX codec is removed in
2397 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002398 std::unique_ptr<SessionDescription> answer =
2399 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002400
2401 std::vector<std::string> codec_names =
2402 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2403 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2404 cricket::kRtxCodecName));
2405}
2406
2407// Test that when multiple RTX codecs are offered, only the matched RTX codec
2408// is added in the answer, and the unsupported RTX codec is filtered out.
2409TEST_F(MediaSessionDescriptionFactoryTest,
2410 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2411 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002412 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2413 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002414 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2415 // This creates RTX for H264-SVC in sender.
2416 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2417 f1_.set_video_codecs(f1_codecs);
2418
2419 // This creates RTX for H264 in sender.
2420 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2421 f1_.set_video_codecs(f1_codecs);
2422
2423 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2424 // This creates RTX for H264 in receiver.
2425 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2426 f2_.set_video_codecs(f2_codecs);
2427
2428 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2429 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002430 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002431 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002432 std::unique_ptr<SessionDescription> answer =
2433 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002434 const VideoContentDescription* vcd =
2435 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002436 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2437 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2438 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002439
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002440 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002441}
2442
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002443// Test that after one RTX codec has been negotiated, a new offer can attempt
2444// to add another.
2445TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2446 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002447 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2448 kActive, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002449 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2450 // This creates RTX for H264 for the offerer.
2451 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2452 f1_.set_video_codecs(f1_codecs);
2453
Steve Anton6fe1fba2018-12-11 10:15:23 -08002454 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002455 ASSERT_TRUE(offer);
2456 const VideoContentDescription* vcd =
2457 GetFirstVideoContentDescription(offer.get());
2458
2459 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2460 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2461 &expected_codecs);
2462 EXPECT_EQ(expected_codecs, vcd->codecs());
2463
2464 // Now, attempt to add RTX for H264-SVC.
2465 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2466 f1_.set_video_codecs(f1_codecs);
2467
kwiberg31022942016-03-11 14:18:21 -08002468 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002469 f1_.CreateOffer(opts, offer.get()));
2470 ASSERT_TRUE(updated_offer);
2471 vcd = GetFirstVideoContentDescription(updated_offer.get());
2472
2473 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2474 &expected_codecs);
2475 EXPECT_EQ(expected_codecs, vcd->codecs());
2476}
2477
Noah Richards2e7a0982015-05-18 14:02:54 -07002478// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2479// generated for each simulcast ssrc and correctly grouped.
2480TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2481 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002482 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2483 kActive, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002484 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002485 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002486 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002487
2488 // Use a single real codec, and then add RTX for it.
2489 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002490 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002491 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2492 f1_.set_video_codecs(f1_codecs);
2493
2494 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2495 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002496 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002497 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002498 MediaContentDescription* media_desc =
2499 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2500 ASSERT_TRUE(media_desc);
2501 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002502 const StreamParamsVec& streams = desc->streams();
2503 // Single stream.
2504 ASSERT_EQ(1u, streams.size());
2505 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2506 EXPECT_EQ(6u, streams[0].ssrcs.size());
2507 // And should have a SIM group for the simulcast.
2508 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2509 // And a FID group for RTX.
2510 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002511 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002512 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2513 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002514 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002515 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2516 EXPECT_EQ(3u, fid_ssrcs.size());
2517}
2518
brandtr03d5fb12016-11-22 03:37:59 -08002519// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2520// together with a FEC-FR grouping.
2521TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2522 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002523 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2524 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002525 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002526 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002527 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002528
2529 // Use a single real codec, and then add FlexFEC for it.
2530 std::vector<VideoCodec> f1_codecs;
2531 f1_codecs.push_back(VideoCodec(97, "H264"));
2532 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2533 f1_.set_video_codecs(f1_codecs);
2534
2535 // Ensure that the offer has a single FlexFEC ssrc and that
2536 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002537 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002538 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002539 MediaContentDescription* media_desc =
2540 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2541 ASSERT_TRUE(media_desc);
2542 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002543 const StreamParamsVec& streams = desc->streams();
2544 // Single stream.
2545 ASSERT_EQ(1u, streams.size());
2546 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2547 EXPECT_EQ(2u, streams[0].ssrcs.size());
2548 // And should have a FEC-FR group for FlexFEC.
2549 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2550 std::vector<uint32_t> primary_ssrcs;
2551 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2552 ASSERT_EQ(1u, primary_ssrcs.size());
2553 uint32_t flexfec_ssrc;
2554 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2555 EXPECT_NE(flexfec_ssrc, 0u);
2556}
2557
2558// Test that FlexFEC is disabled for simulcast.
2559// TODO(brandtr): Remove this test when we support simulcast, either through
2560// multiple FlexfecSenders, or through multistream protection.
2561TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2562 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002563 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2564 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002565 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002566 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002567 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002568
2569 // Use a single real codec, and then add FlexFEC for it.
2570 std::vector<VideoCodec> f1_codecs;
2571 f1_codecs.push_back(VideoCodec(97, "H264"));
2572 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2573 f1_.set_video_codecs(f1_codecs);
2574
2575 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2576 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002577 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002578 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002579 MediaContentDescription* media_desc =
2580 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2581 ASSERT_TRUE(media_desc);
2582 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002583 const StreamParamsVec& streams = desc->streams();
2584 // Single stream.
2585 ASSERT_EQ(1u, streams.size());
2586 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2587 EXPECT_EQ(3u, streams[0].ssrcs.size());
2588 // And should have a SIM group for the simulcast.
2589 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2590 // And not a FEC-FR group for FlexFEC.
2591 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2592 std::vector<uint32_t> primary_ssrcs;
2593 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2594 EXPECT_EQ(3u, primary_ssrcs.size());
2595 for (uint32_t primary_ssrc : primary_ssrcs) {
2596 uint32_t flexfec_ssrc;
2597 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2598 }
2599}
2600
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002601// Create an updated offer after creating an answer to the original offer and
2602// verify that the RTP header extensions that were part of the original answer
2603// are not changed in the updated offer.
2604TEST_F(MediaSessionDescriptionFactoryTest,
2605 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2606 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002607 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002608
2609 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2610 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2611 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2612 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2613
Steve Anton6fe1fba2018-12-11 10:15:23 -08002614 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2615 std::unique_ptr<SessionDescription> answer =
2616 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002617
Yves Gerey665174f2018-06-19 15:03:05 +02002618 EXPECT_EQ(
2619 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2620 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2621 EXPECT_EQ(
2622 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2623 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002624
kwiberg31022942016-03-11 14:18:21 -08002625 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002626 f2_.CreateOffer(opts, answer.get()));
2627
2628 // The expected RTP header extensions in the new offer are the resulting
2629 // extensions from the first offer/answer exchange plus the extensions only
2630 // |f2_| offer.
2631 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002632 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002633 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2634 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2635 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002636 };
2637
2638 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002639 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002640 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2641 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2642 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002643 };
2644
2645 const AudioContentDescription* updated_acd =
2646 GetFirstAudioContentDescription(updated_offer.get());
2647 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2648 updated_acd->rtp_header_extensions());
2649
2650 const VideoContentDescription* updated_vcd =
2651 GetFirstVideoContentDescription(updated_offer.get());
2652 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2653 updated_vcd->rtp_header_extensions());
2654}
2655
deadbeefa5b273a2015-08-20 17:30:13 -07002656// Verify that if the same RTP extension URI is used for audio and video, the
2657// same ID is used. Also verify that the ID isn't changed when creating an
2658// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002659TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002660 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002661 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002662
2663 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2664 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2665
Steve Anton6fe1fba2018-12-11 10:15:23 -08002666 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07002667
2668 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2669 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002670 const RtpExtension kExpectedVideoRtpExtension[] = {
2671 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002672 };
2673
Yves Gerey665174f2018-06-19 15:03:05 +02002674 EXPECT_EQ(
2675 MAKE_VECTOR(kAudioRtpExtension3),
2676 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2677 EXPECT_EQ(
2678 MAKE_VECTOR(kExpectedVideoRtpExtension),
2679 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002680
2681 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002682 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002683 f1_.CreateOffer(opts, offer.get()));
2684
2685 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02002686 GetFirstAudioContentDescription(updated_offer.get())
2687 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002688 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002689 GetFirstVideoContentDescription(updated_offer.get())
2690 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002691}
2692
jbauch5869f502017-06-29 12:31:36 -07002693// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2694TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2695 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002696 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002697
2698 f1_.set_enable_encrypted_rtp_header_extensions(true);
2699 f2_.set_enable_encrypted_rtp_header_extensions(true);
2700
2701 f1_.set_audio_rtp_header_extensions(
2702 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2703 f1_.set_video_rtp_header_extensions(
2704 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2705
Steve Anton6fe1fba2018-12-11 10:15:23 -08002706 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002707
2708 // The extensions that are shared between audio and video should use the same
2709 // id.
2710 const RtpExtension kExpectedVideoRtpExtension[] = {
2711 kVideoRtpExtension3ForEncryption[0],
2712 kAudioRtpExtension3ForEncryptionOffer[1],
2713 kAudioRtpExtension3ForEncryptionOffer[2],
2714 };
2715
Yves Gerey665174f2018-06-19 15:03:05 +02002716 EXPECT_EQ(
2717 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2718 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2719 EXPECT_EQ(
2720 MAKE_VECTOR(kExpectedVideoRtpExtension),
2721 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002722
2723 // Nothing should change when creating a new offer
2724 std::unique_ptr<SessionDescription> updated_offer(
2725 f1_.CreateOffer(opts, offer.get()));
2726
2727 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02002728 GetFirstAudioContentDescription(updated_offer.get())
2729 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002730 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002731 GetFirstVideoContentDescription(updated_offer.get())
2732 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002733}
2734
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002735TEST(MediaSessionDescription, CopySessionDescription) {
2736 SessionDescription source;
2737 cricket::ContentGroup group(cricket::CN_AUDIO);
2738 source.AddGroup(group);
2739 AudioContentDescription* acd(new AudioContentDescription());
2740 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2741 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08002742 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002743 VideoContentDescription* vcd(new VideoContentDescription());
2744 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2745 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08002746 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002747
kwiberg31022942016-03-11 14:18:21 -08002748 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002749 ASSERT_TRUE(copy.get() != NULL);
2750 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2751 const ContentInfo* ac = copy->GetContentByName("audio");
2752 const ContentInfo* vc = copy->GetContentByName("video");
2753 ASSERT_TRUE(ac != NULL);
2754 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08002755 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002756 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002757 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2758 EXPECT_EQ(1u, acd->first_ssrc());
2759
Steve Anton5adfafd2017-12-20 16:34:00 -08002760 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002761 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002762 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2763 EXPECT_EQ(2u, vcd->first_ssrc());
2764}
2765
2766// The below TestTransportInfoXXX tests create different offers/answers, and
2767// ensure the TransportInfo in the SessionDescription matches what we expect.
2768TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2769 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002770 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2771 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002772 TestTransportInfo(true, options, false);
2773}
2774
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002775TEST_F(MediaSessionDescriptionFactoryTest,
2776 TestTransportInfoOfferIceRenomination) {
2777 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002778 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2779 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002780 options.media_description_options[0]
2781 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002782 TestTransportInfo(true, options, false);
2783}
2784
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002785TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2786 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002787 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2788 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002789 TestTransportInfo(true, options, true);
2790}
2791
2792TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2793 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002794 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2795 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2796 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002797 TestTransportInfo(true, options, false);
2798}
2799
2800TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002801 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002802 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002803 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2804 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2805 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002806 TestTransportInfo(true, options, true);
2807}
2808
2809TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2810 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002811 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2812 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2813 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814 options.bundle_enabled = true;
2815 TestTransportInfo(true, options, false);
2816}
2817
2818TEST_F(MediaSessionDescriptionFactoryTest,
2819 TestTransportInfoOfferBundleCurrent) {
2820 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002821 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2822 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2823 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002824 options.bundle_enabled = true;
2825 TestTransportInfo(true, options, true);
2826}
2827
2828TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2829 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002830 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2831 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002832 TestTransportInfo(false, options, false);
2833}
2834
2835TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002836 TestTransportInfoAnswerIceRenomination) {
2837 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002838 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2839 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002840 options.media_description_options[0]
2841 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002842 TestTransportInfo(false, options, false);
2843}
2844
2845TEST_F(MediaSessionDescriptionFactoryTest,
2846 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002847 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002848 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2849 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002850 TestTransportInfo(false, options, true);
2851}
2852
2853TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2854 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002855 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2856 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2857 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002858 TestTransportInfo(false, options, false);
2859}
2860
2861TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002862 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002863 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002864 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2865 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2866 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002867 TestTransportInfo(false, options, true);
2868}
2869
2870TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2871 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002872 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2873 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2874 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002875 options.bundle_enabled = true;
2876 TestTransportInfo(false, options, false);
2877}
2878
2879TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002880 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002881 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002882 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2883 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2884 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002885 options.bundle_enabled = true;
2886 TestTransportInfo(false, options, true);
2887}
2888
2889// Create an offer with bundle enabled and verify the crypto parameters are
2890// the common set of the available cryptos.
2891TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2892 TestCryptoWithBundle(true);
2893}
2894
2895// Create an answer with bundle enabled and verify the crypto parameters are
2896// the common set of the available cryptos.
2897TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2898 TestCryptoWithBundle(false);
2899}
2900
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002901// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2902// DTLS is not enabled locally.
2903TEST_F(MediaSessionDescriptionFactoryTest,
2904 TestOfferDtlsSavpfWithoutDtlsFailed) {
2905 f1_.set_secure(SEC_ENABLED);
2906 f2_.set_secure(SEC_ENABLED);
2907 tdf1_.set_secure(SEC_DISABLED);
2908 tdf2_.set_secure(SEC_DISABLED);
2909
Steve Anton6fe1fba2018-12-11 10:15:23 -08002910 std::unique_ptr<SessionDescription> offer =
2911 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002912 ASSERT_TRUE(offer.get() != NULL);
2913 ContentInfo* offer_content = offer->GetContentByName("audio");
2914 ASSERT_TRUE(offer_content != NULL);
2915 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002916 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002917 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2918
Steve Anton6fe1fba2018-12-11 10:15:23 -08002919 std::unique_ptr<SessionDescription> answer =
2920 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002921 ASSERT_TRUE(answer != NULL);
2922 ContentInfo* answer_content = answer->GetContentByName("audio");
2923 ASSERT_TRUE(answer_content != NULL);
2924
2925 ASSERT_TRUE(answer_content->rejected);
2926}
2927
2928// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2929// UDP/TLS/RTP/SAVPF.
2930TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2931 f1_.set_secure(SEC_ENABLED);
2932 f2_.set_secure(SEC_ENABLED);
2933 tdf1_.set_secure(SEC_ENABLED);
2934 tdf2_.set_secure(SEC_ENABLED);
2935
Steve Anton6fe1fba2018-12-11 10:15:23 -08002936 std::unique_ptr<SessionDescription> offer =
2937 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002938 ASSERT_TRUE(offer.get() != NULL);
2939 ContentInfo* offer_content = offer->GetContentByName("audio");
2940 ASSERT_TRUE(offer_content != NULL);
2941 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002942 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002943 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2944
Steve Anton6fe1fba2018-12-11 10:15:23 -08002945 std::unique_ptr<SessionDescription> answer =
2946 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002947 ASSERT_TRUE(answer != NULL);
2948
2949 const ContentInfo* answer_content = answer->GetContentByName("audio");
2950 ASSERT_TRUE(answer_content != NULL);
2951 ASSERT_FALSE(answer_content->rejected);
2952
2953 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002954 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08002955 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002956}
2957
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002958// Test that we include both SDES and DTLS in the offer, but only include SDES
2959// in the answer if DTLS isn't negotiated.
2960TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2961 f1_.set_secure(SEC_ENABLED);
2962 f2_.set_secure(SEC_ENABLED);
2963 tdf1_.set_secure(SEC_ENABLED);
2964 tdf2_.set_secure(SEC_DISABLED);
2965 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002966 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002967 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002968 const cricket::MediaContentDescription* audio_media_desc;
2969 const cricket::MediaContentDescription* video_media_desc;
2970 const cricket::TransportDescription* audio_trans_desc;
2971 const cricket::TransportDescription* video_trans_desc;
2972
2973 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002974 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002975 ASSERT_TRUE(offer.get() != NULL);
2976
Steve Antonb1c1de12017-12-21 15:14:30 -08002977 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002978 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002979 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002981 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002982 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2983
2984 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2985 ASSERT_TRUE(audio_trans_desc != NULL);
2986 video_trans_desc = offer->GetTransportDescriptionByName("video");
2987 ASSERT_TRUE(video_trans_desc != NULL);
2988 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2989 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2990
2991 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002992 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002993 ASSERT_TRUE(answer.get() != NULL);
2994
Steve Antonb1c1de12017-12-21 15:14:30 -08002995 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002996 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002997 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002998 ASSERT_TRUE(video_media_desc != NULL);
2999 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3000 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3001
3002 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3003 ASSERT_TRUE(audio_trans_desc != NULL);
3004 video_trans_desc = answer->GetTransportDescriptionByName("video");
3005 ASSERT_TRUE(video_trans_desc != NULL);
3006 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3007 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3008
3009 // Enable DTLS; the answer should now only have DTLS support.
3010 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003011 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003012 ASSERT_TRUE(answer.get() != NULL);
3013
Steve Antonb1c1de12017-12-21 15:14:30 -08003014 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003015 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003016 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003017 ASSERT_TRUE(video_media_desc != NULL);
3018 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3019 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003020 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3021 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003022
3023 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3024 ASSERT_TRUE(audio_trans_desc != NULL);
3025 video_trans_desc = answer->GetTransportDescriptionByName("video");
3026 ASSERT_TRUE(video_trans_desc != NULL);
3027 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3028 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003029
3030 // Try creating offer again. DTLS enabled now, crypto's should be empty
3031 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003032 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003033 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003034 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003035 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003036 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003037 ASSERT_TRUE(video_media_desc != NULL);
3038 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3039 EXPECT_TRUE(video_media_desc->cryptos().empty());
3040
3041 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3042 ASSERT_TRUE(audio_trans_desc != NULL);
3043 video_trans_desc = offer->GetTransportDescriptionByName("video");
3044 ASSERT_TRUE(video_trans_desc != NULL);
3045 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3046 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003047}
3048
3049// Test that an answer can't be created if cryptos are required but the offer is
3050// unsecure.
3051TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003052 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003053 f1_.set_secure(SEC_DISABLED);
3054 tdf1_.set_secure(SEC_DISABLED);
3055 f2_.set_secure(SEC_REQUIRED);
3056 tdf1_.set_secure(SEC_ENABLED);
3057
Steve Anton6fe1fba2018-12-11 10:15:23 -08003058 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003059 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003060 std::unique_ptr<SessionDescription> answer =
3061 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003062 EXPECT_TRUE(answer.get() == NULL);
3063}
3064
3065// Test that we accept a DTLS offer without SDES and create an appropriate
3066// answer.
3067TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3068 f1_.set_secure(SEC_DISABLED);
3069 f2_.set_secure(SEC_ENABLED);
3070 tdf1_.set_secure(SEC_ENABLED);
3071 tdf2_.set_secure(SEC_ENABLED);
3072 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003073 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3074 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3075 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003076
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003077 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003078 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003079 ASSERT_TRUE(offer.get() != NULL);
3080
3081 const AudioContentDescription* audio_offer =
3082 GetFirstAudioContentDescription(offer.get());
3083 ASSERT_TRUE(audio_offer->cryptos().empty());
3084 const VideoContentDescription* video_offer =
3085 GetFirstVideoContentDescription(offer.get());
3086 ASSERT_TRUE(video_offer->cryptos().empty());
3087 const DataContentDescription* data_offer =
3088 GetFirstDataContentDescription(offer.get());
3089 ASSERT_TRUE(data_offer->cryptos().empty());
3090
3091 const cricket::TransportDescription* audio_offer_trans_desc =
3092 offer->GetTransportDescriptionByName("audio");
3093 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3094 const cricket::TransportDescription* video_offer_trans_desc =
3095 offer->GetTransportDescriptionByName("video");
3096 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3097 const cricket::TransportDescription* data_offer_trans_desc =
3098 offer->GetTransportDescriptionByName("data");
3099 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3100
3101 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003102 std::unique_ptr<SessionDescription> answer =
3103 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003104 ASSERT_TRUE(answer.get() != NULL);
3105
3106 const cricket::TransportDescription* audio_answer_trans_desc =
3107 answer->GetTransportDescriptionByName("audio");
3108 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3109 const cricket::TransportDescription* video_answer_trans_desc =
3110 answer->GetTransportDescriptionByName("video");
3111 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3112 const cricket::TransportDescription* data_answer_trans_desc =
3113 answer->GetTransportDescriptionByName("data");
3114 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3115}
3116
3117// Verifies if vad_enabled option is set to false, CN codecs are not present in
3118// offer or answer.
3119TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3120 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003121 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003122 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003123 ASSERT_TRUE(offer.get() != NULL);
3124 const ContentInfo* audio_content = offer->GetContentByName("audio");
3125 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3126
3127 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003128 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003129 ASSERT_TRUE(offer.get() != NULL);
3130 audio_content = offer->GetContentByName("audio");
3131 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003132 std::unique_ptr<SessionDescription> answer =
3133 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003134 ASSERT_TRUE(answer.get() != NULL);
3135 audio_content = answer->GetContentByName("audio");
3136 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3137}
deadbeef44f08192015-12-15 16:20:09 -08003138
zhihuang1c378ed2017-08-17 14:10:50 -07003139// Test that the generated MIDs match the existing offer.
3140TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003141 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003142 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
3143 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
3144 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
3145 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08003146 opts.data_channel_type = cricket::DCT_SCTP;
Steve Anton4e70a722017-11-28 14:57:10 -08003147 AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
3148 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003149 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003150 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003151 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003152 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003153
deadbeef44f08192015-12-15 16:20:09 -08003154 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3155 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3156 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3157 ASSERT_TRUE(audio_content != nullptr);
3158 ASSERT_TRUE(video_content != nullptr);
3159 ASSERT_TRUE(data_content != nullptr);
3160 EXPECT_EQ("audio_modified", audio_content->name);
3161 EXPECT_EQ("video_modified", video_content->name);
3162 EXPECT_EQ("data_modified", data_content->name);
3163}
zhihuangcf5b37c2016-05-05 11:44:35 -07003164
zhihuang1c378ed2017-08-17 14:10:50 -07003165// The following tests verify that the unified plan SDP is supported.
3166// Test that we can create an offer with multiple media sections of same media
3167// type.
3168TEST_F(MediaSessionDescriptionFactoryTest,
3169 CreateOfferWithMultipleAVMediaSections) {
3170 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003171 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3172 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003173 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003174 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003175
Steve Anton4e70a722017-11-28 14:57:10 -08003176 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3177 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003178 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003179 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003180
Steve Anton4e70a722017-11-28 14:57:10 -08003181 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3182 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003183 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003184 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003185
Steve Anton4e70a722017-11-28 14:57:10 -08003186 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3187 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003188 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003189 {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003190 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003191 ASSERT_TRUE(offer);
3192
3193 ASSERT_EQ(4u, offer->contents().size());
3194 EXPECT_FALSE(offer->contents()[0].rejected);
3195 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003196 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003197 ASSERT_EQ(1u, acd->streams().size());
3198 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003199 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003200
3201 EXPECT_FALSE(offer->contents()[1].rejected);
3202 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003203 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003204 ASSERT_EQ(1u, vcd->streams().size());
3205 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003206 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003207
3208 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003209 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003210 ASSERT_EQ(1u, acd->streams().size());
3211 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003212 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003213
3214 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003215 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003216 ASSERT_EQ(1u, vcd->streams().size());
3217 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003218 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003219}
3220
3221// Test that we can create an answer with multiple media sections of same media
3222// type.
3223TEST_F(MediaSessionDescriptionFactoryTest,
3224 CreateAnswerWithMultipleAVMediaSections) {
3225 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003226 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3227 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003228 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003229 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003230
Steve Anton4e70a722017-11-28 14:57:10 -08003231 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3232 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003233 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003234 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003235
Steve Anton4e70a722017-11-28 14:57:10 -08003236 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3237 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003238 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003239 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003240
Steve Anton4e70a722017-11-28 14:57:10 -08003241 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3242 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003243 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003244 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003245
Steve Anton6fe1fba2018-12-11 10:15:23 -08003246 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003247 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003248 std::unique_ptr<SessionDescription> answer =
3249 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003250
3251 ASSERT_EQ(4u, answer->contents().size());
3252 EXPECT_FALSE(answer->contents()[0].rejected);
3253 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003254 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003255 ASSERT_EQ(1u, acd->streams().size());
3256 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003257 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003258
3259 EXPECT_FALSE(answer->contents()[1].rejected);
3260 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003261 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003262 ASSERT_EQ(1u, vcd->streams().size());
3263 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003264 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003265
3266 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003267 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003268 ASSERT_EQ(1u, acd->streams().size());
3269 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003270 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003271
3272 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003273 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003274 ASSERT_EQ(1u, vcd->streams().size());
3275 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003276 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003277}
3278
3279// Test that the media section will be rejected in offer if the corresponding
3280// MediaDescriptionOptions is stopped by the offerer.
3281TEST_F(MediaSessionDescriptionFactoryTest,
3282 CreateOfferWithMediaSectionStoppedByOfferer) {
3283 // Create an offer with two audio sections and one of them is stopped.
3284 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003285 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3286 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3287 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3288 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003289 std::unique_ptr<SessionDescription> offer =
3290 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003291 ASSERT_TRUE(offer);
3292 ASSERT_EQ(2u, offer->contents().size());
3293 EXPECT_FALSE(offer->contents()[0].rejected);
3294 EXPECT_TRUE(offer->contents()[1].rejected);
3295}
3296
3297// Test that the media section will be rejected in answer if the corresponding
3298// MediaDescriptionOptions is stopped by the offerer.
3299TEST_F(MediaSessionDescriptionFactoryTest,
3300 CreateAnswerWithMediaSectionStoppedByOfferer) {
3301 // Create an offer with two audio sections and one of them is stopped.
3302 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003303 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3304 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3305 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3306 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003307 std::unique_ptr<SessionDescription> offer =
3308 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003309 ASSERT_TRUE(offer);
3310 ASSERT_EQ(2u, offer->contents().size());
3311 EXPECT_FALSE(offer->contents()[0].rejected);
3312 EXPECT_TRUE(offer->contents()[1].rejected);
3313
3314 // Create an answer based on the offer.
3315 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003316 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3317 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3318 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3319 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003320 std::unique_ptr<SessionDescription> answer =
3321 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003322 ASSERT_EQ(2u, answer->contents().size());
3323 EXPECT_FALSE(answer->contents()[0].rejected);
3324 EXPECT_TRUE(answer->contents()[1].rejected);
3325}
3326
3327// Test that the media section will be rejected in answer if the corresponding
3328// MediaDescriptionOptions is stopped by the answerer.
3329TEST_F(MediaSessionDescriptionFactoryTest,
3330 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3331 // Create an offer with two audio sections.
3332 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003333 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3334 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3335 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3336 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003337 std::unique_ptr<SessionDescription> offer =
3338 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003339 ASSERT_TRUE(offer);
3340 ASSERT_EQ(2u, offer->contents().size());
3341 ASSERT_FALSE(offer->contents()[0].rejected);
3342 ASSERT_FALSE(offer->contents()[1].rejected);
3343
3344 // The answerer rejects one of the audio sections.
3345 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003346 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3347 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3348 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3349 RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003350 std::unique_ptr<SessionDescription> answer =
3351 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003352 ASSERT_EQ(2u, answer->contents().size());
3353 EXPECT_FALSE(answer->contents()[0].rejected);
3354 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003355
3356 // The TransportInfo of the rejected m= section is expected to be added in the
3357 // answer.
3358 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003359}
3360
3361// Test the generated media sections has the same order of the
3362// corresponding MediaDescriptionOptions.
3363TEST_F(MediaSessionDescriptionFactoryTest,
3364 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3365 MediaSessionOptions opts;
3366 // This tests put video section first because normally audio comes first by
3367 // default.
Steve Anton4e70a722017-11-28 14:57:10 -08003368 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3369 kActive, &opts);
3370 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3371 kActive, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003372 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003373
3374 ASSERT_TRUE(offer);
3375 ASSERT_EQ(2u, offer->contents().size());
3376 EXPECT_EQ("video", offer->contents()[0].name);
3377 EXPECT_EQ("audio", offer->contents()[1].name);
3378}
3379
3380// Test that different media sections using the same codec have same payload
3381// type.
3382TEST_F(MediaSessionDescriptionFactoryTest,
3383 PayloadTypesSharedByMediaSectionsOfSameType) {
3384 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003385 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3386 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3387 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3388 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003389 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003390 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003391 ASSERT_TRUE(offer);
3392 ASSERT_EQ(2u, offer->contents().size());
3393 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003394 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003395 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003396 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003397 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3398 ASSERT_EQ(2u, vcd1->codecs().size());
3399 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3400 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3401 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3402 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3403
3404 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003405 std::unique_ptr<SessionDescription> answer =
3406 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003407 ASSERT_TRUE(answer);
3408 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003409 vcd1 = answer->contents()[0].media_description()->as_video();
3410 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003411 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3412 ASSERT_EQ(1u, vcd1->codecs().size());
3413 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3414 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3415}
3416
3417// Test that the codec preference order per media section is respected in
3418// subsequent offer.
3419TEST_F(MediaSessionDescriptionFactoryTest,
3420 CreateOfferRespectsCodecPreferenceOrder) {
3421 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003422 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3423 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3424 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3425 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003426 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003427 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003428 ASSERT_TRUE(offer);
3429 ASSERT_EQ(2u, offer->contents().size());
3430 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003431 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003432 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003433 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003434 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3435 EXPECT_EQ(video_codecs, vcd1->codecs());
3436 EXPECT_EQ(video_codecs, vcd2->codecs());
3437
3438 // Change the codec preference of the first video section and create a
3439 // follow-up offer.
3440 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3441 vcd1->set_codecs(video_codecs_reverse);
3442 std::unique_ptr<SessionDescription> updated_offer(
3443 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003444 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3445 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003446 // The video codec preference order should be respected.
3447 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3448 EXPECT_EQ(video_codecs, vcd2->codecs());
3449}
3450
3451// Test that the codec preference order per media section is respected in
3452// the answer.
3453TEST_F(MediaSessionDescriptionFactoryTest,
3454 CreateAnswerRespectsCodecPreferenceOrder) {
3455 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003456 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3457 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3458 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3459 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003460 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003461 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003462 ASSERT_TRUE(offer);
3463 ASSERT_EQ(2u, offer->contents().size());
3464 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003465 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003466 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003467 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003468 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3469 EXPECT_EQ(video_codecs, vcd1->codecs());
3470 EXPECT_EQ(video_codecs, vcd2->codecs());
3471
3472 // Change the codec preference of the first video section and create an
3473 // answer.
3474 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3475 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003476 std::unique_ptr<SessionDescription> answer =
3477 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003478 vcd1 = answer->contents()[0].media_description()->as_video();
3479 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003480 // The video codec preference order should be respected.
3481 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3482 EXPECT_EQ(video_codecs, vcd2->codecs());
3483}
3484
Zhi Huang6f367472017-11-22 13:20:02 -08003485// Test that when creating an answer, the codecs use local parameters instead of
3486// the remote ones.
3487TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3488 const std::string audio_param_name = "audio_param";
3489 const std::string audio_value1 = "audio_v1";
3490 const std::string audio_value2 = "audio_v2";
3491 const std::string video_param_name = "video_param";
3492 const std::string video_value1 = "video_v1";
3493 const std::string video_value2 = "video_v2";
3494
3495 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3496 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3497 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3498 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3499
3500 // Set the parameters for codecs.
3501 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3502 video_codecs1[0].SetParam(video_param_name, video_value1);
3503 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3504 video_codecs2[0].SetParam(video_param_name, video_value2);
3505
3506 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3507 f1_.set_video_codecs(video_codecs1);
3508 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3509 f2_.set_video_codecs(video_codecs2);
3510
3511 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003512 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3513 kActive, &opts);
3514 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3515 kActive, &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003516
Steve Anton6fe1fba2018-12-11 10:15:23 -08003517 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003518 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003519 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3520 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003521 std::string value;
3522 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3523 EXPECT_EQ(audio_value1, value);
3524 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3525 EXPECT_EQ(video_value1, value);
3526
Steve Anton6fe1fba2018-12-11 10:15:23 -08003527 std::unique_ptr<SessionDescription> answer =
3528 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003529 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003530 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3531 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003532 // Use the parameters from the local codecs.
3533 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3534 EXPECT_EQ(audio_value2, value);
3535 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3536 EXPECT_EQ(video_value2, value);
3537}
3538
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003539// Test that matching packetization-mode is part of the criteria for matching
3540// H264 codecs (in addition to profile-level-id). Previously, this was not the
3541// case, so the first H264 codec with the same profile-level-id would match and
3542// the payload type in the answer would be incorrect.
3543// This is a regression test for bugs.webrtc.org/8808
3544TEST_F(MediaSessionDescriptionFactoryTest,
3545 H264MatchCriteriaIncludesPacketizationMode) {
3546 // Create two H264 codecs with the same profile level ID and different
3547 // packetization modes.
3548 VideoCodec h264_pm0(96, "H264");
3549 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3550 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3551 VideoCodec h264_pm1(97, "H264");
3552 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3553 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3554
3555 // Offerer will send both codecs, answerer should choose the one with matching
3556 // packetization mode (and not the first one it sees).
3557 f1_.set_video_codecs({h264_pm0, h264_pm1});
3558 f2_.set_video_codecs({h264_pm1});
3559
3560 MediaSessionOptions opts;
3561 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3562 kActive, &opts);
3563
Steve Anton6fe1fba2018-12-11 10:15:23 -08003564 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003565 ASSERT_TRUE(offer);
3566
Steve Anton6fe1fba2018-12-11 10:15:23 -08003567 std::unique_ptr<SessionDescription> answer =
3568 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003569 ASSERT_TRUE(answer);
3570
3571 // Answer should have one negotiated codec with packetization-mode=1 using the
3572 // offered payload type.
3573 ASSERT_EQ(1u, answer->contents().size());
3574 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3575 ASSERT_EQ(1u, answer_vcd->codecs().size());
3576 auto answer_codec = answer_vcd->codecs()[0];
3577 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3578}
3579
zhihuangcf5b37c2016-05-05 11:44:35 -07003580class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3581 public:
3582 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003583 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3584 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003585 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3586 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003587 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3588 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003589 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3590 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3591 f1_.set_secure(SEC_ENABLED);
3592 f2_.set_secure(SEC_ENABLED);
3593 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003594 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003595 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003596 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003597 tdf1_.set_secure(SEC_ENABLED);
3598 tdf2_.set_secure(SEC_ENABLED);
3599 }
3600
3601 protected:
3602 MediaSessionDescriptionFactory f1_;
3603 MediaSessionDescriptionFactory f2_;
3604 TransportDescriptionFactory tdf1_;
3605 TransportDescriptionFactory tdf2_;
3606};
3607
3608TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3609 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003610 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003611 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07003612 ASSERT_TRUE(offer.get() != nullptr);
3613 // Set the protocol for all the contents.
3614 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003615 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07003616 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08003617 std::unique_ptr<SessionDescription> answer =
3618 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07003619 const ContentInfo* ac = answer->GetContentByName("audio");
3620 const ContentInfo* vc = answer->GetContentByName("video");
3621 ASSERT_TRUE(ac != nullptr);
3622 ASSERT_TRUE(vc != nullptr);
3623 EXPECT_FALSE(ac->rejected); // the offer is accepted
3624 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003625 const AudioContentDescription* acd = ac->media_description()->as_audio();
3626 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07003627 EXPECT_EQ(GetParam(), acd->protocol());
3628 EXPECT_EQ(GetParam(), vcd->protocol());
3629}
3630
3631INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3632 MediaProtocolTest,
3633 ::testing::ValuesIn(kMediaProtocols));
3634INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3635 MediaProtocolTest,
3636 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003637
3638TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3639 TransportDescriptionFactory tdf;
3640 MediaSessionDescriptionFactory sf(&tdf);
3641 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3642 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3643
3644 // The merged list of codecs should contain any send codecs that are also
3645 // nominally in the recieve codecs list. Payload types should be picked from
3646 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3647 // (set to 1). This equals what happens when the send codecs are used in an
3648 // offer and the receive codecs are used in the following answer.
3649 const std::vector<AudioCodec> sendrecv_codecs =
3650 MAKE_VECTOR(kAudioCodecsAnswer);
3651 const std::vector<AudioCodec> no_codecs;
3652
3653 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3654 << "Please don't change shared test data!";
3655 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3656 << "Please don't change shared test data!";
3657 // Alter iLBC send codec to have zero channels, to test that that is handled
3658 // properly.
3659 send_codecs[1].channels = 0;
3660
3661 // Alther iLBC receive codec to be lowercase, to test that case conversions
3662 // are handled properly.
3663 recv_codecs[2].name = "ilbc";
3664
3665 // Test proper merge
3666 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003667 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3668 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3669 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003670
3671 // Test empty send codecs list
3672 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003673 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3674 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3675 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003676
3677 // Test empty recv codecs list
3678 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003679 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3680 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3681 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003682
3683 // Test all empty codec lists
3684 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003685 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3686 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3687 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003688}
3689
Amit Hilbuch77938e62018-12-21 09:23:38 -08003690// Checks that the RID extensions are added to the video RTP header extensions.
3691// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
3692// not very well defined, as calling set() and immediately get() will yield
3693// an object that is not semantically equivalent to the set object.
3694TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
3695 TransportDescriptionFactory tdf;
3696 MediaSessionDescriptionFactory sf(&tdf);
3697 sf.set_is_unified_plan(true);
3698 cricket::RtpHeaderExtensions extensions;
3699 sf.set_video_rtp_header_extensions(extensions);
3700 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
3701 // Check to see that RID extensions were added to the extension list
3702 EXPECT_GE(result.size(), 2u);
3703 auto rid_extension = std::find_if(
3704 result.begin(), result.end(), [](const RtpExtension& extension) {
3705 return extension.uri == webrtc::RtpExtension::kRidUri;
3706 });
3707 EXPECT_NE(rid_extension, extensions.end());
3708 auto repaired_rid_extension = std::find_if(
3709 result.begin(), result.end(), [](const RtpExtension& extension) {
3710 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
3711 });
3712 EXPECT_NE(repaired_rid_extension, extensions.end());
3713}
3714
3715// Checks that the RID extensions are added to the audio RTP header extensions.
3716// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
3717// not very well defined, as calling set() and immediately get() will yield
3718// an object that is not semantically equivalent to the set object.
3719TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
3720 TransportDescriptionFactory tdf;
3721 MediaSessionDescriptionFactory sf(&tdf);
3722 sf.set_is_unified_plan(true);
3723 cricket::RtpHeaderExtensions extensions;
3724 sf.set_audio_rtp_header_extensions(extensions);
3725 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
3726 // Check to see that RID extensions were added to the extension list
3727 EXPECT_GE(result.size(), 2u);
3728 auto rid_extension = std::find_if(
3729 result.begin(), result.end(), [](const RtpExtension& extension) {
3730 return extension.uri == webrtc::RtpExtension::kRidUri;
3731 });
3732 EXPECT_NE(rid_extension, extensions.end());
3733 auto repaired_rid_extension = std::find_if(
3734 result.begin(), result.end(), [](const RtpExtension& extension) {
3735 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
3736 });
3737 EXPECT_NE(repaired_rid_extension, extensions.end());
3738}
3739
ossu075af922016-06-14 03:29:38 -07003740namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003741// Compare the two vectors of codecs ignoring the payload type.
3742template <class Codec>
3743bool CodecsMatch(const std::vector<Codec>& codecs1,
3744 const std::vector<Codec>& codecs2) {
3745 if (codecs1.size() != codecs2.size()) {
3746 return false;
3747 }
3748
3749 for (size_t i = 0; i < codecs1.size(); ++i) {
3750 if (!codecs1[i].Matches(codecs2[i])) {
3751 return false;
3752 }
3753 }
3754 return true;
3755}
3756
Steve Anton4e70a722017-11-28 14:57:10 -08003757void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07003758 TransportDescriptionFactory tdf;
3759 MediaSessionDescriptionFactory sf(&tdf);
3760 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3761 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3762 const std::vector<AudioCodec> sendrecv_codecs =
3763 MAKE_VECTOR(kAudioCodecsAnswer);
3764 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003765
3766 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003767 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3768
Steve Anton4e70a722017-11-28 14:57:10 -08003769 if (direction == RtpTransceiverDirection::kSendRecv ||
3770 direction == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003771 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003772 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003773 }
ossu075af922016-06-14 03:29:38 -07003774
Steve Anton6fe1fba2018-12-11 10:15:23 -08003775 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07003776 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003777 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07003778
3779 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003780 // that the codecs put in are right. This happens when we neither want to
3781 // send nor receive audio. The checks are still in place if at some point
3782 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003783 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003784 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003785 // sendrecv and inactive should both present lists as if the channel was
3786 // to be used for sending and receiving. Inactive essentially means it
3787 // might eventually be used anything, but we don't know more at this
3788 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08003789 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003790 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08003791 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003792 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003793 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003794 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003795 }
3796 }
3797}
3798
3799static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003800 AudioCodec(0, "codec0", 16000, -1, 1),
3801 AudioCodec(1, "codec1", 8000, 13300, 1),
3802 AudioCodec(2, "codec2", 8000, 64000, 1),
3803 AudioCodec(3, "codec3", 8000, 64000, 1),
3804 AudioCodec(4, "codec4", 8000, 0, 2),
3805 AudioCodec(5, "codec5", 32000, 0, 1),
3806 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003807
zhihuang1c378ed2017-08-17 14:10:50 -07003808/* The codecs groups below are chosen as per the matrix below. The objective
3809 * is to have different sets of codecs in the inputs, to get unique sets of
3810 * codecs after negotiation, depending on offer and answer communication
3811 * directions. One-way directions in the offer should either result in the
3812 * opposite direction in the answer, or an inactive answer. Regardless, the
3813 * choice of codecs should be as if the answer contained the opposite
3814 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003815 *
3816 * | Offer | Answer | Result
3817 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3818 * 0 | x - - | - x - | x - - - -
3819 * 1 | x x x | - x - | x - - x -
3820 * 2 | - x - | x - - | - x - - -
3821 * 3 | x x x | x - - | - x x - -
3822 * 4 | - x - | x x x | - x - - -
3823 * 5 | x - - | x x x | x - - - -
3824 * 6 | x x x | x x x | x x x x x
3825 */
3826// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003827static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3828static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003829// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3830// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003831static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3832static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003833// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003834static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3835static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3836static const int kResultSendrecv_SendCodecs[] = {3, 6};
3837static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3838static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003839
3840template <typename T, int IDXS>
3841std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3842 std::vector<T> out;
3843 out.reserve(IDXS);
3844 for (int idx : indices)
3845 out.push_back(array[idx]);
3846
3847 return out;
3848}
3849
Steve Anton4e70a722017-11-28 14:57:10 -08003850void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
3851 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07003852 bool add_legacy_stream) {
3853 TransportDescriptionFactory offer_tdf;
3854 TransportDescriptionFactory answer_tdf;
3855 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3856 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3857 offer_factory.set_audio_codecs(
3858 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3859 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3860 answer_factory.set_audio_codecs(
3861 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3862 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3863
ossu075af922016-06-14 03:29:38 -07003864 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003865 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3866 &offer_opts);
3867
Steve Anton4e70a722017-11-28 14:57:10 -08003868 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003869 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003870 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003871 }
3872
Steve Anton6fe1fba2018-12-11 10:15:23 -08003873 std::unique_ptr<SessionDescription> offer =
3874 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07003875 ASSERT_TRUE(offer.get() != NULL);
3876
3877 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003878 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3879 &answer_opts);
3880
Steve Anton4e70a722017-11-28 14:57:10 -08003881 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003882 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003883 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003884 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08003885 std::unique_ptr<SessionDescription> answer =
3886 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07003887 const ContentInfo* ac = answer->GetContentByName("audio");
3888
zhihuang1c378ed2017-08-17 14:10:50 -07003889 // If the factory didn't add any audio content to the answer, we cannot
3890 // check that the codecs put in are right. This happens when we neither want
3891 // to send nor receive audio. The checks are still in place if at some point
3892 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003893 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003894 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
3895 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07003896
ossu075af922016-06-14 03:29:38 -07003897 std::vector<AudioCodec> target_codecs;
3898 // For offers with sendrecv or inactive, we should never reply with more
3899 // codecs than offered, with these codec sets.
3900 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08003901 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07003902 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3903 kResultSendrecv_SendrecvCodecs);
3904 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003905 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003906 target_codecs =
3907 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003908 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003909 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003910 target_codecs =
3911 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003912 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003913 case RtpTransceiverDirection::kSendRecv:
3914 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003915 target_codecs =
3916 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08003917 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003918 target_codecs =
3919 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003920 } else {
3921 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3922 kResultSendrecv_SendrecvCodecs);
3923 }
3924 break;
3925 }
3926
zhihuang1c378ed2017-08-17 14:10:50 -07003927 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02003928 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07003929 bool first = true;
3930 os << "{";
3931 for (const auto& c : codecs) {
3932 os << (first ? " " : ", ") << c.id;
3933 first = false;
3934 }
3935 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02003936 return os.Release();
ossu075af922016-06-14 03:29:38 -07003937 };
3938
3939 EXPECT_TRUE(acd->codecs() == target_codecs)
3940 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08003941 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
3942 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07003943 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08003944 << webrtc::RtpTransceiverDirectionToString(answer_direction)
3945 << "; got: "
3946 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07003947 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08003948 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07003949 << "Only inactive offers are allowed to not generate any audio "
3950 "content";
ossu075af922016-06-14 03:29:38 -07003951 }
3952}
brandtr03d5fb12016-11-22 03:37:59 -08003953
3954} // namespace
ossu075af922016-06-14 03:29:38 -07003955
3956class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08003957 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07003958
3959TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003960 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003961}
3962
3963INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3964 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003965 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3966 RtpTransceiverDirection::kRecvOnly,
3967 RtpTransceiverDirection::kSendRecv,
3968 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07003969
3970class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08003971 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
3972 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003973 bool>> {};
ossu075af922016-06-14 03:29:38 -07003974
3975TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003976 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3977 ::testing::get<1>(GetParam()),
3978 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003979}
3980
zhihuang1c378ed2017-08-17 14:10:50 -07003981INSTANTIATE_TEST_CASE_P(
3982 MediaSessionDescriptionFactoryTest,
3983 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003984 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
3985 RtpTransceiverDirection::kRecvOnly,
3986 RtpTransceiverDirection::kSendRecv,
3987 RtpTransceiverDirection::kInactive),
3988 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3989 RtpTransceiverDirection::kRecvOnly,
3990 RtpTransceiverDirection::kSendRecv,
3991 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07003992 ::testing::Bool()));