blob: 49a8aa8c341229cf79811e5cdff363651362f423 [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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/media_session.h"
12
Amit Hilbuch77938e62018-12-21 09:23:38 -080013#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080014#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <string>
Harald Alvestrand1716d392019-06-03 20:35:45 +020016#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <vector>
18
Steve Anton64b626b2019-01-28 17:25:26 -080019#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080020#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020023#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "p2p/base/p2p_constants.h"
25#include "p2p/base/transport_description.h"
26#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "pc/rtp_media_utils.h"
28#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "rtc_base/message_digest.h"
33#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020034#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080035#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080036#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
Yves Gerey665174f2018-06-19 15:03:05 +020038#define ASSERT_CRYPTO(cd, s, cs) \
39 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080040 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041
42typedef std::vector<cricket::Candidate> Candidates;
43
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080044using cricket::AudioCodec;
45using cricket::AudioContentDescription;
46using cricket::ContentInfo;
47using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080048using cricket::GetFirstAudioContent;
49using cricket::GetFirstAudioContentDescription;
50using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020051using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080052using cricket::GetFirstVideoContent;
53using cricket::GetFirstVideoContentDescription;
54using cricket::kAutoBandwidth;
55using cricket::MEDIA_TYPE_AUDIO;
56using cricket::MEDIA_TYPE_DATA;
57using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070059using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080060using cricket::MediaProtocolType;
61using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062using cricket::MediaSessionOptions;
63using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080064using cricket::RidDescription;
65using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020066using cricket::RtpDataCodec;
67using cricket::RtpDataContentDescription;
68using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080069using cricket::SEC_DISABLED;
70using cricket::SEC_ENABLED;
71using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080073using cricket::SimulcastDescription;
74using cricket::SimulcastLayer;
75using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076using cricket::SsrcGroup;
77using cricket::StreamParams;
78using cricket::StreamParamsVec;
79using cricket::TransportDescription;
80using cricket::TransportDescriptionFactory;
81using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080083using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070084using rtc::CS_AEAD_AES_128_GCM;
85using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080086using rtc::CS_AES_CM_128_HMAC_SHA1_32;
87using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080088using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020089using ::testing::Contains;
90using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +010091using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020092using ::testing::ElementsAreArray;
93using ::testing::Eq;
94using ::testing::Field;
95using ::testing::IsEmpty;
96using ::testing::IsFalse;
97using ::testing::Ne;
98using ::testing::Not;
99using ::testing::Pointwise;
100using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700101using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800102using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
104static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700105 AudioCodec(103, "ISAC", 16000, -1, 1),
106 AudioCodec(102, "iLBC", 8000, 13300, 1),
107 AudioCodec(0, "PCMU", 8000, 64000, 1),
108 AudioCodec(8, "PCMA", 8000, 64000, 1),
109 AudioCodec(117, "red", 8000, 0, 1),
110 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
112static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200113 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700114 AudioCodec(0, "PCMU", 8000, 64000, 1),
115 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116};
117
118static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700119 AudioCodec(102, "iLBC", 8000, 13300, 1),
120 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121};
122
perkj26752742016-10-24 01:21:16 -0700123static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
124 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125
zhihuang1c378ed2017-08-17 14:10:50 -0700126static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
127 VideoCodec(96, "H264-SVC")};
128
perkj26752742016-10-24 01:21:16 -0700129static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
130 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
perkj26752742016-10-24 01:21:16 -0700132static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200134static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
135 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200137static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
138 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200140static const RtpDataCodec kDataCodecsAnswer[] = {
141 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142
isheriff6f8d6862016-05-26 11:24:55 -0700143static const RtpExtension kAudioRtpExtension1[] = {
144 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
145 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146};
147
jbauch5869f502017-06-29 12:31:36 -0700148static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
149 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
150 RtpExtension("http://google.com/testing/audio_something", 10),
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
152};
153
isheriff6f8d6862016-05-26 11:24:55 -0700154static const RtpExtension kAudioRtpExtension2[] = {
155 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
156 RtpExtension("http://google.com/testing/audio_something_else", 8),
157 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000158};
159
isheriff6f8d6862016-05-26 11:24:55 -0700160static const RtpExtension kAudioRtpExtension3[] = {
161 RtpExtension("http://google.com/testing/audio_something", 2),
162 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700163};
164
jbauch5869f502017-06-29 12:31:36 -0700165static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
166 RtpExtension("http://google.com/testing/audio_something", 2),
167 // Use RTP extension that supports encryption.
168 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
169};
170
171static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
172 RtpExtension("http://google.com/testing/audio_something", 2),
173 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
175};
176
isheriff6f8d6862016-05-26 11:24:55 -0700177static const RtpExtension kAudioRtpExtensionAnswer[] = {
178 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179};
180
jbauch5869f502017-06-29 12:31:36 -0700181static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
182 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
183};
184
isheriff6f8d6862016-05-26 11:24:55 -0700185static const RtpExtension kVideoRtpExtension1[] = {
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
187 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188};
189
jbauch5869f502017-06-29 12:31:36 -0700190static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
192 RtpExtension("http://google.com/testing/video_something", 13),
193 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
194};
195
isheriff6f8d6862016-05-26 11:24:55 -0700196static const RtpExtension kVideoRtpExtension2[] = {
197 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
198 RtpExtension("http://google.com/testing/video_something_else", 14),
199 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200};
201
isheriff6f8d6862016-05-26 11:24:55 -0700202static const RtpExtension kVideoRtpExtension3[] = {
203 RtpExtension("http://google.com/testing/video_something", 4),
204 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700205};
206
jbauch5869f502017-06-29 12:31:36 -0700207static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
208 RtpExtension("http://google.com/testing/video_something", 4),
209 // Use RTP extension that supports encryption.
210 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
211};
212
isheriff6f8d6862016-05-26 11:24:55 -0700213static const RtpExtension kVideoRtpExtensionAnswer[] = {
214 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215};
216
jbauch5869f502017-06-29 12:31:36 -0700217static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
218 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
219};
220
Johannes Kronce8e8672019-02-22 13:06:44 +0100221static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
222 RtpExtension("http://www.ietf.org/id/"
223 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
224 1),
225};
226
227static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
228 RtpExtension("http://www.ietf.org/id/"
229 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
230 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100231 RtpExtension(
232 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
233 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100234};
235
236static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100237 RtpExtension(
238 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
239 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100240};
241
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100242static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
243 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
244 "generic-frame-descriptor-00",
245 3),
246};
247
Peter Boström0c4e06b2015-10-07 12:23:21 +0200248static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
249static const uint32_t kSimSsrc[] = {10, 20, 30};
250static const uint32_t kFec1Ssrc[] = {10, 11};
251static const uint32_t kFec2Ssrc[] = {20, 21};
252static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253
254static const char kMediaStream1[] = "stream_1";
255static const char kMediaStream2[] = "stream_2";
256static const char kVideoTrack1[] = "video_1";
257static const char kVideoTrack2[] = "video_2";
258static const char kAudioTrack1[] = "audio_1";
259static const char kAudioTrack2[] = "audio_2";
260static const char kAudioTrack3[] = "audio_3";
261static const char kDataTrack1[] = "data_1";
262static const char kDataTrack2[] = "data_2";
263static const char kDataTrack3[] = "data_3";
264
zhihuangcf5b37c2016-05-05 11:44:35 -0700265static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
266 "RTP/SAVPF"};
267static const char* kMediaProtocolsDtls[] = {
268 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
269 "UDP/TLS/RTP/SAVP"};
270
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700271// SRTP cipher name negotiated by the tests. This must be updated if the
272// default changes.
273static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
274static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
275
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800276// These constants are used to make the code using "AddMediaDescriptionOptions"
277// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700278static constexpr bool kStopped = true;
279static constexpr bool kActive = false;
280
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000281static bool IsMediaContentOfType(const ContentInfo* content,
282 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800283 RTC_DCHECK(content);
284 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000285}
286
Steve Anton4e70a722017-11-28 14:57:10 -0800287static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800288 RTC_DCHECK(content);
289 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000290}
291
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000292static void AddRtxCodec(const VideoCodec& rtx_codec,
293 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800294 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000295 codecs->push_back(rtx_codec);
296}
297
298template <class T>
299static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
300 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100301 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000302 for (const auto& codec : codecs) {
303 codec_names.push_back(codec.name);
304 }
305 return codec_names;
306}
307
zhihuang1c378ed2017-08-17 14:10:50 -0700308// This is used for test only. MIDs are not the identification of the
309// MediaDescriptionOptions since some end points may not support MID and the SDP
310// may not contain 'mid'.
311std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
312 const std::string& mid,
313 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800314 return absl::c_find_if(
315 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700316 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
317}
318
319std::vector<MediaDescriptionOptions>::const_iterator
320FindFirstMediaDescriptionByMid(const std::string& mid,
321 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800322 return absl::c_find_if(
323 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700324 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700325}
326
327// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800328static void AddMediaDescriptionOptions(MediaType type,
329 const std::string& mid,
330 RtpTransceiverDirection direction,
331 bool stopped,
332 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800333 opts->media_description_options.push_back(
334 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700335}
336
Steve Anton4e70a722017-11-28 14:57:10 -0800337static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700338 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800339 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
340 opts);
341 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
342 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700343}
344
345static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800346 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700347 MediaSessionOptions* opts) {
348 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800349 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700350}
351
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800352static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700353 const std::string& mid,
354 MediaType type,
355 const std::string& track_id,
356 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800357 const std::vector<RidDescription>& rids,
358 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700359 int num_sim_layer,
360 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700361 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
362 switch (type) {
363 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700364 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700365 break;
366 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800367 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
368 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700369 break;
370 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700371 RTC_CHECK(stream_ids.size() == 1U);
372 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700373 break;
374 default:
375 RTC_NOTREACHED();
376 }
377}
378
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800379static void AttachSenderToMediaDescriptionOptions(
380 const std::string& mid,
381 MediaType type,
382 const std::string& track_id,
383 const std::vector<std::string>& stream_ids,
384 int num_sim_layer,
385 MediaSessionOptions* session_options) {
386 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
387 SimulcastLayerList(), num_sim_layer,
388 session_options);
389}
390
zhihuang1c378ed2017-08-17 14:10:50 -0700391static void DetachSenderFromMediaSection(const std::string& mid,
392 const std::string& track_id,
393 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700394 std::vector<cricket::SenderOptions>& sender_options_list =
395 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
396 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800397 absl::c_find_if(sender_options_list,
398 [track_id](const cricket::SenderOptions& sender_options) {
399 return sender_options.track_id == track_id;
400 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700401 RTC_DCHECK(sender_it != sender_options_list.end());
402 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700403}
404
405// Helper function used to create a default MediaSessionOptions for Plan B SDP.
406// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
407static MediaSessionOptions CreatePlanBMediaSessionOptions() {
408 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800409 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
410 RtpTransceiverDirection::kRecvOnly, kActive,
411 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700412 return session_options;
413}
414
415// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
416// was designed for Plan B SDP, where only one audio "m=" section and one video
417// "m=" section could be generated, and ordering couldn't be controlled. Many of
418// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200419class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800421 MediaSessionDescriptionFactoryTest()
422 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700423 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
424 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000425 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200426 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700427 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
428 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000429 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200430 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200431 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700432 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200433 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700434 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 }
436
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000437 // Create a video StreamParamsVec object with:
438 // - one video stream with 3 simulcast streams and FEC,
439 StreamParamsVec CreateComplexVideoStreamParamsVec() {
440 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
441 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
442 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
443 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
444
445 std::vector<SsrcGroup> ssrc_groups;
446 ssrc_groups.push_back(sim_group);
447 ssrc_groups.push_back(fec_group1);
448 ssrc_groups.push_back(fec_group2);
449 ssrc_groups.push_back(fec_group3);
450
451 StreamParams simulcast_params;
452 simulcast_params.id = kVideoTrack1;
453 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
454 simulcast_params.ssrc_groups = ssrc_groups;
455 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800456 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000457
458 StreamParamsVec video_streams;
459 video_streams.push_back(simulcast_params);
460
461 return video_streams;
462 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463
464 bool CompareCryptoParams(const CryptoParamsVec& c1,
465 const CryptoParamsVec& c2) {
466 if (c1.size() != c2.size())
467 return false;
468 for (size_t i = 0; i < c1.size(); ++i)
469 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
470 c1[i].key_params != c2[i].key_params ||
471 c1[i].session_params != c2[i].session_params)
472 return false;
473 return true;
474 }
475
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700476 // Returns true if the transport info contains "renomination" as an
477 // ICE option.
478 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800479 return absl::c_linear_search(transport_info->description.transport_options,
480 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700481 }
482
zhihuang1c378ed2017-08-17 14:10:50 -0700483 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700484 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485 bool has_current_desc) {
486 const std::string current_audio_ufrag = "current_audio_ufrag";
487 const std::string current_audio_pwd = "current_audio_pwd";
488 const std::string current_video_ufrag = "current_video_ufrag";
489 const std::string current_video_pwd = "current_video_pwd";
490 const std::string current_data_ufrag = "current_data_ufrag";
491 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800492 std::unique_ptr<SessionDescription> current_desc;
493 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000494 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200495 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800496 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200497 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800498 TransportDescription(current_audio_ufrag, current_audio_pwd)));
499 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200500 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800501 TransportDescription(current_video_ufrag, current_video_pwd)));
502 current_desc->AddTransportInfo(TransportInfo(
503 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 }
505 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800506 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 } else {
kwiberg31022942016-03-11 14:18:21 -0800508 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800509 offer = f1_.CreateOffer(options, NULL);
510 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511 }
512 ASSERT_TRUE(desc.get() != NULL);
513 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000514 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 EXPECT_TRUE(ti_audio != NULL);
516 if (has_current_desc) {
517 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
518 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
519 } else {
520 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
521 ti_audio->description.ice_ufrag.size());
522 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
523 ti_audio->description.ice_pwd.size());
524 }
zhihuang1c378ed2017-08-17 14:10:50 -0700525 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700526 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700527 EXPECT_EQ(
528 media_desc_options_it->transport_options.enable_ice_renomination,
529 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700530 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
531 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532
533 } else {
534 EXPECT_TRUE(ti_audio == NULL);
535 }
536 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000537 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700539 auto media_desc_options_it =
540 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 if (options.bundle_enabled) {
542 EXPECT_EQ(ti_audio->description.ice_ufrag,
543 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200544 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700545 EXPECT_EQ(ti_audio->description.opaque_parameters,
546 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 } else {
548 if (has_current_desc) {
549 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
550 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
551 } else {
552 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
553 ti_video->description.ice_ufrag.size());
554 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
555 ti_video->description.ice_pwd.size());
556 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700557 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
558 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 }
zhihuang1c378ed2017-08-17 14:10:50 -0700560 EXPECT_EQ(
561 media_desc_options_it->transport_options.enable_ice_renomination,
562 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 } else {
564 EXPECT_TRUE(ti_video == NULL);
565 }
566 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
567 if (options.has_data()) {
568 EXPECT_TRUE(ti_data != NULL);
569 if (options.bundle_enabled) {
570 EXPECT_EQ(ti_audio->description.ice_ufrag,
571 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200572 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 } else {
574 if (has_current_desc) {
575 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
576 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
577 } else {
578 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
579 ti_data->description.ice_ufrag.size());
580 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
581 ti_data->description.ice_pwd.size());
582 }
583 }
zhihuang1c378ed2017-08-17 14:10:50 -0700584 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700585 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700586 EXPECT_EQ(
587 media_desc_options_it->transport_options.enable_ice_renomination,
588 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700589
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700591 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 }
593 }
594
595 void TestCryptoWithBundle(bool offer) {
596 f1_.set_secure(SEC_ENABLED);
597 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800598 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
599 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
600 &options);
kwiberg31022942016-03-11 14:18:21 -0800601 std::unique_ptr<SessionDescription> ref_desc;
602 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 if (offer) {
604 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800605 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800607 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 } else {
609 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800610 ref_desc = f1_.CreateOffer(options, NULL);
611 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800613 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800615 desc->GetContentDescriptionByName("audio");
616 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800618 desc->GetContentDescriptionByName("video");
619 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
621 video_media_desc->cryptos()));
622 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800623 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 audio_media_desc->cryptos()[0].cipher_suite);
625
626 // Verify the selected crypto is one from the reference audio
627 // media content.
628 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800629 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 bool found = false;
631 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
632 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200633 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 found = true;
635 break;
636 }
637 }
638 EXPECT_TRUE(found);
639 }
640
641 // This test that the audio and video media direction is set to
642 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700643 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800645 RtpTransceiverDirection direction_in_offer,
646 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700647 MediaSessionOptions offer_opts;
648 AddAudioVideoSections(direction_in_offer, &offer_opts);
649
Steve Anton6fe1fba2018-12-11 10:15:23 -0800650 std::unique_ptr<SessionDescription> offer =
651 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700653 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700655 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657
zhihuang1c378ed2017-08-17 14:10:50 -0700658 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800659 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800660 std::unique_ptr<SessionDescription> answer =
661 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 const AudioContentDescription* acd_answer =
663 GetFirstAudioContentDescription(answer.get());
664 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
665 const VideoContentDescription* vcd_answer =
666 GetFirstVideoContentDescription(answer.get());
667 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
668 }
669
670 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800671 RTC_DCHECK(content);
672 RTC_CHECK(content->media_description());
673 const cricket::AudioContentDescription* audio_desc =
674 content->media_description()->as_audio();
675 RTC_CHECK(audio_desc);
676 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
677 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800679 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 }
681 return true;
682 }
683
jbauchcb560652016-08-04 05:20:32 -0700684 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
685 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800686 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700687 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700688
jbauchcb560652016-08-04 05:20:32 -0700689 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800690 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700691 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700692
jbauchcb560652016-08-04 05:20:32 -0700693 f1_.set_secure(SEC_ENABLED);
694 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800695 std::unique_ptr<SessionDescription> offer =
696 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700697 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800698 std::unique_ptr<SessionDescription> answer =
699 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700700 const ContentInfo* ac = answer->GetContentByName("audio");
701 const ContentInfo* vc = answer->GetContentByName("video");
702 ASSERT_TRUE(ac != NULL);
703 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800704 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
705 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800706 const AudioContentDescription* acd = ac->media_description()->as_audio();
707 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700708 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800709 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700710 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700711 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700712 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
713 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700714 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700715 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700716 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700717 }
718 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800719 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200720 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
721 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700722 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700723 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700724 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700725 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700726 }
Steve Antone38a5a12018-11-21 16:05:15 -0800727 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700728 }
729
Johannes Kronce8e8672019-02-22 13:06:44 +0100730 void TestTransportSequenceNumberNegotiation(
731 const cricket::RtpHeaderExtensions& local,
732 const cricket::RtpHeaderExtensions& offered,
733 const cricket::RtpHeaderExtensions& expectedAnswer) {
734 MediaSessionOptions opts;
735 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
736 f1_.set_audio_rtp_header_extensions(offered);
737 f1_.set_video_rtp_header_extensions(offered);
738 f2_.set_audio_rtp_header_extensions(local);
739 f2_.set_video_rtp_header_extensions(local);
740
741 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
742 ASSERT_TRUE(offer.get() != NULL);
743 std::unique_ptr<SessionDescription> answer =
744 f2_.CreateAnswer(offer.get(), opts, NULL);
745
746 EXPECT_EQ(
747 expectedAnswer,
748 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
749 EXPECT_EQ(
750 expectedAnswer,
751 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
752 }
753
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800755 UniqueRandomIdGenerator ssrc_generator1;
756 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757 MediaSessionDescriptionFactory f1_;
758 MediaSessionDescriptionFactory f2_;
759 TransportDescriptionFactory tdf1_;
760 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761};
762
763// Create a typical audio offer, and ensure it matches what we expect.
764TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
765 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800766 std::unique_ptr<SessionDescription> offer =
767 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 ASSERT_TRUE(offer.get() != NULL);
769 const ContentInfo* ac = offer->GetContentByName("audio");
770 const ContentInfo* vc = offer->GetContentByName("video");
771 ASSERT_TRUE(ac != NULL);
772 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800773 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800774 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700776 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700777 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
779 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700780 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800781 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782}
783
784// Create a typical video offer, and ensure it matches what we expect.
785TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
786 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800787 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000788 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800789 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790 ASSERT_TRUE(offer.get() != NULL);
791 const ContentInfo* ac = offer->GetContentByName("audio");
792 const ContentInfo* vc = offer->GetContentByName("video");
793 ASSERT_TRUE(ac != NULL);
794 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800795 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
796 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800797 const AudioContentDescription* acd = ac->media_description()->as_audio();
798 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700800 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700801 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
803 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700804 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800805 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000807 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700808 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
810 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700811 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800812 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813}
814
815// Test creating an offer with bundle where the Codecs have the same dynamic
816// RTP playlod type. The test verifies that the offer don't contain the
817// duplicate RTP payload types.
818TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000819 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700820 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200821 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
823 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
824
825 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800826 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
827 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800829 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830 const VideoContentDescription* vcd =
831 GetFirstVideoContentDescription(offer.get());
832 const AudioContentDescription* acd =
833 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200834 const RtpDataContentDescription* dcd =
835 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836 ASSERT_TRUE(NULL != vcd);
837 ASSERT_TRUE(NULL != acd);
838 ASSERT_TRUE(NULL != dcd);
839 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
840 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
841 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
842 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
843 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
844 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
845}
846
zhihuang1c378ed2017-08-17 14:10:50 -0700847// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848// after an audio only session has been negotiated.
849TEST_F(MediaSessionDescriptionFactoryTest,
850 TestCreateUpdatedVideoOfferWithBundle) {
851 f1_.set_secure(SEC_ENABLED);
852 f2_.set_secure(SEC_ENABLED);
853 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800854 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
855 RtpTransceiverDirection::kRecvOnly, kActive,
856 &opts);
857 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
858 RtpTransceiverDirection::kInactive, kStopped,
859 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 opts.data_channel_type = cricket::DCT_NONE;
861 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800862 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
863 std::unique_ptr<SessionDescription> answer =
864 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865
866 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800867 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
868 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
869 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800871 std::unique_ptr<SessionDescription> updated_offer(
872 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873
874 const AudioContentDescription* acd =
875 GetFirstAudioContentDescription(updated_offer.get());
876 const VideoContentDescription* vcd =
877 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200878 const RtpDataContentDescription* dcd =
879 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 EXPECT_TRUE(NULL != vcd);
881 EXPECT_TRUE(NULL != acd);
882 EXPECT_TRUE(NULL != dcd);
883
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700884 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800885 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700886 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800887 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700888 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800889 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000890}
deadbeef44f08192015-12-15 16:20:09 -0800891
wu@webrtc.org78187522013-10-07 23:32:02 +0000892// Create a RTP data offer, and ensure it matches what we expect.
893TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800895 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
896 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800898 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 ASSERT_TRUE(offer.get() != NULL);
900 const ContentInfo* ac = offer->GetContentByName("audio");
901 const ContentInfo* dc = offer->GetContentByName("data");
902 ASSERT_TRUE(ac != NULL);
903 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800904 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
905 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800906 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200907 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700909 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700910 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
912 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700913 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800914 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200916 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700917 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200919 dcd->bandwidth()); // default bandwidth (auto)
920 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700921 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800922 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923}
924
wu@webrtc.org78187522013-10-07 23:32:02 +0000925// Create an SCTP data offer with bundle without error.
926TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
927 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000928 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800929 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000930 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800931 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000932 EXPECT_TRUE(offer.get() != NULL);
933 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000934 auto dcd = GetFirstSctpDataContentDescription(offer.get());
935 ASSERT_TRUE(dcd);
936 // Since this transport is insecure, the protocol should be "SCTP".
937 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
938}
939
940// Create an SCTP data offer with bundle without error.
941TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
942 MediaSessionOptions opts;
943 opts.bundle_enabled = true;
944 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
945 f1_.set_secure(SEC_ENABLED);
946 tdf1_.set_secure(SEC_ENABLED);
947 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
948 EXPECT_TRUE(offer.get() != NULL);
949 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
950 auto dcd = GetFirstSctpDataContentDescription(offer.get());
951 ASSERT_TRUE(dcd);
952 // The protocol should now be "UDP/DTLS/SCTP"
953 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000954}
955
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000956// Test creating an sctp data channel from an already generated offer.
957TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
958 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000959 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800960 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000961 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800962 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000963 ASSERT_TRUE(offer1.get() != NULL);
964 const ContentInfo* data = offer1->GetContentByName("data");
965 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800966 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000967
968 // Now set data_channel_type to 'none' (default) and make sure that the
969 // datachannel type that gets generated from the previous offer, is of the
970 // same type.
971 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800972 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000973 f1_.CreateOffer(opts, offer1.get()));
974 data = offer2->GetContentByName("data");
975 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800976 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000977}
978
Steve Anton2bed3972019-01-04 17:04:30 -0800979// Test that if BUNDLE is enabled and all media sections are rejected then the
980// BUNDLE group is not present in the re-offer.
981TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
982 MediaSessionOptions opts;
983 opts.bundle_enabled = true;
984 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
985 RtpTransceiverDirection::kSendRecv, kActive,
986 &opts);
987 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
988
989 opts.media_description_options[0].stopped = true;
990 std::unique_ptr<SessionDescription> reoffer =
991 f1_.CreateOffer(opts, offer.get());
992
993 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
994}
995
996// Test that if BUNDLE is enabled and the remote re-offer does not include a
997// BUNDLE group since all media sections are rejected, then the re-answer also
998// does not include a BUNDLE group.
999TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
1000 MediaSessionOptions opts;
1001 opts.bundle_enabled = true;
1002 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1003 RtpTransceiverDirection::kSendRecv, kActive,
1004 &opts);
1005 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1006 std::unique_ptr<SessionDescription> answer =
1007 f2_.CreateAnswer(offer.get(), opts, nullptr);
1008
1009 opts.media_description_options[0].stopped = true;
1010 std::unique_ptr<SessionDescription> reoffer =
1011 f1_.CreateOffer(opts, offer.get());
1012 std::unique_ptr<SessionDescription> reanswer =
1013 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1014
1015 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1016}
1017
1018// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1019// was rejected then the new offerer-tagged media section is the non-rejected
1020// media section.
1021TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1022 MediaSessionOptions opts;
1023 opts.bundle_enabled = true;
1024 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1025 RtpTransceiverDirection::kSendRecv, kActive,
1026 &opts);
1027 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1028
1029 // Reject the audio m= section and add a video m= section.
1030 opts.media_description_options[0].stopped = true;
1031 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1032 RtpTransceiverDirection::kSendRecv, kActive,
1033 &opts);
1034 std::unique_ptr<SessionDescription> reoffer =
1035 f1_.CreateOffer(opts, offer.get());
1036
1037 const cricket::ContentGroup* bundle_group =
1038 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1039 ASSERT_TRUE(bundle_group);
1040 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1041 EXPECT_TRUE(bundle_group->HasContentName("video"));
1042}
1043
1044// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1045// was rejected and a new media section is added, then the re-answer BUNDLE
1046// group will contain only the non-rejected media section.
1047TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1048 MediaSessionOptions opts;
1049 opts.bundle_enabled = true;
1050 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1051 RtpTransceiverDirection::kSendRecv, kActive,
1052 &opts);
1053 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1054 std::unique_ptr<SessionDescription> answer =
1055 f2_.CreateAnswer(offer.get(), opts, nullptr);
1056
1057 // Reject the audio m= section and add a video m= section.
1058 opts.media_description_options[0].stopped = true;
1059 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1060 RtpTransceiverDirection::kSendRecv, kActive,
1061 &opts);
1062 std::unique_ptr<SessionDescription> reoffer =
1063 f1_.CreateOffer(opts, offer.get());
1064 std::unique_ptr<SessionDescription> reanswer =
1065 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1066
1067 const cricket::ContentGroup* bundle_group =
1068 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1069 ASSERT_TRUE(bundle_group);
1070 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1071 EXPECT_TRUE(bundle_group->HasContentName("video"));
1072}
1073
1074// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1075// and there is still a non-rejected media section that was in the initial
1076// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1077// media section.
1078TEST_F(MediaSessionDescriptionFactoryTest,
1079 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1080 MediaSessionOptions opts;
1081 opts.bundle_enabled = true;
1082 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1083 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1084 std::unique_ptr<SessionDescription> answer =
1085 f2_.CreateAnswer(offer.get(), opts, nullptr);
1086
1087 // Reject the audio m= section.
1088 opts.media_description_options[0].stopped = true;
1089 std::unique_ptr<SessionDescription> reoffer =
1090 f1_.CreateOffer(opts, offer.get());
1091
1092 const TransportDescription* offer_tagged =
1093 offer->GetTransportDescriptionByName("audio");
1094 ASSERT_TRUE(offer_tagged);
1095 const TransportDescription* reoffer_tagged =
1096 reoffer->GetTransportDescriptionByName("video");
1097 ASSERT_TRUE(reoffer_tagged);
1098 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1099 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1100}
1101
1102// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1103// and there is still a non-rejected media section that was in the initial
1104// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1105// media section.
1106TEST_F(MediaSessionDescriptionFactoryTest,
1107 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1108 MediaSessionOptions opts;
1109 opts.bundle_enabled = true;
1110 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1111 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1112 std::unique_ptr<SessionDescription> answer =
1113 f2_.CreateAnswer(offer.get(), opts, nullptr);
1114
1115 // Reject the audio m= section.
1116 opts.media_description_options[0].stopped = true;
1117 std::unique_ptr<SessionDescription> reoffer =
1118 f1_.CreateOffer(opts, offer.get());
1119 std::unique_ptr<SessionDescription> reanswer =
1120 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1121
1122 const TransportDescription* answer_tagged =
1123 answer->GetTransportDescriptionByName("audio");
1124 ASSERT_TRUE(answer_tagged);
1125 const TransportDescription* reanswer_tagged =
1126 reanswer->GetTransportDescriptionByName("video");
1127 ASSERT_TRUE(reanswer_tagged);
1128 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1129 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1130}
1131
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132// Create an audio, video offer without legacy StreamParams.
1133TEST_F(MediaSessionDescriptionFactoryTest,
1134 TestCreateOfferWithoutLegacyStreams) {
1135 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001136 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001137 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138 ASSERT_TRUE(offer.get() != NULL);
1139 const ContentInfo* ac = offer->GetContentByName("audio");
1140 const ContentInfo* vc = offer->GetContentByName("video");
1141 ASSERT_TRUE(ac != NULL);
1142 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001143 const AudioContentDescription* acd = ac->media_description()->as_audio();
1144 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001145
Yves Gerey665174f2018-06-19 15:03:05 +02001146 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1147 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148}
1149
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001150// Creates an audio+video sendonly offer.
1151TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001152 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001153 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001154 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1155 {kMediaStream1}, 1, &opts);
1156 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1157 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001158
Steve Anton6fe1fba2018-12-11 10:15:23 -08001159 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001160 ASSERT_TRUE(offer.get() != NULL);
1161 EXPECT_EQ(2u, offer->contents().size());
1162 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1163 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1164
Steve Anton4e70a722017-11-28 14:57:10 -08001165 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1166 GetMediaDirection(&offer->contents()[0]));
1167 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1168 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001169}
1170
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001171// Verifies that the order of the media contents in the current
1172// SessionDescription is preserved in the new SessionDescription.
1173TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1174 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001175 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001176
kwiberg31022942016-03-11 14:18:21 -08001177 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001178 ASSERT_TRUE(offer1.get() != NULL);
1179 EXPECT_EQ(1u, offer1->contents().size());
1180 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1181
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001182 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1183 RtpTransceiverDirection::kRecvOnly, kActive,
1184 &opts);
kwiberg31022942016-03-11 14:18:21 -08001185 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001186 f1_.CreateOffer(opts, offer1.get()));
1187 ASSERT_TRUE(offer2.get() != NULL);
1188 EXPECT_EQ(2u, offer2->contents().size());
1189 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1190 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1191
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001192 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1193 RtpTransceiverDirection::kRecvOnly, kActive,
1194 &opts);
kwiberg31022942016-03-11 14:18:21 -08001195 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001196 f1_.CreateOffer(opts, offer2.get()));
1197 ASSERT_TRUE(offer3.get() != NULL);
1198 EXPECT_EQ(3u, offer3->contents().size());
1199 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1200 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1201 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001202}
1203
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001204// Create a typical audio answer, and ensure it matches what we expect.
1205TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1206 f1_.set_secure(SEC_ENABLED);
1207 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001208 std::unique_ptr<SessionDescription> offer =
1209 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001210 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001211 std::unique_ptr<SessionDescription> answer =
1212 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001213 const ContentInfo* ac = answer->GetContentByName("audio");
1214 const ContentInfo* vc = answer->GetContentByName("video");
1215 ASSERT_TRUE(ac != NULL);
1216 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001217 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001218 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001220 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001221 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1223 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001224 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001225 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226}
1227
jbauchcb560652016-08-04 05:20:32 -07001228// Create a typical audio answer with GCM ciphers enabled, and ensure it
1229// matches what we expect.
1230TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1231 f1_.set_secure(SEC_ENABLED);
1232 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001233 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001234 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001235 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001236 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001237 std::unique_ptr<SessionDescription> answer =
1238 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001239 const ContentInfo* ac = answer->GetContentByName("audio");
1240 const ContentInfo* vc = answer->GetContentByName("video");
1241 ASSERT_TRUE(ac != NULL);
1242 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001243 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001244 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001245 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001246 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001247 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001248 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1249 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001250 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001251 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001252}
1253
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254// Create a typical video answer, and ensure it matches what we expect.
1255TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1256 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001257 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 f1_.set_secure(SEC_ENABLED);
1259 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001260 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001262 std::unique_ptr<SessionDescription> answer =
1263 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 const ContentInfo* ac = answer->GetContentByName("audio");
1265 const ContentInfo* vc = answer->GetContentByName("video");
1266 ASSERT_TRUE(ac != NULL);
1267 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001268 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1269 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001270 const AudioContentDescription* acd = ac->media_description()->as_audio();
1271 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001273 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001275 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001277 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001279 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001280 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1281 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001282 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001283 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001284}
1285
jbauchcb560652016-08-04 05:20:32 -07001286// Create a typical video answer with GCM ciphers enabled, and ensure it
1287// matches what we expect.
1288TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1289 TestVideoGcmCipher(true, true);
1290}
1291
1292// Create a typical video answer with GCM ciphers enabled for the offer only,
1293// and ensure it matches what we expect.
1294TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1295 TestVideoGcmCipher(true, false);
1296}
1297
1298// Create a typical video answer with GCM ciphers enabled for the answer only,
1299// and ensure it matches what we expect.
1300TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1301 TestVideoGcmCipher(false, true);
1302}
1303
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001304TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001305 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001306 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 f1_.set_secure(SEC_ENABLED);
1308 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001309 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001311 std::unique_ptr<SessionDescription> answer =
1312 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001313 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001314 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001315 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001316 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001317 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1318 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001319 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001320 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001321 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001322 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001324 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001325 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001326 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001327 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001328 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001329 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001330 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001331 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001332 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333}
1334
jbauchcb560652016-08-04 05:20:32 -07001335TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001336 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001337 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001338 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001339 f1_.set_secure(SEC_ENABLED);
1340 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001341 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001342 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001343 std::unique_ptr<SessionDescription> answer =
1344 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001345 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001346 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001347 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001348 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001349 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1350 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001351 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001352 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001353 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001354 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001355 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001356 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001357 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001358 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001359 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001360 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001361 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001362 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001363 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001364 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001365}
1366
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001367// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1368// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001369TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1370 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001371 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001372 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001373 ASSERT_TRUE(offer.get() != NULL);
1374 ContentInfo* dc_offer = offer->GetContentByName("data");
1375 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001376 SctpDataContentDescription* dcd_offer =
1377 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001378 EXPECT_TRUE(dcd_offer->use_sctpmap());
1379
Steve Anton6fe1fba2018-12-11 10:15:23 -08001380 std::unique_ptr<SessionDescription> answer =
1381 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001382 const ContentInfo* dc_answer = answer->GetContentByName("data");
1383 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001384 const SctpDataContentDescription* dcd_answer =
1385 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001386 EXPECT_TRUE(dcd_answer->use_sctpmap());
1387}
1388
1389// The answer's use_sctpmap flag should match the offer's.
1390TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1391 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001392 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001393 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001394 ASSERT_TRUE(offer.get() != NULL);
1395 ContentInfo* dc_offer = offer->GetContentByName("data");
1396 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001397 SctpDataContentDescription* dcd_offer =
1398 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001399 dcd_offer->set_use_sctpmap(false);
1400
Steve Anton6fe1fba2018-12-11 10:15:23 -08001401 std::unique_ptr<SessionDescription> answer =
1402 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001403 const ContentInfo* dc_answer = answer->GetContentByName("data");
1404 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001405 const SctpDataContentDescription* dcd_answer =
1406 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001407 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001408}
1409
deadbeef8b7e9ad2017-05-25 09:38:55 -07001410// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1411// and "TCP/DTLS/SCTP" offers.
1412TEST_F(MediaSessionDescriptionFactoryTest,
1413 TestCreateDataAnswerToDifferentOfferedProtos) {
1414 // Need to enable DTLS offer/answer generation (disabled by default in this
1415 // test).
1416 f1_.set_secure(SEC_ENABLED);
1417 f2_.set_secure(SEC_ENABLED);
1418 tdf1_.set_secure(SEC_ENABLED);
1419 tdf2_.set_secure(SEC_ENABLED);
1420
1421 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001422 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001423 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001424 ASSERT_TRUE(offer.get() != nullptr);
1425 ContentInfo* dc_offer = offer->GetContentByName("data");
1426 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001427 SctpDataContentDescription* dcd_offer =
1428 dc_offer->media_description()->as_sctp();
1429 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001430
1431 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1432 "TCP/DTLS/SCTP"};
1433 for (const std::string& proto : protos) {
1434 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001435 std::unique_ptr<SessionDescription> answer =
1436 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001437 const ContentInfo* dc_answer = answer->GetContentByName("data");
1438 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001439 const SctpDataContentDescription* dcd_answer =
1440 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001441 EXPECT_FALSE(dc_answer->rejected);
1442 EXPECT_EQ(proto, dcd_answer->protocol());
1443 }
1444}
1445
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001446TEST_F(MediaSessionDescriptionFactoryTest,
1447 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1448 // Need to enable DTLS offer/answer generation (disabled by default in this
1449 // test).
1450 f1_.set_secure(SEC_ENABLED);
1451 f2_.set_secure(SEC_ENABLED);
1452 tdf1_.set_secure(SEC_ENABLED);
1453 tdf2_.set_secure(SEC_ENABLED);
1454
1455 MediaSessionOptions opts;
1456 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1457 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1458 ASSERT_TRUE(offer.get() != nullptr);
1459 ContentInfo* dc_offer = offer->GetContentByName("data");
1460 ASSERT_TRUE(dc_offer != nullptr);
1461 SctpDataContentDescription* dcd_offer =
1462 dc_offer->media_description()->as_sctp();
1463 ASSERT_TRUE(dcd_offer);
1464 dcd_offer->set_max_message_size(1234);
1465 std::unique_ptr<SessionDescription> answer =
1466 f2_.CreateAnswer(offer.get(), opts, nullptr);
1467 const ContentInfo* dc_answer = answer->GetContentByName("data");
1468 ASSERT_TRUE(dc_answer != nullptr);
1469 const SctpDataContentDescription* dcd_answer =
1470 dc_answer->media_description()->as_sctp();
1471 EXPECT_FALSE(dc_answer->rejected);
1472 EXPECT_EQ(1234, dcd_answer->max_message_size());
1473}
1474
1475TEST_F(MediaSessionDescriptionFactoryTest,
1476 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1477 // Need to enable DTLS offer/answer generation (disabled by default in this
1478 // test).
1479 f1_.set_secure(SEC_ENABLED);
1480 f2_.set_secure(SEC_ENABLED);
1481 tdf1_.set_secure(SEC_ENABLED);
1482 tdf2_.set_secure(SEC_ENABLED);
1483
1484 MediaSessionOptions opts;
1485 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1486 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1487 ASSERT_TRUE(offer.get() != nullptr);
1488 ContentInfo* dc_offer = offer->GetContentByName("data");
1489 ASSERT_TRUE(dc_offer != nullptr);
1490 SctpDataContentDescription* dcd_offer =
1491 dc_offer->media_description()->as_sctp();
1492 ASSERT_TRUE(dcd_offer);
1493 dcd_offer->set_max_message_size(0);
1494 std::unique_ptr<SessionDescription> answer =
1495 f2_.CreateAnswer(offer.get(), opts, nullptr);
1496 const ContentInfo* dc_answer = answer->GetContentByName("data");
1497 ASSERT_TRUE(dc_answer != nullptr);
1498 const SctpDataContentDescription* dcd_answer =
1499 dc_answer->media_description()->as_sctp();
1500 EXPECT_FALSE(dc_answer->rejected);
1501 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1502}
1503
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001504// Verifies that the order of the media contents in the offer is preserved in
1505// the answer.
1506TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1507 MediaSessionOptions opts;
1508
1509 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001510 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001511 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001512 ASSERT_TRUE(offer1.get() != NULL);
1513
1514 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001515 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1516 RtpTransceiverDirection::kRecvOnly, kActive,
1517 &opts);
kwiberg31022942016-03-11 14:18:21 -08001518 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001519 f1_.CreateOffer(opts, offer1.get()));
1520 ASSERT_TRUE(offer2.get() != NULL);
1521
1522 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001523 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1524 RtpTransceiverDirection::kRecvOnly, kActive,
1525 &opts);
kwiberg31022942016-03-11 14:18:21 -08001526 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001527 f1_.CreateOffer(opts, offer2.get()));
1528 ASSERT_TRUE(offer3.get() != NULL);
1529
Steve Anton6fe1fba2018-12-11 10:15:23 -08001530 std::unique_ptr<SessionDescription> answer =
1531 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001532 ASSERT_TRUE(answer.get() != NULL);
1533 EXPECT_EQ(3u, answer->contents().size());
1534 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1535 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1536 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1537}
1538
ossu075af922016-06-14 03:29:38 -07001539// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1540// answerer settings.
1541
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001542// This test that the media direction is set to send/receive in an answer if
1543// the offer is send receive.
1544TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001545 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1546 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001547}
1548
1549// This test that the media direction is set to receive only in an answer if
1550// the offer is send only.
1551TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001552 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1553 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554}
1555
1556// This test that the media direction is set to send only in an answer if
1557// the offer is recv only.
1558TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001559 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1560 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001561}
1562
1563// This test that the media direction is set to inactive in an answer if
1564// the offer is inactive.
1565TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001566 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1567 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568}
1569
1570// Test that a data content with an unknown protocol is rejected in an answer.
1571TEST_F(MediaSessionDescriptionFactoryTest,
1572 CreateDataAnswerToOfferWithUnknownProtocol) {
1573 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001574 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001575 f1_.set_secure(SEC_ENABLED);
1576 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001577 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001578 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001579 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001580 RtpDataContentDescription* dcd_offer =
1581 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001583 // Offer must be acceptable as an RTP protocol in order to be set.
1584 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001585 dcd_offer->set_protocol(protocol);
1586
Steve Anton6fe1fba2018-12-11 10:15:23 -08001587 std::unique_ptr<SessionDescription> answer =
1588 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001589
1590 const ContentInfo* dc_answer = answer->GetContentByName("data");
1591 ASSERT_TRUE(dc_answer != NULL);
1592 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001593 const RtpDataContentDescription* dcd_answer =
1594 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001595 ASSERT_TRUE(dcd_answer != NULL);
1596 EXPECT_EQ(protocol, dcd_answer->protocol());
1597}
1598
1599// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1600TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001601 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001602 f1_.set_secure(SEC_DISABLED);
1603 f2_.set_secure(SEC_DISABLED);
1604 tdf1_.set_secure(SEC_DISABLED);
1605 tdf2_.set_secure(SEC_DISABLED);
1606
Steve Anton6fe1fba2018-12-11 10:15:23 -08001607 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001608 const AudioContentDescription* offer_acd =
1609 GetFirstAudioContentDescription(offer.get());
1610 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001611 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001612
Steve Anton6fe1fba2018-12-11 10:15:23 -08001613 std::unique_ptr<SessionDescription> answer =
1614 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001615
1616 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1617 ASSERT_TRUE(ac_answer != NULL);
1618 EXPECT_FALSE(ac_answer->rejected);
1619
1620 const AudioContentDescription* answer_acd =
1621 GetFirstAudioContentDescription(answer.get());
1622 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001623 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001624}
1625
1626// Create a video offer and answer and ensure the RTP header extensions
1627// matches what we expect.
1628TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1629 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001630 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001631 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1632 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1633 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1634 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1635
Steve Anton6fe1fba2018-12-11 10:15:23 -08001636 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001637 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001638 std::unique_ptr<SessionDescription> answer =
1639 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640
Yves Gerey665174f2018-06-19 15:03:05 +02001641 EXPECT_EQ(
1642 MAKE_VECTOR(kAudioRtpExtension1),
1643 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1644 EXPECT_EQ(
1645 MAKE_VECTOR(kVideoRtpExtension1),
1646 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1647 EXPECT_EQ(
1648 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1649 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1650 EXPECT_EQ(
1651 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1652 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001653}
1654
Johannes Kronce8e8672019-02-22 13:06:44 +01001655// Create a audio/video offer and answer and ensure that the
1656// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1657// supported and should take precedence even though not listed among locally
1658// supported extensions.
1659TEST_F(MediaSessionDescriptionFactoryTest,
1660 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1661 TestTransportSequenceNumberNegotiation(
1662 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1663 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1664 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1665}
1666TEST_F(MediaSessionDescriptionFactoryTest,
1667 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1668 TestTransportSequenceNumberNegotiation(
1669 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1670 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1671 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1672}
1673TEST_F(MediaSessionDescriptionFactoryTest,
1674 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1675 TestTransportSequenceNumberNegotiation(
1676 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1677 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1678 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1679}
1680
jbauch5869f502017-06-29 12:31:36 -07001681TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001682 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1683 MediaSessionOptions opts;
1684 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1685
1686 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1687 f1_.set_audio_rtp_header_extensions(offered);
1688 f1_.set_video_rtp_header_extensions(offered);
1689 const auto local = MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01);
1690 f2_.set_audio_rtp_header_extensions(local);
1691 f2_.set_video_rtp_header_extensions(local);
1692 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1693 std::unique_ptr<SessionDescription> answer =
1694 f2_.CreateAnswer(offer.get(), opts, nullptr);
1695 EXPECT_THAT(
1696 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1697 ElementsAreArray(offered));
1698 EXPECT_THAT(
1699 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1700 ElementsAreArray(offered));
1701}
1702
1703TEST_F(MediaSessionDescriptionFactoryTest,
1704 TestNegotiateFrameDescriptorWhenExposedLocally) {
1705 MediaSessionOptions opts;
1706 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1707
1708 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1709 f1_.set_audio_rtp_header_extensions(offered);
1710 f1_.set_video_rtp_header_extensions(offered);
1711 const auto local = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1712 f2_.set_audio_rtp_header_extensions(local);
1713 f2_.set_video_rtp_header_extensions(local);
1714 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1715 std::unique_ptr<SessionDescription> answer =
1716 f2_.CreateAnswer(offer.get(), opts, nullptr);
1717 EXPECT_THAT(
1718 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1719 ElementsAreArray(offered));
1720 EXPECT_THAT(
1721 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1722 ElementsAreArray(offered));
1723}
1724
1725TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001726 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1727 MediaSessionOptions opts;
1728 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1729
1730 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1731 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1732 f1_.set_video_rtp_header_extensions({offer_dd});
1733 f2_.set_video_rtp_header_extensions({local_tsn});
1734 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1735 std::unique_ptr<SessionDescription> answer =
1736 f2_.CreateAnswer(offer.get(), opts, nullptr);
1737 EXPECT_THAT(
1738 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1739 ElementsAre(offer_dd));
1740}
1741
1742TEST_F(MediaSessionDescriptionFactoryTest,
1743 NegotiateDependencyDescriptorWhenExposedLocally) {
1744 MediaSessionOptions opts;
1745 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1746
1747 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1748 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
1749 f1_.set_video_rtp_header_extensions({offer_dd});
1750 f2_.set_video_rtp_header_extensions({local_dd});
1751 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1752 std::unique_ptr<SessionDescription> answer =
1753 f2_.CreateAnswer(offer.get(), opts, nullptr);
1754 EXPECT_THAT(
1755 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1756 ElementsAre(offer_dd));
1757}
1758
1759TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001760 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001761 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001762 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001763
1764 f1_.set_enable_encrypted_rtp_header_extensions(true);
1765 f2_.set_enable_encrypted_rtp_header_extensions(true);
1766
Yves Gerey665174f2018-06-19 15:03:05 +02001767 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1768 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1769 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1770 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001771
Steve Anton6fe1fba2018-12-11 10:15:23 -08001772 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001773 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001774 std::unique_ptr<SessionDescription> answer =
1775 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001776
Yves Gerey665174f2018-06-19 15:03:05 +02001777 EXPECT_EQ(
1778 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1779 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1780 EXPECT_EQ(
1781 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1782 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1783 EXPECT_EQ(
1784 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1785 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1786 EXPECT_EQ(
1787 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1788 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001789}
1790
1791TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001792 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001793 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001794 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001795
1796 f1_.set_enable_encrypted_rtp_header_extensions(true);
1797
Yves Gerey665174f2018-06-19 15:03:05 +02001798 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1799 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1800 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1801 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001802
Steve Anton6fe1fba2018-12-11 10:15:23 -08001803 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001804 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001805 std::unique_ptr<SessionDescription> answer =
1806 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001807
Yves Gerey665174f2018-06-19 15:03:05 +02001808 EXPECT_EQ(
1809 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1810 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1811 EXPECT_EQ(
1812 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1813 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1814 EXPECT_EQ(
1815 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1816 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1817 EXPECT_EQ(
1818 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1819 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001820}
1821
1822TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001823 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001824 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001825 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001826
1827 f2_.set_enable_encrypted_rtp_header_extensions(true);
1828
Yves Gerey665174f2018-06-19 15:03:05 +02001829 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1830 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1831 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1832 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001833
Steve Anton6fe1fba2018-12-11 10:15:23 -08001834 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001835 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001836 std::unique_ptr<SessionDescription> answer =
1837 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001838
Yves Gerey665174f2018-06-19 15:03:05 +02001839 EXPECT_EQ(
1840 MAKE_VECTOR(kAudioRtpExtension1),
1841 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1842 EXPECT_EQ(
1843 MAKE_VECTOR(kVideoRtpExtension1),
1844 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1845 EXPECT_EQ(
1846 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1847 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1848 EXPECT_EQ(
1849 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1850 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001851}
1852
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001853// Create an audio, video, data answer without legacy StreamParams.
1854TEST_F(MediaSessionDescriptionFactoryTest,
1855 TestCreateAnswerWithoutLegacyStreams) {
1856 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001857 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1858 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001859 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001860 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001861 std::unique_ptr<SessionDescription> answer =
1862 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001863 const ContentInfo* ac = answer->GetContentByName("audio");
1864 const ContentInfo* vc = answer->GetContentByName("video");
1865 const ContentInfo* dc = answer->GetContentByName("data");
1866 ASSERT_TRUE(ac != NULL);
1867 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001868 const AudioContentDescription* acd = ac->media_description()->as_audio();
1869 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001870 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871
1872 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1873 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1874 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1875}
1876
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001877// Create a typical video answer, and ensure it matches what we expect.
1878TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1879 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001880 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1881 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1882 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001883
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001885 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1886 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1887 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001888
kwiberg31022942016-03-11 14:18:21 -08001889 std::unique_ptr<SessionDescription> offer;
1890 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001891
1892 offer_opts.rtcp_mux_enabled = true;
1893 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001894 offer = f1_.CreateOffer(offer_opts, NULL);
1895 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001896 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1897 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001898 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001899 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1900 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001901 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001902 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1903 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001904 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001905 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1906 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001907 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001908
1909 offer_opts.rtcp_mux_enabled = true;
1910 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001911 offer = f1_.CreateOffer(offer_opts, NULL);
1912 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001913 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1914 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001915 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001916 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1917 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001918 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1920 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001921 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001922 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1923 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001924 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001925
1926 offer_opts.rtcp_mux_enabled = false;
1927 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001928 offer = f1_.CreateOffer(offer_opts, NULL);
1929 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001930 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1931 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001932 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001933 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1934 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001935 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001936 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1937 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001938 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1940 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001941 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942
1943 offer_opts.rtcp_mux_enabled = false;
1944 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001945 offer = f1_.CreateOffer(offer_opts, NULL);
1946 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001947 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1948 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001949 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1951 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001952 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1954 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001955 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001956 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1957 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001958 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001959}
1960
1961// Create an audio-only answer to a video offer.
1962TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1963 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001964 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1965 RtpTransceiverDirection::kRecvOnly, kActive,
1966 &opts);
1967 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1968 RtpTransceiverDirection::kRecvOnly, kActive,
1969 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001970 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001972
1973 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001974 std::unique_ptr<SessionDescription> answer =
1975 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976 const ContentInfo* ac = answer->GetContentByName("audio");
1977 const ContentInfo* vc = answer->GetContentByName("video");
1978 ASSERT_TRUE(ac != NULL);
1979 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001980 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001981 EXPECT_TRUE(vc->rejected);
1982}
1983
1984// Create an audio-only answer to an offer with data.
1985TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001986 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001987 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001988 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1989 RtpTransceiverDirection::kRecvOnly, kActive,
1990 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001991 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001992 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001993
1994 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001995 std::unique_ptr<SessionDescription> answer =
1996 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001997 const ContentInfo* ac = answer->GetContentByName("audio");
1998 const ContentInfo* dc = answer->GetContentByName("data");
1999 ASSERT_TRUE(ac != NULL);
2000 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002001 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002002 EXPECT_TRUE(dc->rejected);
2003}
2004
2005// Create an answer that rejects the contents which are rejected in the offer.
2006TEST_F(MediaSessionDescriptionFactoryTest,
2007 CreateAnswerToOfferWithRejectedMedia) {
2008 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002009 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2010 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002011 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002012 ASSERT_TRUE(offer.get() != NULL);
2013 ContentInfo* ac = offer->GetContentByName("audio");
2014 ContentInfo* vc = offer->GetContentByName("video");
2015 ContentInfo* dc = offer->GetContentByName("data");
2016 ASSERT_TRUE(ac != NULL);
2017 ASSERT_TRUE(vc != NULL);
2018 ASSERT_TRUE(dc != NULL);
2019 ac->rejected = true;
2020 vc->rejected = true;
2021 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002022 std::unique_ptr<SessionDescription> answer =
2023 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002024 ac = answer->GetContentByName("audio");
2025 vc = answer->GetContentByName("video");
2026 dc = answer->GetContentByName("data");
2027 ASSERT_TRUE(ac != NULL);
2028 ASSERT_TRUE(vc != NULL);
2029 ASSERT_TRUE(dc != NULL);
2030 EXPECT_TRUE(ac->rejected);
2031 EXPECT_TRUE(vc->rejected);
2032 EXPECT_TRUE(dc->rejected);
2033}
2034
Johannes Kron0854eb62018-10-10 22:33:20 +02002035TEST_F(MediaSessionDescriptionFactoryTest,
2036 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2037 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002038 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002039 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002040 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002041 ASSERT_TRUE(offer.get() != NULL);
2042 std::unique_ptr<SessionDescription> answer_no_support(
2043 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002044 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002045
2046 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002047 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002048 ASSERT_TRUE(offer.get() != NULL);
2049 std::unique_ptr<SessionDescription> answer_support(
2050 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002051 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002052}
2053
2054TEST_F(MediaSessionDescriptionFactoryTest,
2055 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2056 MediaSessionOptions opts;
2057 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002058 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002059 MediaContentDescription* video_offer =
2060 offer->GetContentDescriptionByName("video");
2061 ASSERT_TRUE(video_offer);
2062 MediaContentDescription* audio_offer =
2063 offer->GetContentDescriptionByName("audio");
2064 ASSERT_TRUE(audio_offer);
2065
2066 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002067 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2068 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002069
2070 ASSERT_TRUE(offer.get() != NULL);
2071 std::unique_ptr<SessionDescription> answer_no_support(
2072 f2_.CreateAnswer(offer.get(), opts, NULL));
2073 MediaContentDescription* video_answer =
2074 answer_no_support->GetContentDescriptionByName("video");
2075 MediaContentDescription* audio_answer =
2076 answer_no_support->GetContentDescriptionByName("audio");
2077 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002078 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002079 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002080 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002081
2082 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002083 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2084 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002085 ASSERT_TRUE(offer.get() != NULL);
2086 std::unique_ptr<SessionDescription> answer_support(
2087 f2_.CreateAnswer(offer.get(), opts, NULL));
2088 video_answer = answer_support->GetContentDescriptionByName("video");
2089 audio_answer = answer_support->GetContentDescriptionByName("audio");
2090 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002091 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002092 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002093 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002094}
2095
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002096// Create an audio and video offer with:
2097// - one video track
2098// - two audio tracks
2099// - two data tracks
2100// and ensure it matches what we expect. Also updates the initial offer by
2101// adding a new video track and replaces one of the audio tracks.
2102TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2103 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002104 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002105 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2106 {kMediaStream1}, 1, &opts);
2107 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2108 {kMediaStream1}, 1, &opts);
2109 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2110 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002111
Steve Anton4e70a722017-11-28 14:57:10 -08002112 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002113 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2114 {kMediaStream1}, 1, &opts);
2115 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2116 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002117
2118 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002119 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002120
2121 ASSERT_TRUE(offer.get() != NULL);
2122 const ContentInfo* ac = offer->GetContentByName("audio");
2123 const ContentInfo* vc = offer->GetContentByName("video");
2124 const ContentInfo* dc = offer->GetContentByName("data");
2125 ASSERT_TRUE(ac != NULL);
2126 ASSERT_TRUE(vc != NULL);
2127 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002128 const AudioContentDescription* acd = ac->media_description()->as_audio();
2129 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002130 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002132 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002133
2134 const StreamParamsVec& audio_streams = acd->streams();
2135 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002136 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002137 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2138 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2139 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2140 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2141 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2142 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2143
2144 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2145 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002146 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002147
2148 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002149 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002150 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151
2152 const StreamParamsVec& video_streams = vcd->streams();
2153 ASSERT_EQ(1U, video_streams.size());
2154 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2155 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2156 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2157 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2158
2159 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002160 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002161 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002162
2163 const StreamParamsVec& data_streams = dcd->streams();
2164 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002165 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002166 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2167 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2168 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2169 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2170 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2171 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2172
2173 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002174 dcd->bandwidth()); // default bandwidth (auto)
2175 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002176 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002177
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178 // Update the offer. Add a new video track that is not synched to the
2179 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002180 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2181 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002182 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002183 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2184 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002185 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002186 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2187 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002188 std::unique_ptr<SessionDescription> updated_offer(
2189 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002190
2191 ASSERT_TRUE(updated_offer.get() != NULL);
2192 ac = updated_offer->GetContentByName("audio");
2193 vc = updated_offer->GetContentByName("video");
2194 dc = updated_offer->GetContentByName("data");
2195 ASSERT_TRUE(ac != NULL);
2196 ASSERT_TRUE(vc != NULL);
2197 ASSERT_TRUE(dc != NULL);
2198 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002199 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002200 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002201 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002202 const RtpDataContentDescription* updated_dcd =
2203 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002204
2205 EXPECT_EQ(acd->type(), updated_acd->type());
2206 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2207 EXPECT_EQ(vcd->type(), updated_vcd->type());
2208 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2209 EXPECT_EQ(dcd->type(), updated_dcd->type());
2210 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002211 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002212 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002213 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002214 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002215 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002216 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2217
2218 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2219 ASSERT_EQ(2U, updated_audio_streams.size());
2220 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2221 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2222 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2223 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2224 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2225
2226 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2227 ASSERT_EQ(2U, updated_video_streams.size());
2228 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2229 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002230 // All the media streams in one PeerConnection share one RTCP CNAME.
2231 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002232
2233 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2234 ASSERT_EQ(2U, updated_data_streams.size());
2235 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2236 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2237 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2238 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2239 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002240 // The stream correctly got the CNAME from the MediaSessionOptions.
2241 // The Expected RTCP CNAME is the default one as we are using the default
2242 // MediaSessionOptions.
2243 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244}
2245
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002246// Create an offer with simulcast video stream.
2247TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2248 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002249 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2250 RtpTransceiverDirection::kRecvOnly, kActive,
2251 &opts);
2252 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2253 RtpTransceiverDirection::kSendRecv, kActive,
2254 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002255 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002256 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2257 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002258 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002259
2260 ASSERT_TRUE(offer.get() != NULL);
2261 const ContentInfo* vc = offer->GetContentByName("video");
2262 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002263 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002264
2265 const StreamParamsVec& video_streams = vcd->streams();
2266 ASSERT_EQ(1U, video_streams.size());
2267 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2268 const SsrcGroup* sim_ssrc_group =
2269 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2270 ASSERT_TRUE(sim_ssrc_group != NULL);
2271 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2272}
2273
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002274MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2275 const RidDescription& rid1 = ::testing::get<0>(arg);
2276 const RidDescription& rid2 = ::testing::get<1>(arg);
2277 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2278}
2279
2280static void CheckSimulcastInSessionDescription(
2281 const SessionDescription* description,
2282 const std::string& content_name,
2283 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002284 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002285 ASSERT_NE(description, nullptr);
2286 const ContentInfo* content = description->GetContentByName(content_name);
2287 ASSERT_NE(content, nullptr);
2288 const MediaContentDescription* cd = content->media_description();
2289 ASSERT_NE(cd, nullptr);
2290 const StreamParamsVec& streams = cd->streams();
2291 ASSERT_THAT(streams, SizeIs(1));
2292 const StreamParams& stream = streams[0];
2293 ASSERT_THAT(stream.ssrcs, IsEmpty());
2294 EXPECT_TRUE(stream.has_rids());
2295 const std::vector<RidDescription> rids = stream.rids();
2296
2297 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2298
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002299 EXPECT_TRUE(cd->HasSimulcast());
2300 const SimulcastDescription& simulcast = cd->simulcast_description();
2301 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2302 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2303
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002304 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002305}
2306
2307// Create an offer with spec-compliant simulcast video stream.
2308TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2309 MediaSessionOptions opts;
2310 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2311 RtpTransceiverDirection::kSendRecv, kActive,
2312 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002313 std::vector<RidDescription> send_rids;
2314 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2315 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2316 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2317 SimulcastLayerList simulcast_layers;
2318 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2319 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2320 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2321 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2322 {kMediaStream1}, send_rids,
2323 simulcast_layers, 0, &opts);
2324 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2325
2326 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002327 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002328}
2329
2330// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2331// In this scenario, RIDs do not need to be negotiated (there is only one).
2332TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2333 MediaSessionOptions opts;
2334 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2335 RtpTransceiverDirection::kSendRecv, kActive,
2336 &opts);
2337 RidDescription rid("f", RidDirection::kSend);
2338 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2339 {kMediaStream1}, {rid},
2340 SimulcastLayerList(), 0, &opts);
2341 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2342
2343 ASSERT_NE(offer.get(), nullptr);
2344 const ContentInfo* content = offer->GetContentByName("video");
2345 ASSERT_NE(content, nullptr);
2346 const MediaContentDescription* cd = content->media_description();
2347 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002348 const StreamParamsVec& streams = cd->streams();
2349 ASSERT_THAT(streams, SizeIs(1));
2350 const StreamParams& stream = streams[0];
2351 ASSERT_THAT(stream.ssrcs, IsEmpty());
2352 EXPECT_FALSE(stream.has_rids());
2353 EXPECT_FALSE(cd->HasSimulcast());
2354}
2355
2356// Create an answer with spec-compliant simulcast video stream.
2357// In this scenario, the SFU is the caller requesting that we send Simulcast.
2358TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2359 MediaSessionOptions offer_opts;
2360 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2361 RtpTransceiverDirection::kSendRecv, kActive,
2362 &offer_opts);
2363 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2364 {kMediaStream1}, 1, &offer_opts);
2365 std::unique_ptr<SessionDescription> offer =
2366 f1_.CreateOffer(offer_opts, nullptr);
2367
2368 MediaSessionOptions answer_opts;
2369 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2370 RtpTransceiverDirection::kSendRecv, kActive,
2371 &answer_opts);
2372
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002373 std::vector<RidDescription> rid_descriptions{
2374 RidDescription("f", RidDirection::kSend),
2375 RidDescription("h", RidDirection::kSend),
2376 RidDescription("q", RidDirection::kSend),
2377 };
2378 SimulcastLayerList simulcast_layers;
2379 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2380 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2381 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2382 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2383 {kMediaStream1}, rid_descriptions,
2384 simulcast_layers, 0, &answer_opts);
2385 std::unique_ptr<SessionDescription> answer =
2386 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2387
2388 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002389 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002390}
2391
2392// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2393// In this scenario, RIDs do not need to be negotiated (there is only one).
2394// Note that RID Direction is not the same as the transceiver direction.
2395TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2396 MediaSessionOptions offer_opts;
2397 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2398 RtpTransceiverDirection::kSendRecv, kActive,
2399 &offer_opts);
2400 RidDescription rid_offer("f", RidDirection::kSend);
2401 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2402 {kMediaStream1}, {rid_offer},
2403 SimulcastLayerList(), 0, &offer_opts);
2404 std::unique_ptr<SessionDescription> offer =
2405 f1_.CreateOffer(offer_opts, nullptr);
2406
2407 MediaSessionOptions answer_opts;
2408 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2409 RtpTransceiverDirection::kSendRecv, kActive,
2410 &answer_opts);
2411
2412 RidDescription rid_answer("f", RidDirection::kReceive);
2413 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2414 {kMediaStream1}, {rid_answer},
2415 SimulcastLayerList(), 0, &answer_opts);
2416 std::unique_ptr<SessionDescription> answer =
2417 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2418
2419 ASSERT_NE(answer.get(), nullptr);
2420 const ContentInfo* content = offer->GetContentByName("video");
2421 ASSERT_NE(content, nullptr);
2422 const MediaContentDescription* cd = content->media_description();
2423 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002424 const StreamParamsVec& streams = cd->streams();
2425 ASSERT_THAT(streams, SizeIs(1));
2426 const StreamParams& stream = streams[0];
2427 ASSERT_THAT(stream.ssrcs, IsEmpty());
2428 EXPECT_FALSE(stream.has_rids());
2429 EXPECT_FALSE(cd->HasSimulcast());
2430}
2431
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432// Create an audio and video answer to a standard video offer with:
2433// - one video track
2434// - two audio tracks
2435// - two data tracks
2436// and ensure it matches what we expect. Also updates the initial answer by
2437// adding a new video track and removes one of the audio tracks.
2438TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2439 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002440 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2441 RtpTransceiverDirection::kRecvOnly, kActive,
2442 &offer_opts);
2443 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2444 RtpTransceiverDirection::kRecvOnly, kActive,
2445 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002446 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002447 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2448 RtpTransceiverDirection::kRecvOnly, kActive,
2449 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002450 f1_.set_secure(SEC_ENABLED);
2451 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002452 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002453
zhihuang1c378ed2017-08-17 14:10:50 -07002454 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002455 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2456 RtpTransceiverDirection::kSendRecv, kActive,
2457 &answer_opts);
2458 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2459 RtpTransceiverDirection::kSendRecv, kActive,
2460 &answer_opts);
2461 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2462 {kMediaStream1}, 1, &answer_opts);
2463 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2464 {kMediaStream1}, 1, &answer_opts);
2465 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2466 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002467
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002468 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2469 RtpTransceiverDirection::kSendRecv, kActive,
2470 &answer_opts);
2471 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2472 {kMediaStream1}, 1, &answer_opts);
2473 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2474 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002475 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002476
Steve Anton6fe1fba2018-12-11 10:15:23 -08002477 std::unique_ptr<SessionDescription> answer =
2478 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002479
2480 ASSERT_TRUE(answer.get() != NULL);
2481 const ContentInfo* ac = answer->GetContentByName("audio");
2482 const ContentInfo* vc = answer->GetContentByName("video");
2483 const ContentInfo* dc = answer->GetContentByName("data");
2484 ASSERT_TRUE(ac != NULL);
2485 ASSERT_TRUE(vc != NULL);
2486 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002487 const AudioContentDescription* acd = ac->media_description()->as_audio();
2488 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002489 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002490 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2491 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2492 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002493
2494 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002495 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002496
2497 const StreamParamsVec& audio_streams = acd->streams();
2498 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002499 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002500 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2501 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2502 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2503 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2504 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2505 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2506
2507 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2508 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2509
2510 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002511 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002512
2513 const StreamParamsVec& video_streams = vcd->streams();
2514 ASSERT_EQ(1U, video_streams.size());
2515 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2516 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2517 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2518 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2519
2520 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002521 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002522
2523 const StreamParamsVec& data_streams = dcd->streams();
2524 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002525 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2527 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2528 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2529 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2530 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2531 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2532
2533 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002534 dcd->bandwidth()); // default bandwidth (auto)
2535 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002536
2537 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002538 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002539 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2540 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002541 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2542 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002543 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002544 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002545
2546 ASSERT_TRUE(updated_answer.get() != NULL);
2547 ac = updated_answer->GetContentByName("audio");
2548 vc = updated_answer->GetContentByName("video");
2549 dc = updated_answer->GetContentByName("data");
2550 ASSERT_TRUE(ac != NULL);
2551 ASSERT_TRUE(vc != NULL);
2552 ASSERT_TRUE(dc != NULL);
2553 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002554 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002555 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002556 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002557 const RtpDataContentDescription* updated_dcd =
2558 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002559
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002560 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002561 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002562 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002563 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002564 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002565 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2566
2567 EXPECT_EQ(acd->type(), updated_acd->type());
2568 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2569 EXPECT_EQ(vcd->type(), updated_vcd->type());
2570 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2571 EXPECT_EQ(dcd->type(), updated_dcd->type());
2572 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2573
2574 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2575 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002576 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002577
2578 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2579 ASSERT_EQ(2U, updated_video_streams.size());
2580 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2581 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002582 // All media streams in one PeerConnection share one CNAME.
2583 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002584
2585 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2586 ASSERT_EQ(1U, updated_data_streams.size());
2587 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2588}
2589
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002590// Create an updated offer after creating an answer to the original offer and
2591// verify that the codecs that were part of the original answer are not changed
2592// in the updated offer.
2593TEST_F(MediaSessionDescriptionFactoryTest,
2594 RespondentCreatesOfferAfterCreatingAnswer) {
2595 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002596 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002597
Steve Anton6fe1fba2018-12-11 10:15:23 -08002598 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2599 std::unique_ptr<SessionDescription> answer =
2600 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002601
2602 const AudioContentDescription* acd =
2603 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002604 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002605
2606 const VideoContentDescription* vcd =
2607 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002608 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002609
kwiberg31022942016-03-11 14:18:21 -08002610 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002611 f2_.CreateOffer(opts, answer.get()));
2612
2613 // The expected audio codecs are the common audio codecs from the first
2614 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2615 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002616 // TODO(wu): |updated_offer| should not include the codec
2617 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002618 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002619 kAudioCodecsAnswer[0],
2620 kAudioCodecsAnswer[1],
2621 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002622 };
2623
2624 // The expected video codecs are the common video codecs from the first
2625 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2626 // preference order.
2627 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002628 kVideoCodecsAnswer[0],
2629 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002630 };
2631
2632 const AudioContentDescription* updated_acd =
2633 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002634 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002635
2636 const VideoContentDescription* updated_vcd =
2637 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002638 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639}
2640
Steve Anton5c72e712018-12-10 14:25:30 -08002641// Test that a reoffer does not reuse audio codecs from a previous media section
2642// that is being recycled.
2643TEST_F(MediaSessionDescriptionFactoryTest,
2644 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002645 f1_.set_video_codecs({});
2646 f2_.set_video_codecs({});
Steve Anton5c72e712018-12-10 14:25:30 -08002647
2648 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002649 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2650 RtpTransceiverDirection::kSendRecv, kActive,
2651 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002652 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2653 std::unique_ptr<SessionDescription> answer =
2654 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002655
2656 // Recycle the media section by changing its mid.
2657 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002658 std::unique_ptr<SessionDescription> reoffer =
2659 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002660
2661 // Expect that the results of the first negotiation are ignored. If the m=
2662 // section was not recycled the payload types would match the initial offerer.
2663 const AudioContentDescription* acd =
2664 GetFirstAudioContentDescription(reoffer.get());
2665 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2666}
2667
2668// Test that a reoffer does not reuse video codecs from a previous media section
2669// that is being recycled.
2670TEST_F(MediaSessionDescriptionFactoryTest,
2671 ReOfferDoesNotReUseRecycledVideoCodecs) {
2672 f1_.set_audio_codecs({}, {});
2673 f2_.set_audio_codecs({}, {});
2674
2675 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002676 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2677 RtpTransceiverDirection::kSendRecv, kActive,
2678 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002679 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2680 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002681
2682 // Recycle the media section by changing its mid.
2683 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002684 std::unique_ptr<SessionDescription> reoffer =
2685 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002686
2687 // Expect that the results of the first negotiation are ignored. If the m=
2688 // section was not recycled the payload types would match the initial offerer.
2689 const VideoContentDescription* vcd =
2690 GetFirstVideoContentDescription(reoffer.get());
2691 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2692}
2693
2694// Test that a reanswer does not reuse audio codecs from a previous media
2695// section that is being recycled.
2696TEST_F(MediaSessionDescriptionFactoryTest,
2697 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002698 f1_.set_video_codecs({});
2699 f2_.set_video_codecs({});
Steve Anton5c72e712018-12-10 14:25:30 -08002700
2701 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2702 // second offer/answer is forward (|f1_| as offerer).
2703 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002704 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2705 RtpTransceiverDirection::kSendRecv, kActive,
2706 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002707 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2708 std::unique_ptr<SessionDescription> answer =
2709 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002710
2711 // Recycle the media section by changing its mid.
2712 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002713 std::unique_ptr<SessionDescription> reoffer =
2714 f1_.CreateOffer(opts, answer.get());
2715 std::unique_ptr<SessionDescription> reanswer =
2716 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002717
2718 // Expect that the results of the first negotiation are ignored. If the m=
2719 // section was not recycled the payload types would match the initial offerer.
2720 const AudioContentDescription* acd =
2721 GetFirstAudioContentDescription(reanswer.get());
2722 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2723}
2724
2725// Test that a reanswer does not reuse video codecs from a previous media
2726// section that is being recycled.
2727TEST_F(MediaSessionDescriptionFactoryTest,
2728 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2729 f1_.set_audio_codecs({}, {});
2730 f2_.set_audio_codecs({}, {});
2731
2732 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2733 // second offer/answer is forward (|f1_| as offerer).
2734 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002735 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2736 RtpTransceiverDirection::kSendRecv, kActive,
2737 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002738 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2739 std::unique_ptr<SessionDescription> answer =
2740 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002741
2742 // Recycle the media section by changing its mid.
2743 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002744 std::unique_ptr<SessionDescription> reoffer =
2745 f1_.CreateOffer(opts, answer.get());
2746 std::unique_ptr<SessionDescription> reanswer =
2747 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002748
2749 // Expect that the results of the first negotiation are ignored. If the m=
2750 // section was not recycled the payload types would match the initial offerer.
2751 const VideoContentDescription* vcd =
2752 GetFirstVideoContentDescription(reanswer.get());
2753 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2754}
2755
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002756// Create an updated offer after creating an answer to the original offer and
2757// verify that the codecs that were part of the original answer are not changed
2758// in the updated offer. In this test Rtx is enabled.
2759TEST_F(MediaSessionDescriptionFactoryTest,
2760 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2761 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002762 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2763 RtpTransceiverDirection::kRecvOnly, kActive,
2764 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002766 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002767 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002768 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002769
2770 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002771 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002772 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002773 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002774
Steve Anton6fe1fba2018-12-11 10:15:23 -08002775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002776 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002777 std::unique_ptr<SessionDescription> answer =
2778 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002779
2780 const VideoContentDescription* vcd =
2781 GetFirstVideoContentDescription(answer.get());
2782
2783 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002784 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2785 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786
2787 EXPECT_EQ(expected_codecs, vcd->codecs());
2788
deadbeef67cf2c12016-04-13 10:07:16 -07002789 // Now, make sure we get same result (except for the order) if |f2_| creates
2790 // an updated offer even though the default payload types between |f1_| and
2791 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002792 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793 f2_.CreateOffer(opts, answer.get()));
2794 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002795 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002796 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2797
2798 const VideoContentDescription* updated_vcd =
2799 GetFirstVideoContentDescription(updated_answer.get());
2800
2801 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2802}
2803
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002804// Regression test for:
2805// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2806// Existing codecs should always appear before new codecs in re-offers. But
2807// under a specific set of circumstances, the existing RTX codec was ending up
2808// added to the end of the list.
2809TEST_F(MediaSessionDescriptionFactoryTest,
2810 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2811 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002812 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2813 RtpTransceiverDirection::kRecvOnly, kActive,
2814 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002815 // We specifically choose different preferred payload types for VP8 to
2816 // trigger the issue.
2817 cricket::VideoCodec vp8_offerer(100, "VP8");
2818 cricket::VideoCodec vp8_offerer_rtx =
2819 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2820 cricket::VideoCodec vp8_answerer(110, "VP8");
2821 cricket::VideoCodec vp8_answerer_rtx =
2822 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2823 cricket::VideoCodec vp9(120, "VP9");
2824 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2825
2826 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2827 // We also specifically cause the answerer to prefer VP9, such that if it
2828 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2829 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2830 vp8_answerer_rtx};
2831
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002832 f1_.set_video_codecs(f1_codecs);
2833 f2_.set_video_codecs(f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002834 std::vector<AudioCodec> audio_codecs;
2835 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2836 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2837
2838 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002839 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002840 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002841 std::unique_ptr<SessionDescription> answer =
2842 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002843
2844 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2845 // But if the bug is triggered, RTX for VP8 ends up last.
2846 std::unique_ptr<SessionDescription> updated_offer(
2847 f2_.CreateOffer(opts, answer.get()));
2848
2849 const VideoContentDescription* vcd =
2850 GetFirstVideoContentDescription(updated_offer.get());
2851 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2852 ASSERT_EQ(4u, codecs.size());
2853 EXPECT_EQ(vp8_offerer, codecs[0]);
2854 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2855 EXPECT_EQ(vp9, codecs[2]);
2856 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002857}
2858
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002859// Create an updated offer that adds video after creating an audio only answer
2860// to the original offer. This test verifies that if a video codec and the RTX
2861// codec have the same default payload type as an audio codec that is already in
2862// use, the added codecs payload types are changed.
2863TEST_F(MediaSessionDescriptionFactoryTest,
2864 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2865 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002866 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002867 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002868 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002869
2870 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002871 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2872 RtpTransceiverDirection::kRecvOnly, kActive,
2873 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874
Steve Anton6fe1fba2018-12-11 10:15:23 -08002875 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2876 std::unique_ptr<SessionDescription> answer =
2877 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002878
2879 const AudioContentDescription* acd =
2880 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002881 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002882
2883 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2884 // reference be the same as an audio codec that was negotiated in the
2885 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002886 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002887 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002888
2889 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2890 int used_pl_type = acd->codecs()[0].id;
2891 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002892 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002893 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002894
kwiberg31022942016-03-11 14:18:21 -08002895 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002896 f2_.CreateOffer(opts, answer.get()));
2897 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002898 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002899 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2900
2901 const AudioContentDescription* updated_acd =
2902 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002903 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002904
2905 const VideoContentDescription* updated_vcd =
2906 GetFirstVideoContentDescription(updated_answer.get());
2907
2908 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002909 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002910 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002911 EXPECT_NE(used_pl_type, new_h264_pl_type);
2912 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002913 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002914 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2915 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2916}
2917
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002918// Create an updated offer with RTX after creating an answer to an offer
2919// without RTX, and with different default payload types.
2920// Verify that the added RTX codec references the correct payload type.
2921TEST_F(MediaSessionDescriptionFactoryTest,
2922 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2923 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002924 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002925
2926 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2927 // This creates rtx for H264 with the payload type |f2_| uses.
2928 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002929 f2_.set_video_codecs(f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002930
Steve Anton6fe1fba2018-12-11 10:15:23 -08002931 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002932 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002933 std::unique_ptr<SessionDescription> answer =
2934 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002935
2936 const VideoContentDescription* vcd =
2937 GetFirstVideoContentDescription(answer.get());
2938
2939 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2940 EXPECT_EQ(expected_codecs, vcd->codecs());
2941
2942 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2943 // updated offer, even though the default payload types are different from
2944 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002945 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002946 f2_.CreateOffer(opts, answer.get()));
2947 ASSERT_TRUE(updated_offer);
2948
2949 const VideoContentDescription* updated_vcd =
2950 GetFirstVideoContentDescription(updated_offer.get());
2951
2952 // New offer should attempt to add H263, and RTX for H264.
2953 expected_codecs.push_back(kVideoCodecs2[1]);
2954 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2955 &expected_codecs);
2956 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2957}
2958
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002959// Test that RTX is ignored when there is no associated payload type parameter.
2960TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2961 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002962 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2963 RtpTransceiverDirection::kRecvOnly, kActive,
2964 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002965 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002966 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002967 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002968 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002969
2970 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002971 // This creates RTX for H264 with the payload type |f2_| uses.
2972 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002973 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974
Steve Anton6fe1fba2018-12-11 10:15:23 -08002975 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002976 ASSERT_TRUE(offer.get() != NULL);
2977 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2978 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2979 // is possible to test that that RTX is dropped when
2980 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002981 MediaContentDescription* media_desc =
2982 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2983 ASSERT_TRUE(media_desc);
2984 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002985 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002986 for (VideoCodec& codec : codecs) {
2987 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2988 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002989 }
2990 }
2991 desc->set_codecs(codecs);
2992
Steve Anton6fe1fba2018-12-11 10:15:23 -08002993 std::unique_ptr<SessionDescription> answer =
2994 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002995
Steve Anton64b626b2019-01-28 17:25:26 -08002996 EXPECT_THAT(
2997 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2998 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002999}
3000
3001// Test that RTX will be filtered out in the answer if its associated payload
3002// type doesn't match the local value.
3003TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3004 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003005 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3006 RtpTransceiverDirection::kRecvOnly, kActive,
3007 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003008 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3009 // This creates RTX for H264 in sender.
3010 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003011 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003012
3013 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3014 // This creates RTX for H263 in receiver.
3015 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003016 f2_.set_video_codecs(f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003017
Steve Anton6fe1fba2018-12-11 10:15:23 -08003018 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003019 ASSERT_TRUE(offer.get() != NULL);
3020 // Associated payload type doesn't match, therefore, RTX codec is removed in
3021 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003022 std::unique_ptr<SessionDescription> answer =
3023 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003024
Steve Anton64b626b2019-01-28 17:25:26 -08003025 EXPECT_THAT(
3026 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3027 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003028}
3029
3030// Test that when multiple RTX codecs are offered, only the matched RTX codec
3031// is added in the answer, and the unsupported RTX codec is filtered out.
3032TEST_F(MediaSessionDescriptionFactoryTest,
3033 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3034 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003035 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3036 RtpTransceiverDirection::kRecvOnly, kActive,
3037 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003038 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3039 // This creates RTX for H264-SVC in sender.
3040 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003041 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003042
3043 // This creates RTX for H264 in sender.
3044 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003045 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003046
3047 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3048 // This creates RTX for H264 in receiver.
3049 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003050 f2_.set_video_codecs(f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003051
3052 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3053 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003054 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003055 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003056 std::unique_ptr<SessionDescription> answer =
3057 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003058 const VideoContentDescription* vcd =
3059 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003060 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3061 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3062 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003063
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003064 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003065}
3066
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003067// Test that after one RTX codec has been negotiated, a new offer can attempt
3068// to add another.
3069TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3070 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003071 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3072 RtpTransceiverDirection::kRecvOnly, kActive,
3073 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003074 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3075 // This creates RTX for H264 for the offerer.
3076 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003077 f1_.set_video_codecs(f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003078
Steve Anton6fe1fba2018-12-11 10:15:23 -08003079 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003080 ASSERT_TRUE(offer);
3081 const VideoContentDescription* vcd =
3082 GetFirstVideoContentDescription(offer.get());
3083
3084 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3085 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3086 &expected_codecs);
3087 EXPECT_EQ(expected_codecs, vcd->codecs());
3088
3089 // Now, attempt to add RTX for H264-SVC.
3090 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003091 f1_.set_video_codecs(f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003092
kwiberg31022942016-03-11 14:18:21 -08003093 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003094 f1_.CreateOffer(opts, offer.get()));
3095 ASSERT_TRUE(updated_offer);
3096 vcd = GetFirstVideoContentDescription(updated_offer.get());
3097
3098 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3099 &expected_codecs);
3100 EXPECT_EQ(expected_codecs, vcd->codecs());
3101}
3102
Noah Richards2e7a0982015-05-18 14:02:54 -07003103// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3104// generated for each simulcast ssrc and correctly grouped.
3105TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3106 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003107 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3108 RtpTransceiverDirection::kSendRecv, kActive,
3109 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003110 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003111 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3112 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003113
3114 // Use a single real codec, and then add RTX for it.
3115 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003116 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003117 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003118 f1_.set_video_codecs(f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003119
3120 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3121 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003122 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003123 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003124 MediaContentDescription* media_desc =
3125 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3126 ASSERT_TRUE(media_desc);
3127 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003128 const StreamParamsVec& streams = desc->streams();
3129 // Single stream.
3130 ASSERT_EQ(1u, streams.size());
3131 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3132 EXPECT_EQ(6u, streams[0].ssrcs.size());
3133 // And should have a SIM group for the simulcast.
3134 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3135 // And a FID group for RTX.
3136 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003137 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003138 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3139 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003140 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003141 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3142 EXPECT_EQ(3u, fid_ssrcs.size());
3143}
3144
brandtr03d5fb12016-11-22 03:37:59 -08003145// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3146// together with a FEC-FR grouping.
3147TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3148 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003149 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3150 RtpTransceiverDirection::kSendRecv, kActive,
3151 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003152 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003153 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3154 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003155
3156 // Use a single real codec, and then add FlexFEC for it.
3157 std::vector<VideoCodec> f1_codecs;
3158 f1_codecs.push_back(VideoCodec(97, "H264"));
3159 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003160 f1_.set_video_codecs(f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003161
3162 // Ensure that the offer has a single FlexFEC ssrc and that
3163 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003164 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003165 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003166 MediaContentDescription* media_desc =
3167 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3168 ASSERT_TRUE(media_desc);
3169 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003170 const StreamParamsVec& streams = desc->streams();
3171 // Single stream.
3172 ASSERT_EQ(1u, streams.size());
3173 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3174 EXPECT_EQ(2u, streams[0].ssrcs.size());
3175 // And should have a FEC-FR group for FlexFEC.
3176 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3177 std::vector<uint32_t> primary_ssrcs;
3178 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3179 ASSERT_EQ(1u, primary_ssrcs.size());
3180 uint32_t flexfec_ssrc;
3181 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3182 EXPECT_NE(flexfec_ssrc, 0u);
3183}
3184
3185// Test that FlexFEC is disabled for simulcast.
3186// TODO(brandtr): Remove this test when we support simulcast, either through
3187// multiple FlexfecSenders, or through multistream protection.
3188TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3189 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003190 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3191 RtpTransceiverDirection::kSendRecv, kActive,
3192 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003193 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003194 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3195 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003196
3197 // Use a single real codec, and then add FlexFEC for it.
3198 std::vector<VideoCodec> f1_codecs;
3199 f1_codecs.push_back(VideoCodec(97, "H264"));
3200 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003201 f1_.set_video_codecs(f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003202
3203 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3204 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003205 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003206 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003207 MediaContentDescription* media_desc =
3208 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3209 ASSERT_TRUE(media_desc);
3210 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003211 const StreamParamsVec& streams = desc->streams();
3212 // Single stream.
3213 ASSERT_EQ(1u, streams.size());
3214 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3215 EXPECT_EQ(3u, streams[0].ssrcs.size());
3216 // And should have a SIM group for the simulcast.
3217 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3218 // And not a FEC-FR group for FlexFEC.
3219 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3220 std::vector<uint32_t> primary_ssrcs;
3221 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3222 EXPECT_EQ(3u, primary_ssrcs.size());
3223 for (uint32_t primary_ssrc : primary_ssrcs) {
3224 uint32_t flexfec_ssrc;
3225 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3226 }
3227}
3228
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003229// Create an updated offer after creating an answer to the original offer and
3230// verify that the RTP header extensions that were part of the original answer
3231// are not changed in the updated offer.
3232TEST_F(MediaSessionDescriptionFactoryTest,
3233 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3234 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003235 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003236
3237 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3238 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3239 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3240 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3241
Steve Anton6fe1fba2018-12-11 10:15:23 -08003242 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3243 std::unique_ptr<SessionDescription> answer =
3244 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003245
Yves Gerey665174f2018-06-19 15:03:05 +02003246 EXPECT_EQ(
3247 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3248 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3249 EXPECT_EQ(
3250 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3251 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003252
kwiberg31022942016-03-11 14:18:21 -08003253 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003254 f2_.CreateOffer(opts, answer.get()));
3255
3256 // The expected RTP header extensions in the new offer are the resulting
3257 // extensions from the first offer/answer exchange plus the extensions only
3258 // |f2_| offer.
3259 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003260 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003261 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003262 kAudioRtpExtensionAnswer[0],
3263 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003264 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003265 };
3266
3267 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003268 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003269 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003270 kVideoRtpExtensionAnswer[0],
3271 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003272 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003273 };
3274
3275 const AudioContentDescription* updated_acd =
3276 GetFirstAudioContentDescription(updated_offer.get());
3277 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3278 updated_acd->rtp_header_extensions());
3279
3280 const VideoContentDescription* updated_vcd =
3281 GetFirstVideoContentDescription(updated_offer.get());
3282 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3283 updated_vcd->rtp_header_extensions());
3284}
3285
deadbeefa5b273a2015-08-20 17:30:13 -07003286// Verify that if the same RTP extension URI is used for audio and video, the
3287// same ID is used. Also verify that the ID isn't changed when creating an
3288// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003289TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003290 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003291 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003292
3293 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3294 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3295
Steve Anton6fe1fba2018-12-11 10:15:23 -08003296 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003297
3298 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3299 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003300 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003301 kVideoRtpExtension3[0],
3302 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003303 };
3304
Yves Gerey665174f2018-06-19 15:03:05 +02003305 EXPECT_EQ(
3306 MAKE_VECTOR(kAudioRtpExtension3),
3307 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3308 EXPECT_EQ(
3309 MAKE_VECTOR(kExpectedVideoRtpExtension),
3310 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003311
3312 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003313 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003314 f1_.CreateOffer(opts, offer.get()));
3315
3316 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003317 GetFirstAudioContentDescription(updated_offer.get())
3318 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003319 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003320 GetFirstVideoContentDescription(updated_offer.get())
3321 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003322}
3323
jbauch5869f502017-06-29 12:31:36 -07003324// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3325TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3326 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003327 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003328
3329 f1_.set_enable_encrypted_rtp_header_extensions(true);
3330 f2_.set_enable_encrypted_rtp_header_extensions(true);
3331
3332 f1_.set_audio_rtp_header_extensions(
3333 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3334 f1_.set_video_rtp_header_extensions(
3335 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3336
Steve Anton6fe1fba2018-12-11 10:15:23 -08003337 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003338
3339 // The extensions that are shared between audio and video should use the same
3340 // id.
3341 const RtpExtension kExpectedVideoRtpExtension[] = {
3342 kVideoRtpExtension3ForEncryption[0],
3343 kAudioRtpExtension3ForEncryptionOffer[1],
3344 kAudioRtpExtension3ForEncryptionOffer[2],
3345 };
3346
Yves Gerey665174f2018-06-19 15:03:05 +02003347 EXPECT_EQ(
3348 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3349 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3350 EXPECT_EQ(
3351 MAKE_VECTOR(kExpectedVideoRtpExtension),
3352 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003353
3354 // Nothing should change when creating a new offer
3355 std::unique_ptr<SessionDescription> updated_offer(
3356 f1_.CreateOffer(opts, offer.get()));
3357
3358 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003359 GetFirstAudioContentDescription(updated_offer.get())
3360 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003361 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003362 GetFirstVideoContentDescription(updated_offer.get())
3363 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003364}
3365
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003366TEST(MediaSessionDescription, CopySessionDescription) {
3367 SessionDescription source;
3368 cricket::ContentGroup group(cricket::CN_AUDIO);
3369 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003370 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003371 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003372 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3373 acd->AddLegacyStream(1);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003374 std::unique_ptr<AudioContentDescription> acd_passed =
3375 absl::WrapUnique(acd->Copy());
3376 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp,
3377 std::move(acd_passed));
3378 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003379 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003380 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3381 vcd->AddLegacyStream(2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003382 std::unique_ptr<VideoContentDescription> vcd_passed =
3383 absl::WrapUnique(vcd->Copy());
3384 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp,
3385 std::move(vcd_passed));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003386
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003387 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003388 ASSERT_TRUE(copy.get() != NULL);
3389 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3390 const ContentInfo* ac = copy->GetContentByName("audio");
3391 const ContentInfo* vc = copy->GetContentByName("video");
3392 ASSERT_TRUE(ac != NULL);
3393 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003394 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003395 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003396 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3397 EXPECT_EQ(1u, acd->first_ssrc());
3398
Steve Anton5adfafd2017-12-20 16:34:00 -08003399 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003400 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003401 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3402 EXPECT_EQ(2u, vcd->first_ssrc());
3403}
3404
3405// The below TestTransportInfoXXX tests create different offers/answers, and
3406// ensure the TransportInfo in the SessionDescription matches what we expect.
3407TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3408 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003409 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3410 RtpTransceiverDirection::kRecvOnly, kActive,
3411 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003412 TestTransportInfo(true, options, false);
3413}
3414
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003415TEST_F(MediaSessionDescriptionFactoryTest,
3416 TestTransportInfoOfferIceRenomination) {
3417 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003418 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3419 RtpTransceiverDirection::kRecvOnly, kActive,
3420 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003421 options.media_description_options[0]
3422 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003423 TestTransportInfo(true, options, false);
3424}
3425
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003426TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3427 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003428 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3429 RtpTransceiverDirection::kRecvOnly, kActive,
3430 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003431 TestTransportInfo(true, options, true);
3432}
3433
3434TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3435 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003436 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3437 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3438 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003439 TestTransportInfo(true, options, false);
3440}
3441
3442TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003443 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003444 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003445 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3446 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3447 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003448 TestTransportInfo(true, options, true);
3449}
3450
3451TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3452 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003453 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3454 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3455 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003456 options.bundle_enabled = true;
3457 TestTransportInfo(true, options, false);
3458}
3459
3460TEST_F(MediaSessionDescriptionFactoryTest,
3461 TestTransportInfoOfferBundleCurrent) {
3462 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003463 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3464 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3465 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003466 options.bundle_enabled = true;
3467 TestTransportInfo(true, options, true);
3468}
3469
3470TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3471 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003472 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3473 RtpTransceiverDirection::kRecvOnly, kActive,
3474 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003475 TestTransportInfo(false, options, false);
3476}
3477
3478TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003479 TestTransportInfoAnswerIceRenomination) {
3480 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003481 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3482 RtpTransceiverDirection::kRecvOnly, kActive,
3483 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003484 options.media_description_options[0]
3485 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003486 TestTransportInfo(false, options, false);
3487}
3488
3489TEST_F(MediaSessionDescriptionFactoryTest,
3490 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003491 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003492 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3493 RtpTransceiverDirection::kRecvOnly, kActive,
3494 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003495 TestTransportInfo(false, options, true);
3496}
3497
3498TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3499 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003500 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3501 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3502 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003503 TestTransportInfo(false, options, false);
3504}
3505
3506TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003507 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003508 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003509 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3510 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3511 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003512 TestTransportInfo(false, options, true);
3513}
3514
3515TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3516 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003517 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3518 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3519 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003520 options.bundle_enabled = true;
3521 TestTransportInfo(false, options, false);
3522}
3523
3524TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003525 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003526 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003527 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3528 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3529 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003530 options.bundle_enabled = true;
3531 TestTransportInfo(false, options, true);
3532}
3533
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003534TEST_F(MediaSessionDescriptionFactoryTest,
3535 TestTransportInfoOfferBundlesTransportOptions) {
3536 MediaSessionOptions options;
3537 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3538
3539 cricket::OpaqueTransportParameters audio_params;
3540 audio_params.protocol = "audio-transport";
3541 audio_params.parameters = "audio-params";
3542 FindFirstMediaDescriptionByMid("audio", &options)
3543 ->transport_options.opaque_parameters = audio_params;
3544
3545 cricket::OpaqueTransportParameters video_params;
3546 video_params.protocol = "video-transport";
3547 video_params.parameters = "video-params";
3548 FindFirstMediaDescriptionByMid("video", &options)
3549 ->transport_options.opaque_parameters = video_params;
3550
3551 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3552}
3553
3554TEST_F(MediaSessionDescriptionFactoryTest,
3555 TestTransportInfoAnswerBundlesTransportOptions) {
3556 MediaSessionOptions options;
3557 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3558
3559 cricket::OpaqueTransportParameters audio_params;
3560 audio_params.protocol = "audio-transport";
3561 audio_params.parameters = "audio-params";
3562 FindFirstMediaDescriptionByMid("audio", &options)
3563 ->transport_options.opaque_parameters = audio_params;
3564
3565 cricket::OpaqueTransportParameters video_params;
3566 video_params.protocol = "video-transport";
3567 video_params.parameters = "video-params";
3568 FindFirstMediaDescriptionByMid("video", &options)
3569 ->transport_options.opaque_parameters = video_params;
3570
3571 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3572}
3573
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003574TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3575 MediaSessionOptions options;
3576 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3577 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3578 &options);
3579
3580 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3581 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3582 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3583
3584 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3585
3586 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3587 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3588 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3589}
3590
3591TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3592 MediaSessionOptions options;
3593 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3594 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3595 &options);
3596
3597 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3598 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3599 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3600
3601 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3602 std::unique_ptr<SessionDescription> answer =
3603 f1_.CreateAnswer(offer.get(), options, nullptr);
3604
3605 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3606 "foo");
3607 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3608 "bar");
3609 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3610}
3611
3612TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3613 MediaSessionOptions options;
3614 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3615 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3616 &options);
3617
3618 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3619
3620 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3621 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3622 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3623
3624 std::unique_ptr<SessionDescription> answer =
3625 f1_.CreateAnswer(offer.get(), options, nullptr);
3626
3627 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3628 absl::nullopt);
3629 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3630 absl::nullopt);
3631 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3632 absl::nullopt);
3633}
3634
3635TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3636 MediaSessionOptions options;
3637 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3638 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3639 &options);
3640
3641 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3642 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3643 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3644
3645 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3646
3647 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3648 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3649 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3650
3651 std::unique_ptr<SessionDescription> answer =
3652 f1_.CreateAnswer(offer.get(), options, nullptr);
3653
3654 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3655 absl::nullopt);
3656 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3657 absl::nullopt);
3658 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3659 absl::nullopt);
3660}
3661
3662TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3663 MediaSessionOptions options;
3664 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3665 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3666 &options);
3667
3668 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3669 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3670 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3671
3672 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3673
3674 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3675 absl::nullopt;
3676 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3677 absl::nullopt;
3678 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3679 absl::nullopt;
3680
3681 std::unique_ptr<SessionDescription> answer =
3682 f1_.CreateAnswer(offer.get(), options, nullptr);
3683
3684 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3685 absl::nullopt);
3686 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3687 absl::nullopt);
3688 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3689 absl::nullopt);
3690}
3691
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003692// Create an offer with bundle enabled and verify the crypto parameters are
3693// the common set of the available cryptos.
3694TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3695 TestCryptoWithBundle(true);
3696}
3697
3698// Create an answer with bundle enabled and verify the crypto parameters are
3699// the common set of the available cryptos.
3700TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3701 TestCryptoWithBundle(false);
3702}
3703
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003704// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3705// DTLS is not enabled locally.
3706TEST_F(MediaSessionDescriptionFactoryTest,
3707 TestOfferDtlsSavpfWithoutDtlsFailed) {
3708 f1_.set_secure(SEC_ENABLED);
3709 f2_.set_secure(SEC_ENABLED);
3710 tdf1_.set_secure(SEC_DISABLED);
3711 tdf2_.set_secure(SEC_DISABLED);
3712
Steve Anton6fe1fba2018-12-11 10:15:23 -08003713 std::unique_ptr<SessionDescription> offer =
3714 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003715 ASSERT_TRUE(offer.get() != NULL);
3716 ContentInfo* offer_content = offer->GetContentByName("audio");
3717 ASSERT_TRUE(offer_content != NULL);
3718 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003719 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003720 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3721
Steve Anton6fe1fba2018-12-11 10:15:23 -08003722 std::unique_ptr<SessionDescription> answer =
3723 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003724 ASSERT_TRUE(answer != NULL);
3725 ContentInfo* answer_content = answer->GetContentByName("audio");
3726 ASSERT_TRUE(answer_content != NULL);
3727
3728 ASSERT_TRUE(answer_content->rejected);
3729}
3730
3731// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3732// UDP/TLS/RTP/SAVPF.
3733TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3734 f1_.set_secure(SEC_ENABLED);
3735 f2_.set_secure(SEC_ENABLED);
3736 tdf1_.set_secure(SEC_ENABLED);
3737 tdf2_.set_secure(SEC_ENABLED);
3738
Steve Anton6fe1fba2018-12-11 10:15:23 -08003739 std::unique_ptr<SessionDescription> offer =
3740 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003741 ASSERT_TRUE(offer.get() != NULL);
3742 ContentInfo* offer_content = offer->GetContentByName("audio");
3743 ASSERT_TRUE(offer_content != NULL);
3744 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003745 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003746 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3747
Steve Anton6fe1fba2018-12-11 10:15:23 -08003748 std::unique_ptr<SessionDescription> answer =
3749 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003750 ASSERT_TRUE(answer != NULL);
3751
3752 const ContentInfo* answer_content = answer->GetContentByName("audio");
3753 ASSERT_TRUE(answer_content != NULL);
3754 ASSERT_FALSE(answer_content->rejected);
3755
3756 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003757 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003758 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003759}
3760
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003761// Test that we include both SDES and DTLS in the offer, but only include SDES
3762// in the answer if DTLS isn't negotiated.
3763TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3764 f1_.set_secure(SEC_ENABLED);
3765 f2_.set_secure(SEC_ENABLED);
3766 tdf1_.set_secure(SEC_ENABLED);
3767 tdf2_.set_secure(SEC_DISABLED);
3768 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003769 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003770 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003771 const cricket::MediaContentDescription* audio_media_desc;
3772 const cricket::MediaContentDescription* video_media_desc;
3773 const cricket::TransportDescription* audio_trans_desc;
3774 const cricket::TransportDescription* video_trans_desc;
3775
3776 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003777 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003778 ASSERT_TRUE(offer.get() != NULL);
3779
Steve Antonb1c1de12017-12-21 15:14:30 -08003780 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003781 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003782 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003783 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003784 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003785 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3786
3787 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3788 ASSERT_TRUE(audio_trans_desc != NULL);
3789 video_trans_desc = offer->GetTransportDescriptionByName("video");
3790 ASSERT_TRUE(video_trans_desc != NULL);
3791 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3792 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3793
3794 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003795 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003796 ASSERT_TRUE(answer.get() != NULL);
3797
Steve Antonb1c1de12017-12-21 15:14:30 -08003798 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003799 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003800 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003801 ASSERT_TRUE(video_media_desc != NULL);
3802 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3803 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3804
3805 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3806 ASSERT_TRUE(audio_trans_desc != NULL);
3807 video_trans_desc = answer->GetTransportDescriptionByName("video");
3808 ASSERT_TRUE(video_trans_desc != NULL);
3809 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3810 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3811
3812 // Enable DTLS; the answer should now only have DTLS support.
3813 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003814 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003815 ASSERT_TRUE(answer.get() != NULL);
3816
Steve Antonb1c1de12017-12-21 15:14:30 -08003817 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003818 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003819 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003820 ASSERT_TRUE(video_media_desc != NULL);
3821 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3822 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003823 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3824 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003825
3826 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3827 ASSERT_TRUE(audio_trans_desc != NULL);
3828 video_trans_desc = answer->GetTransportDescriptionByName("video");
3829 ASSERT_TRUE(video_trans_desc != NULL);
3830 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3831 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003832
3833 // Try creating offer again. DTLS enabled now, crypto's should be empty
3834 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003835 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003836 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003837 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003838 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003839 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003840 ASSERT_TRUE(video_media_desc != NULL);
3841 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3842 EXPECT_TRUE(video_media_desc->cryptos().empty());
3843
3844 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3845 ASSERT_TRUE(audio_trans_desc != NULL);
3846 video_trans_desc = offer->GetTransportDescriptionByName("video");
3847 ASSERT_TRUE(video_trans_desc != NULL);
3848 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3849 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003850}
3851
3852// Test that an answer can't be created if cryptos are required but the offer is
3853// unsecure.
3854TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003855 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003856 f1_.set_secure(SEC_DISABLED);
3857 tdf1_.set_secure(SEC_DISABLED);
3858 f2_.set_secure(SEC_REQUIRED);
3859 tdf1_.set_secure(SEC_ENABLED);
3860
Steve Anton6fe1fba2018-12-11 10:15:23 -08003861 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003862 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003863 std::unique_ptr<SessionDescription> answer =
3864 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003865 EXPECT_TRUE(answer.get() == NULL);
3866}
3867
3868// Test that we accept a DTLS offer without SDES and create an appropriate
3869// answer.
3870TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3871 f1_.set_secure(SEC_DISABLED);
3872 f2_.set_secure(SEC_ENABLED);
3873 tdf1_.set_secure(SEC_ENABLED);
3874 tdf2_.set_secure(SEC_ENABLED);
3875 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003876 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3877 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3878 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003879
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003880 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003881 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003882 ASSERT_TRUE(offer.get() != NULL);
3883
3884 const AudioContentDescription* audio_offer =
3885 GetFirstAudioContentDescription(offer.get());
3886 ASSERT_TRUE(audio_offer->cryptos().empty());
3887 const VideoContentDescription* video_offer =
3888 GetFirstVideoContentDescription(offer.get());
3889 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003890 const RtpDataContentDescription* data_offer =
3891 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003892 ASSERT_TRUE(data_offer->cryptos().empty());
3893
3894 const cricket::TransportDescription* audio_offer_trans_desc =
3895 offer->GetTransportDescriptionByName("audio");
3896 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3897 const cricket::TransportDescription* video_offer_trans_desc =
3898 offer->GetTransportDescriptionByName("video");
3899 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3900 const cricket::TransportDescription* data_offer_trans_desc =
3901 offer->GetTransportDescriptionByName("data");
3902 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3903
3904 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003905 std::unique_ptr<SessionDescription> answer =
3906 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003907 ASSERT_TRUE(answer.get() != NULL);
3908
3909 const cricket::TransportDescription* audio_answer_trans_desc =
3910 answer->GetTransportDescriptionByName("audio");
3911 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3912 const cricket::TransportDescription* video_answer_trans_desc =
3913 answer->GetTransportDescriptionByName("video");
3914 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3915 const cricket::TransportDescription* data_answer_trans_desc =
3916 answer->GetTransportDescriptionByName("data");
3917 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3918}
3919
3920// Verifies if vad_enabled option is set to false, CN codecs are not present in
3921// offer or answer.
3922TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3923 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003924 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003925 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003926 ASSERT_TRUE(offer.get() != NULL);
3927 const ContentInfo* audio_content = offer->GetContentByName("audio");
3928 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3929
3930 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003931 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003932 ASSERT_TRUE(offer.get() != NULL);
3933 audio_content = offer->GetContentByName("audio");
3934 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003935 std::unique_ptr<SessionDescription> answer =
3936 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003937 ASSERT_TRUE(answer.get() != NULL);
3938 audio_content = answer->GetContentByName("audio");
3939 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3940}
deadbeef44f08192015-12-15 16:20:09 -08003941
zhihuang1c378ed2017-08-17 14:10:50 -07003942// Test that the generated MIDs match the existing offer.
3943TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003944 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003945 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3946 RtpTransceiverDirection::kRecvOnly, kActive,
3947 &opts);
3948 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3949 RtpTransceiverDirection::kRecvOnly, kActive,
3950 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003951 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003952 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3953 RtpTransceiverDirection::kSendRecv, kActive,
3954 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003955 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003956 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003957 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003958 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003959
deadbeef44f08192015-12-15 16:20:09 -08003960 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3961 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3962 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3963 ASSERT_TRUE(audio_content != nullptr);
3964 ASSERT_TRUE(video_content != nullptr);
3965 ASSERT_TRUE(data_content != nullptr);
3966 EXPECT_EQ("audio_modified", audio_content->name);
3967 EXPECT_EQ("video_modified", video_content->name);
3968 EXPECT_EQ("data_modified", data_content->name);
3969}
zhihuangcf5b37c2016-05-05 11:44:35 -07003970
zhihuang1c378ed2017-08-17 14:10:50 -07003971// The following tests verify that the unified plan SDP is supported.
3972// Test that we can create an offer with multiple media sections of same media
3973// type.
3974TEST_F(MediaSessionDescriptionFactoryTest,
3975 CreateOfferWithMultipleAVMediaSections) {
3976 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003977 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3978 RtpTransceiverDirection::kSendRecv, kActive,
3979 &opts);
3980 AttachSenderToMediaDescriptionOptions(
3981 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003982
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003983 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3984 RtpTransceiverDirection::kSendRecv, kActive,
3985 &opts);
3986 AttachSenderToMediaDescriptionOptions(
3987 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003988
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003989 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3990 RtpTransceiverDirection::kSendRecv, kActive,
3991 &opts);
3992 AttachSenderToMediaDescriptionOptions(
3993 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003994
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003995 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3996 RtpTransceiverDirection::kSendRecv, kActive,
3997 &opts);
3998 AttachSenderToMediaDescriptionOptions(
3999 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004000 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004001 ASSERT_TRUE(offer);
4002
4003 ASSERT_EQ(4u, offer->contents().size());
4004 EXPECT_FALSE(offer->contents()[0].rejected);
4005 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004006 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004007 ASSERT_EQ(1u, acd->streams().size());
4008 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004009 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004010
4011 EXPECT_FALSE(offer->contents()[1].rejected);
4012 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004013 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004014 ASSERT_EQ(1u, vcd->streams().size());
4015 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004016 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004017
4018 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004019 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004020 ASSERT_EQ(1u, acd->streams().size());
4021 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004022 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004023
4024 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004025 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004026 ASSERT_EQ(1u, vcd->streams().size());
4027 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004028 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004029}
4030
4031// Test that we can create an answer with multiple media sections of same media
4032// type.
4033TEST_F(MediaSessionDescriptionFactoryTest,
4034 CreateAnswerWithMultipleAVMediaSections) {
4035 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004036 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4037 RtpTransceiverDirection::kSendRecv, kActive,
4038 &opts);
4039 AttachSenderToMediaDescriptionOptions(
4040 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004041
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004042 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4043 RtpTransceiverDirection::kSendRecv, kActive,
4044 &opts);
4045 AttachSenderToMediaDescriptionOptions(
4046 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004047
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004048 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4049 RtpTransceiverDirection::kSendRecv, kActive,
4050 &opts);
4051 AttachSenderToMediaDescriptionOptions(
4052 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004053
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004054 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4055 RtpTransceiverDirection::kSendRecv, kActive,
4056 &opts);
4057 AttachSenderToMediaDescriptionOptions(
4058 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004059
Steve Anton6fe1fba2018-12-11 10:15:23 -08004060 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004061 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004062 std::unique_ptr<SessionDescription> answer =
4063 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004064
4065 ASSERT_EQ(4u, answer->contents().size());
4066 EXPECT_FALSE(answer->contents()[0].rejected);
4067 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004068 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004069 ASSERT_EQ(1u, acd->streams().size());
4070 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004071 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004072
4073 EXPECT_FALSE(answer->contents()[1].rejected);
4074 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004075 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004076 ASSERT_EQ(1u, vcd->streams().size());
4077 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004078 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004079
4080 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004081 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004082 ASSERT_EQ(1u, acd->streams().size());
4083 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004084 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004085
4086 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004087 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004088 ASSERT_EQ(1u, vcd->streams().size());
4089 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004090 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004091}
4092
4093// Test that the media section will be rejected in offer if the corresponding
4094// MediaDescriptionOptions is stopped by the offerer.
4095TEST_F(MediaSessionDescriptionFactoryTest,
4096 CreateOfferWithMediaSectionStoppedByOfferer) {
4097 // Create an offer with two audio sections and one of them is stopped.
4098 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004099 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4100 RtpTransceiverDirection::kSendRecv, kActive,
4101 &offer_opts);
4102 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4103 RtpTransceiverDirection::kInactive, kStopped,
4104 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004105 std::unique_ptr<SessionDescription> offer =
4106 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004107 ASSERT_TRUE(offer);
4108 ASSERT_EQ(2u, offer->contents().size());
4109 EXPECT_FALSE(offer->contents()[0].rejected);
4110 EXPECT_TRUE(offer->contents()[1].rejected);
4111}
4112
4113// Test that the media section will be rejected in answer if the corresponding
4114// MediaDescriptionOptions is stopped by the offerer.
4115TEST_F(MediaSessionDescriptionFactoryTest,
4116 CreateAnswerWithMediaSectionStoppedByOfferer) {
4117 // Create an offer with two audio sections and one of them is stopped.
4118 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004119 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4120 RtpTransceiverDirection::kSendRecv, kActive,
4121 &offer_opts);
4122 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4123 RtpTransceiverDirection::kInactive, kStopped,
4124 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004125 std::unique_ptr<SessionDescription> offer =
4126 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004127 ASSERT_TRUE(offer);
4128 ASSERT_EQ(2u, offer->contents().size());
4129 EXPECT_FALSE(offer->contents()[0].rejected);
4130 EXPECT_TRUE(offer->contents()[1].rejected);
4131
4132 // Create an answer based on the offer.
4133 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004134 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4135 RtpTransceiverDirection::kSendRecv, kActive,
4136 &answer_opts);
4137 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4138 RtpTransceiverDirection::kSendRecv, kActive,
4139 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004140 std::unique_ptr<SessionDescription> answer =
4141 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004142 ASSERT_EQ(2u, answer->contents().size());
4143 EXPECT_FALSE(answer->contents()[0].rejected);
4144 EXPECT_TRUE(answer->contents()[1].rejected);
4145}
4146
4147// Test that the media section will be rejected in answer if the corresponding
4148// MediaDescriptionOptions is stopped by the answerer.
4149TEST_F(MediaSessionDescriptionFactoryTest,
4150 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4151 // Create an offer with two audio sections.
4152 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004153 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4154 RtpTransceiverDirection::kSendRecv, kActive,
4155 &offer_opts);
4156 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4157 RtpTransceiverDirection::kSendRecv, kActive,
4158 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004159 std::unique_ptr<SessionDescription> offer =
4160 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004161 ASSERT_TRUE(offer);
4162 ASSERT_EQ(2u, offer->contents().size());
4163 ASSERT_FALSE(offer->contents()[0].rejected);
4164 ASSERT_FALSE(offer->contents()[1].rejected);
4165
4166 // The answerer rejects one of the audio sections.
4167 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004168 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4169 RtpTransceiverDirection::kSendRecv, kActive,
4170 &answer_opts);
4171 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4172 RtpTransceiverDirection::kInactive, kStopped,
4173 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004174 std::unique_ptr<SessionDescription> answer =
4175 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004176 ASSERT_EQ(2u, answer->contents().size());
4177 EXPECT_FALSE(answer->contents()[0].rejected);
4178 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004179
4180 // The TransportInfo of the rejected m= section is expected to be added in the
4181 // answer.
4182 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004183}
4184
4185// Test the generated media sections has the same order of the
4186// corresponding MediaDescriptionOptions.
4187TEST_F(MediaSessionDescriptionFactoryTest,
4188 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4189 MediaSessionOptions opts;
4190 // This tests put video section first because normally audio comes first by
4191 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004192 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4193 RtpTransceiverDirection::kSendRecv, kActive,
4194 &opts);
4195 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4196 RtpTransceiverDirection::kSendRecv, kActive,
4197 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004198 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004199
4200 ASSERT_TRUE(offer);
4201 ASSERT_EQ(2u, offer->contents().size());
4202 EXPECT_EQ("video", offer->contents()[0].name);
4203 EXPECT_EQ("audio", offer->contents()[1].name);
4204}
4205
4206// Test that different media sections using the same codec have same payload
4207// type.
4208TEST_F(MediaSessionDescriptionFactoryTest,
4209 PayloadTypesSharedByMediaSectionsOfSameType) {
4210 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004211 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4212 RtpTransceiverDirection::kSendRecv, kActive,
4213 &opts);
4214 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4215 RtpTransceiverDirection::kSendRecv, kActive,
4216 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004217 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004218 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004219 ASSERT_TRUE(offer);
4220 ASSERT_EQ(2u, offer->contents().size());
4221 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004222 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004223 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004224 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004225 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4226 ASSERT_EQ(2u, vcd1->codecs().size());
4227 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4228 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4229 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4230 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4231
4232 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004233 std::unique_ptr<SessionDescription> answer =
4234 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004235 ASSERT_TRUE(answer);
4236 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004237 vcd1 = answer->contents()[0].media_description()->as_video();
4238 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004239 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4240 ASSERT_EQ(1u, vcd1->codecs().size());
4241 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4242 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4243}
4244
4245// Test that the codec preference order per media section is respected in
4246// subsequent offer.
4247TEST_F(MediaSessionDescriptionFactoryTest,
4248 CreateOfferRespectsCodecPreferenceOrder) {
4249 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004250 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4251 RtpTransceiverDirection::kSendRecv, kActive,
4252 &opts);
4253 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4254 RtpTransceiverDirection::kSendRecv, kActive,
4255 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004256 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004257 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004258 ASSERT_TRUE(offer);
4259 ASSERT_EQ(2u, offer->contents().size());
4260 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004261 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004262 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004263 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004264 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4265 EXPECT_EQ(video_codecs, vcd1->codecs());
4266 EXPECT_EQ(video_codecs, vcd2->codecs());
4267
4268 // Change the codec preference of the first video section and create a
4269 // follow-up offer.
4270 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4271 vcd1->set_codecs(video_codecs_reverse);
4272 std::unique_ptr<SessionDescription> updated_offer(
4273 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004274 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4275 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004276 // The video codec preference order should be respected.
4277 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4278 EXPECT_EQ(video_codecs, vcd2->codecs());
4279}
4280
4281// Test that the codec preference order per media section is respected in
4282// the answer.
4283TEST_F(MediaSessionDescriptionFactoryTest,
4284 CreateAnswerRespectsCodecPreferenceOrder) {
4285 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004286 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4287 RtpTransceiverDirection::kSendRecv, kActive,
4288 &opts);
4289 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4290 RtpTransceiverDirection::kSendRecv, kActive,
4291 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004292 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004293 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004294 ASSERT_TRUE(offer);
4295 ASSERT_EQ(2u, offer->contents().size());
4296 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004297 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004298 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004299 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004300 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4301 EXPECT_EQ(video_codecs, vcd1->codecs());
4302 EXPECT_EQ(video_codecs, vcd2->codecs());
4303
4304 // Change the codec preference of the first video section and create an
4305 // answer.
4306 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4307 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004308 std::unique_ptr<SessionDescription> answer =
4309 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004310 vcd1 = answer->contents()[0].media_description()->as_video();
4311 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004312 // The video codec preference order should be respected.
4313 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4314 EXPECT_EQ(video_codecs, vcd2->codecs());
4315}
4316
Zhi Huang6f367472017-11-22 13:20:02 -08004317// Test that when creating an answer, the codecs use local parameters instead of
4318// the remote ones.
4319TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4320 const std::string audio_param_name = "audio_param";
4321 const std::string audio_value1 = "audio_v1";
4322 const std::string audio_value2 = "audio_v2";
4323 const std::string video_param_name = "video_param";
4324 const std::string video_value1 = "video_v1";
4325 const std::string video_value2 = "video_v2";
4326
4327 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4328 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4329 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4330 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4331
4332 // Set the parameters for codecs.
4333 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4334 video_codecs1[0].SetParam(video_param_name, video_value1);
4335 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4336 video_codecs2[0].SetParam(video_param_name, video_value2);
4337
4338 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004339 f1_.set_video_codecs(video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004340 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004341 f2_.set_video_codecs(video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004342
4343 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004344 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4345 RtpTransceiverDirection::kSendRecv, kActive,
4346 &opts);
4347 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4348 RtpTransceiverDirection::kSendRecv, kActive,
4349 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004350
Steve Anton6fe1fba2018-12-11 10:15:23 -08004351 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004352 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004353 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4354 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004355 std::string value;
4356 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4357 EXPECT_EQ(audio_value1, value);
4358 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4359 EXPECT_EQ(video_value1, value);
4360
Steve Anton6fe1fba2018-12-11 10:15:23 -08004361 std::unique_ptr<SessionDescription> answer =
4362 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004363 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004364 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4365 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004366 // Use the parameters from the local codecs.
4367 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4368 EXPECT_EQ(audio_value2, value);
4369 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4370 EXPECT_EQ(video_value2, value);
4371}
4372
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004373// Test that matching packetization-mode is part of the criteria for matching
4374// H264 codecs (in addition to profile-level-id). Previously, this was not the
4375// case, so the first H264 codec with the same profile-level-id would match and
4376// the payload type in the answer would be incorrect.
4377// This is a regression test for bugs.webrtc.org/8808
4378TEST_F(MediaSessionDescriptionFactoryTest,
4379 H264MatchCriteriaIncludesPacketizationMode) {
4380 // Create two H264 codecs with the same profile level ID and different
4381 // packetization modes.
4382 VideoCodec h264_pm0(96, "H264");
4383 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4384 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4385 VideoCodec h264_pm1(97, "H264");
4386 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4387 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4388
4389 // Offerer will send both codecs, answerer should choose the one with matching
4390 // packetization mode (and not the first one it sees).
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004391 f1_.set_video_codecs({h264_pm0, h264_pm1});
4392 f2_.set_video_codecs({h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004393
4394 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004395 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4396 RtpTransceiverDirection::kSendRecv, kActive,
4397 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004398
Steve Anton6fe1fba2018-12-11 10:15:23 -08004399 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004400 ASSERT_TRUE(offer);
4401
Steve Anton6fe1fba2018-12-11 10:15:23 -08004402 std::unique_ptr<SessionDescription> answer =
4403 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004404 ASSERT_TRUE(answer);
4405
4406 // Answer should have one negotiated codec with packetization-mode=1 using the
4407 // offered payload type.
4408 ASSERT_EQ(1u, answer->contents().size());
4409 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4410 ASSERT_EQ(1u, answer_vcd->codecs().size());
4411 auto answer_codec = answer_vcd->codecs()[0];
4412 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4413}
4414
zhihuangcf5b37c2016-05-05 11:44:35 -07004415class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4416 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004417 MediaProtocolTest()
4418 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004419 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4420 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004421 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004422 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004423 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4424 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004425 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004426 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004427 f1_.set_secure(SEC_ENABLED);
4428 f2_.set_secure(SEC_ENABLED);
4429 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004430 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004431 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004432 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004433 tdf1_.set_secure(SEC_ENABLED);
4434 tdf2_.set_secure(SEC_ENABLED);
4435 }
4436
4437 protected:
4438 MediaSessionDescriptionFactory f1_;
4439 MediaSessionDescriptionFactory f2_;
4440 TransportDescriptionFactory tdf1_;
4441 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004442 UniqueRandomIdGenerator ssrc_generator1;
4443 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004444};
4445
4446TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4447 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004448 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004449 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004450 ASSERT_TRUE(offer.get() != nullptr);
4451 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004452 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004453 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004454 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004455 std::unique_ptr<SessionDescription> answer =
4456 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004457 const ContentInfo* ac = answer->GetContentByName("audio");
4458 const ContentInfo* vc = answer->GetContentByName("video");
4459 ASSERT_TRUE(ac != nullptr);
4460 ASSERT_TRUE(vc != nullptr);
4461 EXPECT_FALSE(ac->rejected); // the offer is accepted
4462 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004463 const AudioContentDescription* acd = ac->media_description()->as_audio();
4464 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004465 EXPECT_EQ(GetParam(), acd->protocol());
4466 EXPECT_EQ(GetParam(), vcd->protocol());
4467}
4468
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004469INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4470 MediaProtocolTest,
4471 ::testing::ValuesIn(kMediaProtocols));
4472INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4473 MediaProtocolTest,
4474 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004475
4476TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4477 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004478 UniqueRandomIdGenerator ssrc_generator;
4479 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004480 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4481 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4482
4483 // The merged list of codecs should contain any send codecs that are also
4484 // nominally in the recieve codecs list. Payload types should be picked from
4485 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4486 // (set to 1). This equals what happens when the send codecs are used in an
4487 // offer and the receive codecs are used in the following answer.
4488 const std::vector<AudioCodec> sendrecv_codecs =
4489 MAKE_VECTOR(kAudioCodecsAnswer);
4490 const std::vector<AudioCodec> no_codecs;
4491
4492 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4493 << "Please don't change shared test data!";
4494 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4495 << "Please don't change shared test data!";
4496 // Alter iLBC send codec to have zero channels, to test that that is handled
4497 // properly.
4498 send_codecs[1].channels = 0;
4499
4500 // Alther iLBC receive codec to be lowercase, to test that case conversions
4501 // are handled properly.
4502 recv_codecs[2].name = "ilbc";
4503
4504 // Test proper merge
4505 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004506 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4507 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4508 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004509
4510 // Test empty send codecs list
4511 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004512 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4513 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4514 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004515
4516 // Test empty recv codecs list
4517 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004518 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4519 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4520 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004521
4522 // Test all empty codec lists
4523 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004524 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4525 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4526 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004527}
4528
4529namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004530// Compare the two vectors of codecs ignoring the payload type.
4531template <class Codec>
4532bool CodecsMatch(const std::vector<Codec>& codecs1,
4533 const std::vector<Codec>& codecs2) {
4534 if (codecs1.size() != codecs2.size()) {
4535 return false;
4536 }
4537
4538 for (size_t i = 0; i < codecs1.size(); ++i) {
4539 if (!codecs1[i].Matches(codecs2[i])) {
4540 return false;
4541 }
4542 }
4543 return true;
4544}
4545
Steve Anton4e70a722017-11-28 14:57:10 -08004546void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004547 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004548 UniqueRandomIdGenerator ssrc_generator;
4549 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004550 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4551 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4552 const std::vector<AudioCodec> sendrecv_codecs =
4553 MAKE_VECTOR(kAudioCodecsAnswer);
4554 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004555
4556 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004557 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4558 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004559
Steve Anton4e70a722017-11-28 14:57:10 -08004560 if (direction == RtpTransceiverDirection::kSendRecv ||
4561 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004562 AttachSenderToMediaDescriptionOptions(
4563 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004564 }
ossu075af922016-06-14 03:29:38 -07004565
Steve Anton6fe1fba2018-12-11 10:15:23 -08004566 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004567 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004568 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004569
4570 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004571 // that the codecs put in are right. This happens when we neither want to
4572 // send nor receive audio. The checks are still in place if at some point
4573 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004574 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004575 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004576 // sendrecv and inactive should both present lists as if the channel was
4577 // to be used for sending and receiving. Inactive essentially means it
4578 // might eventually be used anything, but we don't know more at this
4579 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004580 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004581 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004582 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004583 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004584 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004585 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004586 }
4587 }
4588}
4589
4590static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004591 AudioCodec(0, "codec0", 16000, -1, 1),
4592 AudioCodec(1, "codec1", 8000, 13300, 1),
4593 AudioCodec(2, "codec2", 8000, 64000, 1),
4594 AudioCodec(3, "codec3", 8000, 64000, 1),
4595 AudioCodec(4, "codec4", 8000, 0, 2),
4596 AudioCodec(5, "codec5", 32000, 0, 1),
4597 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004598
zhihuang1c378ed2017-08-17 14:10:50 -07004599/* The codecs groups below are chosen as per the matrix below. The objective
4600 * is to have different sets of codecs in the inputs, to get unique sets of
4601 * codecs after negotiation, depending on offer and answer communication
4602 * directions. One-way directions in the offer should either result in the
4603 * opposite direction in the answer, or an inactive answer. Regardless, the
4604 * choice of codecs should be as if the answer contained the opposite
4605 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004606 *
4607 * | Offer | Answer | Result
4608 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4609 * 0 | x - - | - x - | x - - - -
4610 * 1 | x x x | - x - | x - - x -
4611 * 2 | - x - | x - - | - x - - -
4612 * 3 | x x x | x - - | - x x - -
4613 * 4 | - x - | x x x | - x - - -
4614 * 5 | x - - | x x x | x - - - -
4615 * 6 | x x x | x x x | x x x x x
4616 */
4617// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004618static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4619static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004620// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4621// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004622static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4623static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004624// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004625static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4626static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4627static const int kResultSendrecv_SendCodecs[] = {3, 6};
4628static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4629static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004630
4631template <typename T, int IDXS>
4632std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4633 std::vector<T> out;
4634 out.reserve(IDXS);
4635 for (int idx : indices)
4636 out.push_back(array[idx]);
4637
4638 return out;
4639}
4640
Steve Anton4e70a722017-11-28 14:57:10 -08004641void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4642 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004643 bool add_legacy_stream) {
4644 TransportDescriptionFactory offer_tdf;
4645 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004646 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4647 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4648 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004649 offer_factory.set_audio_codecs(
4650 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4651 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4652 answer_factory.set_audio_codecs(
4653 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4654 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4655
ossu075af922016-06-14 03:29:38 -07004656 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004657 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4658 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004659
Steve Anton4e70a722017-11-28 14:57:10 -08004660 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004661 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4662 kAudioTrack1, {kMediaStream1}, 1,
4663 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004664 }
4665
Steve Anton6fe1fba2018-12-11 10:15:23 -08004666 std::unique_ptr<SessionDescription> offer =
4667 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004668 ASSERT_TRUE(offer.get() != NULL);
4669
4670 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004671 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4672 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004673
Steve Anton4e70a722017-11-28 14:57:10 -08004674 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004675 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4676 kAudioTrack1, {kMediaStream1}, 1,
4677 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004678 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004679 std::unique_ptr<SessionDescription> answer =
4680 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004681 const ContentInfo* ac = answer->GetContentByName("audio");
4682
zhihuang1c378ed2017-08-17 14:10:50 -07004683 // If the factory didn't add any audio content to the answer, we cannot
4684 // check that the codecs put in are right. This happens when we neither want
4685 // to send nor receive audio. The checks are still in place if at some point
4686 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004687 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004688 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4689 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004690
ossu075af922016-06-14 03:29:38 -07004691 std::vector<AudioCodec> target_codecs;
4692 // For offers with sendrecv or inactive, we should never reply with more
4693 // codecs than offered, with these codec sets.
4694 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004695 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004696 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4697 kResultSendrecv_SendrecvCodecs);
4698 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004699 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004700 target_codecs =
4701 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004702 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004703 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004704 target_codecs =
4705 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004706 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004707 case RtpTransceiverDirection::kSendRecv:
4708 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004709 target_codecs =
4710 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004711 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004712 target_codecs =
4713 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004714 } else {
4715 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4716 kResultSendrecv_SendrecvCodecs);
4717 }
4718 break;
4719 }
4720
zhihuang1c378ed2017-08-17 14:10:50 -07004721 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004722 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004723 bool first = true;
4724 os << "{";
4725 for (const auto& c : codecs) {
4726 os << (first ? " " : ", ") << c.id;
4727 first = false;
4728 }
4729 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004730 return os.Release();
ossu075af922016-06-14 03:29:38 -07004731 };
4732
4733 EXPECT_TRUE(acd->codecs() == target_codecs)
4734 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004735 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4736 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004737 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004738 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4739 << "; got: "
4740 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004741 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004742 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004743 << "Only inactive offers are allowed to not generate any audio "
4744 "content";
ossu075af922016-06-14 03:29:38 -07004745 }
4746}
brandtr03d5fb12016-11-22 03:37:59 -08004747
4748} // namespace
ossu075af922016-06-14 03:29:38 -07004749
4750class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004751 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004752
4753TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004754 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004755}
4756
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004757INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4758 AudioCodecsOfferTest,
4759 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4760 RtpTransceiverDirection::kRecvOnly,
4761 RtpTransceiverDirection::kSendRecv,
4762 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004763
4764class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004765 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4766 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004767 bool>> {};
ossu075af922016-06-14 03:29:38 -07004768
4769TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004770 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4771 ::testing::get<1>(GetParam()),
4772 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004773}
4774
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004775INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004776 MediaSessionDescriptionFactoryTest,
4777 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004778 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4779 RtpTransceiverDirection::kRecvOnly,
4780 RtpTransceiverDirection::kSendRecv,
4781 RtpTransceiverDirection::kInactive),
4782 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4783 RtpTransceiverDirection::kRecvOnly,
4784 RtpTransceiverDirection::kSendRecv,
4785 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004786 ::testing::Bool()));