blob: b217051054e095d0deed548eb0bafbc110ed59af [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 Alvestrand0fb07f82020-02-27 20:21:37 +01003374 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003375 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003376 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003377 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3378 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003379 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003380
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003381 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003382 ASSERT_TRUE(copy.get() != NULL);
3383 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3384 const ContentInfo* ac = copy->GetContentByName("audio");
3385 const ContentInfo* vc = copy->GetContentByName("video");
3386 ASSERT_TRUE(ac != NULL);
3387 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003388 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003389 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003390 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3391 EXPECT_EQ(1u, acd->first_ssrc());
3392
Steve Anton5adfafd2017-12-20 16:34:00 -08003393 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003394 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003395 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3396 EXPECT_EQ(2u, vcd->first_ssrc());
3397}
3398
3399// The below TestTransportInfoXXX tests create different offers/answers, and
3400// ensure the TransportInfo in the SessionDescription matches what we expect.
3401TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3402 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003403 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3404 RtpTransceiverDirection::kRecvOnly, kActive,
3405 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003406 TestTransportInfo(true, options, false);
3407}
3408
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003409TEST_F(MediaSessionDescriptionFactoryTest,
3410 TestTransportInfoOfferIceRenomination) {
3411 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003412 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3413 RtpTransceiverDirection::kRecvOnly, kActive,
3414 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003415 options.media_description_options[0]
3416 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003417 TestTransportInfo(true, options, false);
3418}
3419
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003420TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3421 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003422 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3423 RtpTransceiverDirection::kRecvOnly, kActive,
3424 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003425 TestTransportInfo(true, options, true);
3426}
3427
3428TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3429 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003430 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3431 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3432 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003433 TestTransportInfo(true, options, false);
3434}
3435
3436TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003437 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003438 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003439 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3440 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3441 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003442 TestTransportInfo(true, options, true);
3443}
3444
3445TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3446 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003447 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3448 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3449 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003450 options.bundle_enabled = true;
3451 TestTransportInfo(true, options, false);
3452}
3453
3454TEST_F(MediaSessionDescriptionFactoryTest,
3455 TestTransportInfoOfferBundleCurrent) {
3456 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003457 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3458 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3459 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003460 options.bundle_enabled = true;
3461 TestTransportInfo(true, options, true);
3462}
3463
3464TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3465 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003466 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3467 RtpTransceiverDirection::kRecvOnly, kActive,
3468 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003469 TestTransportInfo(false, options, false);
3470}
3471
3472TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003473 TestTransportInfoAnswerIceRenomination) {
3474 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003475 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3476 RtpTransceiverDirection::kRecvOnly, kActive,
3477 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003478 options.media_description_options[0]
3479 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003480 TestTransportInfo(false, options, false);
3481}
3482
3483TEST_F(MediaSessionDescriptionFactoryTest,
3484 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003485 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003486 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3487 RtpTransceiverDirection::kRecvOnly, kActive,
3488 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003489 TestTransportInfo(false, options, true);
3490}
3491
3492TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3493 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003494 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3495 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3496 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003497 TestTransportInfo(false, options, false);
3498}
3499
3500TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003501 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003502 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003503 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3504 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3505 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003506 TestTransportInfo(false, options, true);
3507}
3508
3509TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3510 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003511 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3512 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3513 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003514 options.bundle_enabled = true;
3515 TestTransportInfo(false, options, false);
3516}
3517
3518TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003519 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003520 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003521 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3522 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3523 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003524 options.bundle_enabled = true;
3525 TestTransportInfo(false, options, true);
3526}
3527
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003528TEST_F(MediaSessionDescriptionFactoryTest,
3529 TestTransportInfoOfferBundlesTransportOptions) {
3530 MediaSessionOptions options;
3531 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3532
3533 cricket::OpaqueTransportParameters audio_params;
3534 audio_params.protocol = "audio-transport";
3535 audio_params.parameters = "audio-params";
3536 FindFirstMediaDescriptionByMid("audio", &options)
3537 ->transport_options.opaque_parameters = audio_params;
3538
3539 cricket::OpaqueTransportParameters video_params;
3540 video_params.protocol = "video-transport";
3541 video_params.parameters = "video-params";
3542 FindFirstMediaDescriptionByMid("video", &options)
3543 ->transport_options.opaque_parameters = video_params;
3544
3545 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3546}
3547
3548TEST_F(MediaSessionDescriptionFactoryTest,
3549 TestTransportInfoAnswerBundlesTransportOptions) {
3550 MediaSessionOptions options;
3551 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3552
3553 cricket::OpaqueTransportParameters audio_params;
3554 audio_params.protocol = "audio-transport";
3555 audio_params.parameters = "audio-params";
3556 FindFirstMediaDescriptionByMid("audio", &options)
3557 ->transport_options.opaque_parameters = audio_params;
3558
3559 cricket::OpaqueTransportParameters video_params;
3560 video_params.protocol = "video-transport";
3561 video_params.parameters = "video-params";
3562 FindFirstMediaDescriptionByMid("video", &options)
3563 ->transport_options.opaque_parameters = video_params;
3564
3565 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3566}
3567
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003568TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3569 MediaSessionOptions options;
3570 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3571 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3572 &options);
3573
3574 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3575 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3576 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3577
3578 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3579
3580 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3581 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3582 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3583}
3584
3585TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3586 MediaSessionOptions options;
3587 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3588 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3589 &options);
3590
3591 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3592 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3593 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3594
3595 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3596 std::unique_ptr<SessionDescription> answer =
3597 f1_.CreateAnswer(offer.get(), options, nullptr);
3598
3599 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3600 "foo");
3601 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3602 "bar");
3603 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3604}
3605
3606TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3607 MediaSessionOptions options;
3608 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3609 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3610 &options);
3611
3612 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3613
3614 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3615 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3616 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3617
3618 std::unique_ptr<SessionDescription> answer =
3619 f1_.CreateAnswer(offer.get(), options, nullptr);
3620
3621 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3622 absl::nullopt);
3623 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3624 absl::nullopt);
3625 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3626 absl::nullopt);
3627}
3628
3629TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3630 MediaSessionOptions options;
3631 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3632 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3633 &options);
3634
3635 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3636 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3637 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3638
3639 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3640
3641 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3642 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3643 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3644
3645 std::unique_ptr<SessionDescription> answer =
3646 f1_.CreateAnswer(offer.get(), options, nullptr);
3647
3648 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3649 absl::nullopt);
3650 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3651 absl::nullopt);
3652 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3653 absl::nullopt);
3654}
3655
3656TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3657 MediaSessionOptions options;
3658 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3659 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3660 &options);
3661
3662 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3663 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3664 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3665
3666 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3667
3668 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3669 absl::nullopt;
3670 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3671 absl::nullopt;
3672 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3673 absl::nullopt;
3674
3675 std::unique_ptr<SessionDescription> answer =
3676 f1_.CreateAnswer(offer.get(), options, nullptr);
3677
3678 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3679 absl::nullopt);
3680 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3681 absl::nullopt);
3682 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3683 absl::nullopt);
3684}
3685
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003686// Create an offer with bundle enabled and verify the crypto parameters are
3687// the common set of the available cryptos.
3688TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3689 TestCryptoWithBundle(true);
3690}
3691
3692// Create an answer with bundle enabled and verify the crypto parameters are
3693// the common set of the available cryptos.
3694TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3695 TestCryptoWithBundle(false);
3696}
3697
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003698// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3699// DTLS is not enabled locally.
3700TEST_F(MediaSessionDescriptionFactoryTest,
3701 TestOfferDtlsSavpfWithoutDtlsFailed) {
3702 f1_.set_secure(SEC_ENABLED);
3703 f2_.set_secure(SEC_ENABLED);
3704 tdf1_.set_secure(SEC_DISABLED);
3705 tdf2_.set_secure(SEC_DISABLED);
3706
Steve Anton6fe1fba2018-12-11 10:15:23 -08003707 std::unique_ptr<SessionDescription> offer =
3708 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003709 ASSERT_TRUE(offer.get() != NULL);
3710 ContentInfo* offer_content = offer->GetContentByName("audio");
3711 ASSERT_TRUE(offer_content != NULL);
3712 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003713 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003714 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3715
Steve Anton6fe1fba2018-12-11 10:15:23 -08003716 std::unique_ptr<SessionDescription> answer =
3717 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003718 ASSERT_TRUE(answer != NULL);
3719 ContentInfo* answer_content = answer->GetContentByName("audio");
3720 ASSERT_TRUE(answer_content != NULL);
3721
3722 ASSERT_TRUE(answer_content->rejected);
3723}
3724
3725// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3726// UDP/TLS/RTP/SAVPF.
3727TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3728 f1_.set_secure(SEC_ENABLED);
3729 f2_.set_secure(SEC_ENABLED);
3730 tdf1_.set_secure(SEC_ENABLED);
3731 tdf2_.set_secure(SEC_ENABLED);
3732
Steve Anton6fe1fba2018-12-11 10:15:23 -08003733 std::unique_ptr<SessionDescription> offer =
3734 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003735 ASSERT_TRUE(offer.get() != NULL);
3736 ContentInfo* offer_content = offer->GetContentByName("audio");
3737 ASSERT_TRUE(offer_content != NULL);
3738 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003739 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003740 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3741
Steve Anton6fe1fba2018-12-11 10:15:23 -08003742 std::unique_ptr<SessionDescription> answer =
3743 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003744 ASSERT_TRUE(answer != NULL);
3745
3746 const ContentInfo* answer_content = answer->GetContentByName("audio");
3747 ASSERT_TRUE(answer_content != NULL);
3748 ASSERT_FALSE(answer_content->rejected);
3749
3750 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003751 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003752 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003753}
3754
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003755// Test that we include both SDES and DTLS in the offer, but only include SDES
3756// in the answer if DTLS isn't negotiated.
3757TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3758 f1_.set_secure(SEC_ENABLED);
3759 f2_.set_secure(SEC_ENABLED);
3760 tdf1_.set_secure(SEC_ENABLED);
3761 tdf2_.set_secure(SEC_DISABLED);
3762 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003763 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003764 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003765 const cricket::MediaContentDescription* audio_media_desc;
3766 const cricket::MediaContentDescription* video_media_desc;
3767 const cricket::TransportDescription* audio_trans_desc;
3768 const cricket::TransportDescription* video_trans_desc;
3769
3770 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003771 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003772 ASSERT_TRUE(offer.get() != NULL);
3773
Steve Antonb1c1de12017-12-21 15:14:30 -08003774 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003775 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003776 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003777 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003778 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003779 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3780
3781 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3782 ASSERT_TRUE(audio_trans_desc != NULL);
3783 video_trans_desc = offer->GetTransportDescriptionByName("video");
3784 ASSERT_TRUE(video_trans_desc != NULL);
3785 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3786 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3787
3788 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003789 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003790 ASSERT_TRUE(answer.get() != NULL);
3791
Steve Antonb1c1de12017-12-21 15:14:30 -08003792 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003793 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003794 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003795 ASSERT_TRUE(video_media_desc != NULL);
3796 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3797 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3798
3799 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3800 ASSERT_TRUE(audio_trans_desc != NULL);
3801 video_trans_desc = answer->GetTransportDescriptionByName("video");
3802 ASSERT_TRUE(video_trans_desc != NULL);
3803 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3804 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3805
3806 // Enable DTLS; the answer should now only have DTLS support.
3807 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003808 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003809 ASSERT_TRUE(answer.get() != NULL);
3810
Steve Antonb1c1de12017-12-21 15:14:30 -08003811 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003812 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003813 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003814 ASSERT_TRUE(video_media_desc != NULL);
3815 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3816 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003817 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3818 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003819
3820 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3821 ASSERT_TRUE(audio_trans_desc != NULL);
3822 video_trans_desc = answer->GetTransportDescriptionByName("video");
3823 ASSERT_TRUE(video_trans_desc != NULL);
3824 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3825 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003826
3827 // Try creating offer again. DTLS enabled now, crypto's should be empty
3828 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003829 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003830 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003831 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003832 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003833 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003834 ASSERT_TRUE(video_media_desc != NULL);
3835 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3836 EXPECT_TRUE(video_media_desc->cryptos().empty());
3837
3838 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3839 ASSERT_TRUE(audio_trans_desc != NULL);
3840 video_trans_desc = offer->GetTransportDescriptionByName("video");
3841 ASSERT_TRUE(video_trans_desc != NULL);
3842 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3843 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003844}
3845
3846// Test that an answer can't be created if cryptos are required but the offer is
3847// unsecure.
3848TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003849 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003850 f1_.set_secure(SEC_DISABLED);
3851 tdf1_.set_secure(SEC_DISABLED);
3852 f2_.set_secure(SEC_REQUIRED);
3853 tdf1_.set_secure(SEC_ENABLED);
3854
Steve Anton6fe1fba2018-12-11 10:15:23 -08003855 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003856 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003857 std::unique_ptr<SessionDescription> answer =
3858 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003859 EXPECT_TRUE(answer.get() == NULL);
3860}
3861
3862// Test that we accept a DTLS offer without SDES and create an appropriate
3863// answer.
3864TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3865 f1_.set_secure(SEC_DISABLED);
3866 f2_.set_secure(SEC_ENABLED);
3867 tdf1_.set_secure(SEC_ENABLED);
3868 tdf2_.set_secure(SEC_ENABLED);
3869 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003870 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3871 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3872 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003873
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003874 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003875 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003876 ASSERT_TRUE(offer.get() != NULL);
3877
3878 const AudioContentDescription* audio_offer =
3879 GetFirstAudioContentDescription(offer.get());
3880 ASSERT_TRUE(audio_offer->cryptos().empty());
3881 const VideoContentDescription* video_offer =
3882 GetFirstVideoContentDescription(offer.get());
3883 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003884 const RtpDataContentDescription* data_offer =
3885 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003886 ASSERT_TRUE(data_offer->cryptos().empty());
3887
3888 const cricket::TransportDescription* audio_offer_trans_desc =
3889 offer->GetTransportDescriptionByName("audio");
3890 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3891 const cricket::TransportDescription* video_offer_trans_desc =
3892 offer->GetTransportDescriptionByName("video");
3893 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3894 const cricket::TransportDescription* data_offer_trans_desc =
3895 offer->GetTransportDescriptionByName("data");
3896 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3897
3898 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003899 std::unique_ptr<SessionDescription> answer =
3900 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003901 ASSERT_TRUE(answer.get() != NULL);
3902
3903 const cricket::TransportDescription* audio_answer_trans_desc =
3904 answer->GetTransportDescriptionByName("audio");
3905 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3906 const cricket::TransportDescription* video_answer_trans_desc =
3907 answer->GetTransportDescriptionByName("video");
3908 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3909 const cricket::TransportDescription* data_answer_trans_desc =
3910 answer->GetTransportDescriptionByName("data");
3911 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3912}
3913
3914// Verifies if vad_enabled option is set to false, CN codecs are not present in
3915// offer or answer.
3916TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3917 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003918 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003919 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003920 ASSERT_TRUE(offer.get() != NULL);
3921 const ContentInfo* audio_content = offer->GetContentByName("audio");
3922 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3923
3924 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003925 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003926 ASSERT_TRUE(offer.get() != NULL);
3927 audio_content = offer->GetContentByName("audio");
3928 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003929 std::unique_ptr<SessionDescription> answer =
3930 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003931 ASSERT_TRUE(answer.get() != NULL);
3932 audio_content = answer->GetContentByName("audio");
3933 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3934}
deadbeef44f08192015-12-15 16:20:09 -08003935
zhihuang1c378ed2017-08-17 14:10:50 -07003936// Test that the generated MIDs match the existing offer.
3937TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003938 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003939 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3940 RtpTransceiverDirection::kRecvOnly, kActive,
3941 &opts);
3942 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3943 RtpTransceiverDirection::kRecvOnly, kActive,
3944 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003945 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003946 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3947 RtpTransceiverDirection::kSendRecv, kActive,
3948 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003949 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003950 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003951 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003952 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003953
deadbeef44f08192015-12-15 16:20:09 -08003954 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3955 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3956 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3957 ASSERT_TRUE(audio_content != nullptr);
3958 ASSERT_TRUE(video_content != nullptr);
3959 ASSERT_TRUE(data_content != nullptr);
3960 EXPECT_EQ("audio_modified", audio_content->name);
3961 EXPECT_EQ("video_modified", video_content->name);
3962 EXPECT_EQ("data_modified", data_content->name);
3963}
zhihuangcf5b37c2016-05-05 11:44:35 -07003964
zhihuang1c378ed2017-08-17 14:10:50 -07003965// The following tests verify that the unified plan SDP is supported.
3966// Test that we can create an offer with multiple media sections of same media
3967// type.
3968TEST_F(MediaSessionDescriptionFactoryTest,
3969 CreateOfferWithMultipleAVMediaSections) {
3970 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003971 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3972 RtpTransceiverDirection::kSendRecv, kActive,
3973 &opts);
3974 AttachSenderToMediaDescriptionOptions(
3975 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003976
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003977 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3978 RtpTransceiverDirection::kSendRecv, kActive,
3979 &opts);
3980 AttachSenderToMediaDescriptionOptions(
3981 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003982
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003983 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3984 RtpTransceiverDirection::kSendRecv, kActive,
3985 &opts);
3986 AttachSenderToMediaDescriptionOptions(
3987 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003988
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003989 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3990 RtpTransceiverDirection::kSendRecv, kActive,
3991 &opts);
3992 AttachSenderToMediaDescriptionOptions(
3993 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003995 ASSERT_TRUE(offer);
3996
3997 ASSERT_EQ(4u, offer->contents().size());
3998 EXPECT_FALSE(offer->contents()[0].rejected);
3999 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004000 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004001 ASSERT_EQ(1u, acd->streams().size());
4002 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004003 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004004
4005 EXPECT_FALSE(offer->contents()[1].rejected);
4006 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004007 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004008 ASSERT_EQ(1u, vcd->streams().size());
4009 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004010 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004011
4012 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004013 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004014 ASSERT_EQ(1u, acd->streams().size());
4015 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004016 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004017
4018 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004019 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004020 ASSERT_EQ(1u, vcd->streams().size());
4021 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004022 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004023}
4024
4025// Test that we can create an answer with multiple media sections of same media
4026// type.
4027TEST_F(MediaSessionDescriptionFactoryTest,
4028 CreateAnswerWithMultipleAVMediaSections) {
4029 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004030 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4031 RtpTransceiverDirection::kSendRecv, kActive,
4032 &opts);
4033 AttachSenderToMediaDescriptionOptions(
4034 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004035
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004036 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4037 RtpTransceiverDirection::kSendRecv, kActive,
4038 &opts);
4039 AttachSenderToMediaDescriptionOptions(
4040 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004041
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004042 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4043 RtpTransceiverDirection::kSendRecv, kActive,
4044 &opts);
4045 AttachSenderToMediaDescriptionOptions(
4046 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004047
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004048 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4049 RtpTransceiverDirection::kSendRecv, kActive,
4050 &opts);
4051 AttachSenderToMediaDescriptionOptions(
4052 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004053
Steve Anton6fe1fba2018-12-11 10:15:23 -08004054 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004055 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004056 std::unique_ptr<SessionDescription> answer =
4057 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004058
4059 ASSERT_EQ(4u, answer->contents().size());
4060 EXPECT_FALSE(answer->contents()[0].rejected);
4061 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004062 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004063 ASSERT_EQ(1u, acd->streams().size());
4064 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004065 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004066
4067 EXPECT_FALSE(answer->contents()[1].rejected);
4068 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004069 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004070 ASSERT_EQ(1u, vcd->streams().size());
4071 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004072 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004073
4074 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004075 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004076 ASSERT_EQ(1u, acd->streams().size());
4077 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004078 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004079
4080 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004081 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004082 ASSERT_EQ(1u, vcd->streams().size());
4083 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004084 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004085}
4086
4087// Test that the media section will be rejected in offer if the corresponding
4088// MediaDescriptionOptions is stopped by the offerer.
4089TEST_F(MediaSessionDescriptionFactoryTest,
4090 CreateOfferWithMediaSectionStoppedByOfferer) {
4091 // Create an offer with two audio sections and one of them is stopped.
4092 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004093 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4094 RtpTransceiverDirection::kSendRecv, kActive,
4095 &offer_opts);
4096 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4097 RtpTransceiverDirection::kInactive, kStopped,
4098 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004099 std::unique_ptr<SessionDescription> offer =
4100 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004101 ASSERT_TRUE(offer);
4102 ASSERT_EQ(2u, offer->contents().size());
4103 EXPECT_FALSE(offer->contents()[0].rejected);
4104 EXPECT_TRUE(offer->contents()[1].rejected);
4105}
4106
4107// Test that the media section will be rejected in answer if the corresponding
4108// MediaDescriptionOptions is stopped by the offerer.
4109TEST_F(MediaSessionDescriptionFactoryTest,
4110 CreateAnswerWithMediaSectionStoppedByOfferer) {
4111 // Create an offer with two audio sections and one of them is stopped.
4112 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004113 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4114 RtpTransceiverDirection::kSendRecv, kActive,
4115 &offer_opts);
4116 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4117 RtpTransceiverDirection::kInactive, kStopped,
4118 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004119 std::unique_ptr<SessionDescription> offer =
4120 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004121 ASSERT_TRUE(offer);
4122 ASSERT_EQ(2u, offer->contents().size());
4123 EXPECT_FALSE(offer->contents()[0].rejected);
4124 EXPECT_TRUE(offer->contents()[1].rejected);
4125
4126 // Create an answer based on the offer.
4127 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004128 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4129 RtpTransceiverDirection::kSendRecv, kActive,
4130 &answer_opts);
4131 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4132 RtpTransceiverDirection::kSendRecv, kActive,
4133 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004134 std::unique_ptr<SessionDescription> answer =
4135 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004136 ASSERT_EQ(2u, answer->contents().size());
4137 EXPECT_FALSE(answer->contents()[0].rejected);
4138 EXPECT_TRUE(answer->contents()[1].rejected);
4139}
4140
4141// Test that the media section will be rejected in answer if the corresponding
4142// MediaDescriptionOptions is stopped by the answerer.
4143TEST_F(MediaSessionDescriptionFactoryTest,
4144 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4145 // Create an offer with two audio sections.
4146 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004147 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4148 RtpTransceiverDirection::kSendRecv, kActive,
4149 &offer_opts);
4150 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4151 RtpTransceiverDirection::kSendRecv, kActive,
4152 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004153 std::unique_ptr<SessionDescription> offer =
4154 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004155 ASSERT_TRUE(offer);
4156 ASSERT_EQ(2u, offer->contents().size());
4157 ASSERT_FALSE(offer->contents()[0].rejected);
4158 ASSERT_FALSE(offer->contents()[1].rejected);
4159
4160 // The answerer rejects one of the audio sections.
4161 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004162 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4163 RtpTransceiverDirection::kSendRecv, kActive,
4164 &answer_opts);
4165 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4166 RtpTransceiverDirection::kInactive, kStopped,
4167 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004168 std::unique_ptr<SessionDescription> answer =
4169 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004170 ASSERT_EQ(2u, answer->contents().size());
4171 EXPECT_FALSE(answer->contents()[0].rejected);
4172 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004173
4174 // The TransportInfo of the rejected m= section is expected to be added in the
4175 // answer.
4176 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004177}
4178
4179// Test the generated media sections has the same order of the
4180// corresponding MediaDescriptionOptions.
4181TEST_F(MediaSessionDescriptionFactoryTest,
4182 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4183 MediaSessionOptions opts;
4184 // This tests put video section first because normally audio comes first by
4185 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004186 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4187 RtpTransceiverDirection::kSendRecv, kActive,
4188 &opts);
4189 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4190 RtpTransceiverDirection::kSendRecv, kActive,
4191 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004192 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004193
4194 ASSERT_TRUE(offer);
4195 ASSERT_EQ(2u, offer->contents().size());
4196 EXPECT_EQ("video", offer->contents()[0].name);
4197 EXPECT_EQ("audio", offer->contents()[1].name);
4198}
4199
4200// Test that different media sections using the same codec have same payload
4201// type.
4202TEST_F(MediaSessionDescriptionFactoryTest,
4203 PayloadTypesSharedByMediaSectionsOfSameType) {
4204 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004205 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4206 RtpTransceiverDirection::kSendRecv, kActive,
4207 &opts);
4208 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4209 RtpTransceiverDirection::kSendRecv, kActive,
4210 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004211 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004212 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004213 ASSERT_TRUE(offer);
4214 ASSERT_EQ(2u, offer->contents().size());
4215 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004216 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004217 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004218 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004219 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4220 ASSERT_EQ(2u, vcd1->codecs().size());
4221 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4222 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4223 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4224 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4225
4226 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004227 std::unique_ptr<SessionDescription> answer =
4228 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004229 ASSERT_TRUE(answer);
4230 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004231 vcd1 = answer->contents()[0].media_description()->as_video();
4232 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004233 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4234 ASSERT_EQ(1u, vcd1->codecs().size());
4235 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4236 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4237}
4238
4239// Test that the codec preference order per media section is respected in
4240// subsequent offer.
4241TEST_F(MediaSessionDescriptionFactoryTest,
4242 CreateOfferRespectsCodecPreferenceOrder) {
4243 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004244 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4245 RtpTransceiverDirection::kSendRecv, kActive,
4246 &opts);
4247 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4248 RtpTransceiverDirection::kSendRecv, kActive,
4249 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004250 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004251 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004252 ASSERT_TRUE(offer);
4253 ASSERT_EQ(2u, offer->contents().size());
4254 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004255 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004256 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004257 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004258 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4259 EXPECT_EQ(video_codecs, vcd1->codecs());
4260 EXPECT_EQ(video_codecs, vcd2->codecs());
4261
4262 // Change the codec preference of the first video section and create a
4263 // follow-up offer.
4264 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4265 vcd1->set_codecs(video_codecs_reverse);
4266 std::unique_ptr<SessionDescription> updated_offer(
4267 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004268 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4269 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004270 // The video codec preference order should be respected.
4271 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4272 EXPECT_EQ(video_codecs, vcd2->codecs());
4273}
4274
4275// Test that the codec preference order per media section is respected in
4276// the answer.
4277TEST_F(MediaSessionDescriptionFactoryTest,
4278 CreateAnswerRespectsCodecPreferenceOrder) {
4279 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004280 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4281 RtpTransceiverDirection::kSendRecv, kActive,
4282 &opts);
4283 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4284 RtpTransceiverDirection::kSendRecv, kActive,
4285 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004286 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004287 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004288 ASSERT_TRUE(offer);
4289 ASSERT_EQ(2u, offer->contents().size());
4290 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004291 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004292 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004293 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004294 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4295 EXPECT_EQ(video_codecs, vcd1->codecs());
4296 EXPECT_EQ(video_codecs, vcd2->codecs());
4297
4298 // Change the codec preference of the first video section and create an
4299 // answer.
4300 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4301 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004302 std::unique_ptr<SessionDescription> answer =
4303 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004304 vcd1 = answer->contents()[0].media_description()->as_video();
4305 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004306 // The video codec preference order should be respected.
4307 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4308 EXPECT_EQ(video_codecs, vcd2->codecs());
4309}
4310
Zhi Huang6f367472017-11-22 13:20:02 -08004311// Test that when creating an answer, the codecs use local parameters instead of
4312// the remote ones.
4313TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4314 const std::string audio_param_name = "audio_param";
4315 const std::string audio_value1 = "audio_v1";
4316 const std::string audio_value2 = "audio_v2";
4317 const std::string video_param_name = "video_param";
4318 const std::string video_value1 = "video_v1";
4319 const std::string video_value2 = "video_v2";
4320
4321 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4322 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4323 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4324 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4325
4326 // Set the parameters for codecs.
4327 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4328 video_codecs1[0].SetParam(video_param_name, video_value1);
4329 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4330 video_codecs2[0].SetParam(video_param_name, video_value2);
4331
4332 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004333 f1_.set_video_codecs(video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004334 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004335 f2_.set_video_codecs(video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004336
4337 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004338 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4339 RtpTransceiverDirection::kSendRecv, kActive,
4340 &opts);
4341 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4342 RtpTransceiverDirection::kSendRecv, kActive,
4343 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004344
Steve Anton6fe1fba2018-12-11 10:15:23 -08004345 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004346 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004347 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4348 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004349 std::string value;
4350 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4351 EXPECT_EQ(audio_value1, value);
4352 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4353 EXPECT_EQ(video_value1, value);
4354
Steve Anton6fe1fba2018-12-11 10:15:23 -08004355 std::unique_ptr<SessionDescription> answer =
4356 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004357 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004358 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4359 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004360 // Use the parameters from the local codecs.
4361 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4362 EXPECT_EQ(audio_value2, value);
4363 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4364 EXPECT_EQ(video_value2, value);
4365}
4366
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004367// Test that matching packetization-mode is part of the criteria for matching
4368// H264 codecs (in addition to profile-level-id). Previously, this was not the
4369// case, so the first H264 codec with the same profile-level-id would match and
4370// the payload type in the answer would be incorrect.
4371// This is a regression test for bugs.webrtc.org/8808
4372TEST_F(MediaSessionDescriptionFactoryTest,
4373 H264MatchCriteriaIncludesPacketizationMode) {
4374 // Create two H264 codecs with the same profile level ID and different
4375 // packetization modes.
4376 VideoCodec h264_pm0(96, "H264");
4377 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4378 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4379 VideoCodec h264_pm1(97, "H264");
4380 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4381 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4382
4383 // Offerer will send both codecs, answerer should choose the one with matching
4384 // packetization mode (and not the first one it sees).
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004385 f1_.set_video_codecs({h264_pm0, h264_pm1});
4386 f2_.set_video_codecs({h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004387
4388 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004389 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4390 RtpTransceiverDirection::kSendRecv, kActive,
4391 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004392
Steve Anton6fe1fba2018-12-11 10:15:23 -08004393 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004394 ASSERT_TRUE(offer);
4395
Steve Anton6fe1fba2018-12-11 10:15:23 -08004396 std::unique_ptr<SessionDescription> answer =
4397 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004398 ASSERT_TRUE(answer);
4399
4400 // Answer should have one negotiated codec with packetization-mode=1 using the
4401 // offered payload type.
4402 ASSERT_EQ(1u, answer->contents().size());
4403 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4404 ASSERT_EQ(1u, answer_vcd->codecs().size());
4405 auto answer_codec = answer_vcd->codecs()[0];
4406 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4407}
4408
zhihuangcf5b37c2016-05-05 11:44:35 -07004409class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4410 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004411 MediaProtocolTest()
4412 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004413 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4414 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004415 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004416 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004417 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4418 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004419 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004420 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004421 f1_.set_secure(SEC_ENABLED);
4422 f2_.set_secure(SEC_ENABLED);
4423 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004424 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004425 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004426 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004427 tdf1_.set_secure(SEC_ENABLED);
4428 tdf2_.set_secure(SEC_ENABLED);
4429 }
4430
4431 protected:
4432 MediaSessionDescriptionFactory f1_;
4433 MediaSessionDescriptionFactory f2_;
4434 TransportDescriptionFactory tdf1_;
4435 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004436 UniqueRandomIdGenerator ssrc_generator1;
4437 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004438};
4439
4440TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4441 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004442 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004443 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004444 ASSERT_TRUE(offer.get() != nullptr);
4445 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004446 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004447 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004448 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004449 std::unique_ptr<SessionDescription> answer =
4450 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004451 const ContentInfo* ac = answer->GetContentByName("audio");
4452 const ContentInfo* vc = answer->GetContentByName("video");
4453 ASSERT_TRUE(ac != nullptr);
4454 ASSERT_TRUE(vc != nullptr);
4455 EXPECT_FALSE(ac->rejected); // the offer is accepted
4456 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004457 const AudioContentDescription* acd = ac->media_description()->as_audio();
4458 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004459 EXPECT_EQ(GetParam(), acd->protocol());
4460 EXPECT_EQ(GetParam(), vcd->protocol());
4461}
4462
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004463INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4464 MediaProtocolTest,
4465 ::testing::ValuesIn(kMediaProtocols));
4466INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4467 MediaProtocolTest,
4468 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004469
4470TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4471 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004472 UniqueRandomIdGenerator ssrc_generator;
4473 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004474 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4475 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4476
4477 // The merged list of codecs should contain any send codecs that are also
4478 // nominally in the recieve codecs list. Payload types should be picked from
4479 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4480 // (set to 1). This equals what happens when the send codecs are used in an
4481 // offer and the receive codecs are used in the following answer.
4482 const std::vector<AudioCodec> sendrecv_codecs =
4483 MAKE_VECTOR(kAudioCodecsAnswer);
4484 const std::vector<AudioCodec> no_codecs;
4485
4486 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4487 << "Please don't change shared test data!";
4488 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4489 << "Please don't change shared test data!";
4490 // Alter iLBC send codec to have zero channels, to test that that is handled
4491 // properly.
4492 send_codecs[1].channels = 0;
4493
4494 // Alther iLBC receive codec to be lowercase, to test that case conversions
4495 // are handled properly.
4496 recv_codecs[2].name = "ilbc";
4497
4498 // Test proper merge
4499 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004500 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4501 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4502 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004503
4504 // Test empty send codecs list
4505 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004506 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4507 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4508 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004509
4510 // Test empty recv codecs list
4511 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004512 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4513 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4514 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004515
4516 // Test all empty codec lists
4517 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004518 EXPECT_EQ(no_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
4523namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004524// Compare the two vectors of codecs ignoring the payload type.
4525template <class Codec>
4526bool CodecsMatch(const std::vector<Codec>& codecs1,
4527 const std::vector<Codec>& codecs2) {
4528 if (codecs1.size() != codecs2.size()) {
4529 return false;
4530 }
4531
4532 for (size_t i = 0; i < codecs1.size(); ++i) {
4533 if (!codecs1[i].Matches(codecs2[i])) {
4534 return false;
4535 }
4536 }
4537 return true;
4538}
4539
Steve Anton4e70a722017-11-28 14:57:10 -08004540void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004541 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004542 UniqueRandomIdGenerator ssrc_generator;
4543 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004544 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4545 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4546 const std::vector<AudioCodec> sendrecv_codecs =
4547 MAKE_VECTOR(kAudioCodecsAnswer);
4548 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004549
4550 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004551 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4552 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004553
Steve Anton4e70a722017-11-28 14:57:10 -08004554 if (direction == RtpTransceiverDirection::kSendRecv ||
4555 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004556 AttachSenderToMediaDescriptionOptions(
4557 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004558 }
ossu075af922016-06-14 03:29:38 -07004559
Steve Anton6fe1fba2018-12-11 10:15:23 -08004560 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004561 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004562 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004563
4564 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004565 // that the codecs put in are right. This happens when we neither want to
4566 // send nor receive audio. The checks are still in place if at some point
4567 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004568 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004569 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004570 // sendrecv and inactive should both present lists as if the channel was
4571 // to be used for sending and receiving. Inactive essentially means it
4572 // might eventually be used anything, but we don't know more at this
4573 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004574 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004575 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004576 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004577 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004578 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004579 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004580 }
4581 }
4582}
4583
4584static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004585 AudioCodec(0, "codec0", 16000, -1, 1),
4586 AudioCodec(1, "codec1", 8000, 13300, 1),
4587 AudioCodec(2, "codec2", 8000, 64000, 1),
4588 AudioCodec(3, "codec3", 8000, 64000, 1),
4589 AudioCodec(4, "codec4", 8000, 0, 2),
4590 AudioCodec(5, "codec5", 32000, 0, 1),
4591 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004592
zhihuang1c378ed2017-08-17 14:10:50 -07004593/* The codecs groups below are chosen as per the matrix below. The objective
4594 * is to have different sets of codecs in the inputs, to get unique sets of
4595 * codecs after negotiation, depending on offer and answer communication
4596 * directions. One-way directions in the offer should either result in the
4597 * opposite direction in the answer, or an inactive answer. Regardless, the
4598 * choice of codecs should be as if the answer contained the opposite
4599 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004600 *
4601 * | Offer | Answer | Result
4602 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4603 * 0 | x - - | - x - | x - - - -
4604 * 1 | x x x | - x - | x - - x -
4605 * 2 | - x - | x - - | - x - - -
4606 * 3 | x x x | x - - | - x x - -
4607 * 4 | - x - | x x x | - x - - -
4608 * 5 | x - - | x x x | x - - - -
4609 * 6 | x x x | x x x | x x x x x
4610 */
4611// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004612static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4613static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004614// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4615// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004616static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4617static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004618// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004619static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4620static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4621static const int kResultSendrecv_SendCodecs[] = {3, 6};
4622static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4623static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004624
4625template <typename T, int IDXS>
4626std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4627 std::vector<T> out;
4628 out.reserve(IDXS);
4629 for (int idx : indices)
4630 out.push_back(array[idx]);
4631
4632 return out;
4633}
4634
Steve Anton4e70a722017-11-28 14:57:10 -08004635void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4636 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004637 bool add_legacy_stream) {
4638 TransportDescriptionFactory offer_tdf;
4639 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004640 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4641 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4642 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004643 offer_factory.set_audio_codecs(
4644 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4645 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4646 answer_factory.set_audio_codecs(
4647 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4648 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4649
ossu075af922016-06-14 03:29:38 -07004650 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004651 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4652 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004653
Steve Anton4e70a722017-11-28 14:57:10 -08004654 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004655 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4656 kAudioTrack1, {kMediaStream1}, 1,
4657 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004658 }
4659
Steve Anton6fe1fba2018-12-11 10:15:23 -08004660 std::unique_ptr<SessionDescription> offer =
4661 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004662 ASSERT_TRUE(offer.get() != NULL);
4663
4664 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004665 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4666 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004667
Steve Anton4e70a722017-11-28 14:57:10 -08004668 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004669 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4670 kAudioTrack1, {kMediaStream1}, 1,
4671 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004672 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004673 std::unique_ptr<SessionDescription> answer =
4674 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004675 const ContentInfo* ac = answer->GetContentByName("audio");
4676
zhihuang1c378ed2017-08-17 14:10:50 -07004677 // If the factory didn't add any audio content to the answer, we cannot
4678 // check that the codecs put in are right. This happens when we neither want
4679 // to send nor receive audio. The checks are still in place if at some point
4680 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004681 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004682 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4683 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004684
ossu075af922016-06-14 03:29:38 -07004685 std::vector<AudioCodec> target_codecs;
4686 // For offers with sendrecv or inactive, we should never reply with more
4687 // codecs than offered, with these codec sets.
4688 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004689 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004690 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4691 kResultSendrecv_SendrecvCodecs);
4692 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004693 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004694 target_codecs =
4695 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004696 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004697 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004698 target_codecs =
4699 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004700 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004701 case RtpTransceiverDirection::kSendRecv:
4702 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004703 target_codecs =
4704 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004705 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004706 target_codecs =
4707 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004708 } else {
4709 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4710 kResultSendrecv_SendrecvCodecs);
4711 }
4712 break;
4713 }
4714
zhihuang1c378ed2017-08-17 14:10:50 -07004715 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004716 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004717 bool first = true;
4718 os << "{";
4719 for (const auto& c : codecs) {
4720 os << (first ? " " : ", ") << c.id;
4721 first = false;
4722 }
4723 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004724 return os.Release();
ossu075af922016-06-14 03:29:38 -07004725 };
4726
4727 EXPECT_TRUE(acd->codecs() == target_codecs)
4728 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004729 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4730 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004731 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004732 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4733 << "; got: "
4734 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004735 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004736 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004737 << "Only inactive offers are allowed to not generate any audio "
4738 "content";
ossu075af922016-06-14 03:29:38 -07004739 }
4740}
brandtr03d5fb12016-11-22 03:37:59 -08004741
4742} // namespace
ossu075af922016-06-14 03:29:38 -07004743
4744class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004745 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004746
4747TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004748 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004749}
4750
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004751INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4752 AudioCodecsOfferTest,
4753 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4754 RtpTransceiverDirection::kRecvOnly,
4755 RtpTransceiverDirection::kSendRecv,
4756 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004757
4758class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004759 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4760 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004761 bool>> {};
ossu075af922016-06-14 03:29:38 -07004762
4763TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004764 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4765 ::testing::get<1>(GetParam()),
4766 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004767}
4768
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004769INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004770 MediaSessionDescriptionFactoryTest,
4771 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004772 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4773 RtpTransceiverDirection::kRecvOnly,
4774 RtpTransceiverDirection::kSendRecv,
4775 RtpTransceiverDirection::kInactive),
4776 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4777 RtpTransceiverDirection::kRecvOnly,
4778 RtpTransceiverDirection::kSendRecv,
4779 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004780 ::testing::Bool()));