blob: d8cb1591a97b0e6ffb3e0e11e2ef49f46647f17b [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 Bonadei57cabed2020-04-01 12:03:11 +020021#include "absl/strings/match.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020024#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "p2p/base/p2p_constants.h"
26#include "p2p/base/transport_description.h"
27#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "pc/rtp_media_utils.h"
29#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080033#include "rtc_base/message_digest.h"
34#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020035#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080036#include "rtc_base/unique_id_generator.h"
Philipp Hanckefedc7ab2020-11-17 21:59:12 +010037#include "test/field_trial.h"
Steve Antone38a5a12018-11-21 16:05:15 -080038#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
Yves Gerey665174f2018-06-19 15:03:05 +020040#define ASSERT_CRYPTO(cd, s, cs) \
41 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080042 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043
44typedef std::vector<cricket::Candidate> Candidates;
45
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080046using cricket::AudioCodec;
47using cricket::AudioContentDescription;
48using cricket::ContentInfo;
49using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080050using cricket::GetFirstAudioContent;
51using cricket::GetFirstAudioContentDescription;
52using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020053using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080054using cricket::GetFirstVideoContent;
55using cricket::GetFirstVideoContentDescription;
56using cricket::kAutoBandwidth;
57using cricket::MEDIA_TYPE_AUDIO;
58using cricket::MEDIA_TYPE_DATA;
59using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070061using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080062using cricket::MediaProtocolType;
63using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064using cricket::MediaSessionOptions;
65using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080066using cricket::RidDescription;
67using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020068using cricket::RtpDataCodec;
69using cricket::RtpDataContentDescription;
70using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080071using cricket::SEC_DISABLED;
72using cricket::SEC_ENABLED;
73using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080075using cricket::SimulcastDescription;
76using cricket::SimulcastLayer;
77using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000078using cricket::SsrcGroup;
79using cricket::StreamParams;
80using cricket::StreamParamsVec;
81using cricket::TransportDescription;
82using cricket::TransportDescriptionFactory;
83using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000084using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080085using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070086using rtc::CS_AEAD_AES_128_GCM;
87using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080088using rtc::CS_AES_CM_128_HMAC_SHA1_32;
89using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080090using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020091using ::testing::Contains;
92using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +010093using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020094using ::testing::ElementsAreArray;
95using ::testing::Eq;
96using ::testing::Field;
97using ::testing::IsEmpty;
98using ::testing::IsFalse;
99using ::testing::Ne;
100using ::testing::Not;
101using ::testing::Pointwise;
102using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700103using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800104using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105
106static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700107 AudioCodec(103, "ISAC", 16000, -1, 1),
108 AudioCodec(102, "iLBC", 8000, 13300, 1),
109 AudioCodec(0, "PCMU", 8000, 64000, 1),
110 AudioCodec(8, "PCMA", 8000, 64000, 1),
111 AudioCodec(117, "red", 8000, 0, 1),
112 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113
114static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200115 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700116 AudioCodec(0, "PCMU", 8000, 64000, 1),
117 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118};
119
120static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700121 AudioCodec(102, "iLBC", 8000, 13300, 1),
122 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123};
124
perkj26752742016-10-24 01:21:16 -0700125static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
126 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127
zhihuang1c378ed2017-08-17 14:10:50 -0700128static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
129 VideoCodec(96, "H264-SVC")};
130
perkj26752742016-10-24 01:21:16 -0700131static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
132 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133
perkj26752742016-10-24 01:21:16 -0700134static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200136static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
137 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200139static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
140 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000141
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200142static const RtpDataCodec kDataCodecsAnswer[] = {
143 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000144
isheriff6f8d6862016-05-26 11:24:55 -0700145static const RtpExtension kAudioRtpExtension1[] = {
146 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
147 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148};
149
jbauch5869f502017-06-29 12:31:36 -0700150static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
152 RtpExtension("http://google.com/testing/audio_something", 10),
153 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
154};
155
isheriff6f8d6862016-05-26 11:24:55 -0700156static const RtpExtension kAudioRtpExtension2[] = {
157 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
158 RtpExtension("http://google.com/testing/audio_something_else", 8),
159 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160};
161
isheriff6f8d6862016-05-26 11:24:55 -0700162static const RtpExtension kAudioRtpExtension3[] = {
163 RtpExtension("http://google.com/testing/audio_something", 2),
164 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700165};
166
jbauch5869f502017-06-29 12:31:36 -0700167static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
168 RtpExtension("http://google.com/testing/audio_something", 2),
169 // Use RTP extension that supports encryption.
170 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
171};
172
173static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
174 RtpExtension("http://google.com/testing/audio_something", 2),
175 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
176 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
177};
178
isheriff6f8d6862016-05-26 11:24:55 -0700179static const RtpExtension kAudioRtpExtensionAnswer[] = {
180 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000181};
182
jbauch5869f502017-06-29 12:31:36 -0700183static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
184 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
185};
186
isheriff6f8d6862016-05-26 11:24:55 -0700187static const RtpExtension kVideoRtpExtension1[] = {
188 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
189 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190};
191
jbauch5869f502017-06-29 12:31:36 -0700192static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
193 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
194 RtpExtension("http://google.com/testing/video_something", 13),
195 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
196};
197
isheriff6f8d6862016-05-26 11:24:55 -0700198static const RtpExtension kVideoRtpExtension2[] = {
199 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
200 RtpExtension("http://google.com/testing/video_something_else", 14),
201 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202};
203
isheriff6f8d6862016-05-26 11:24:55 -0700204static const RtpExtension kVideoRtpExtension3[] = {
205 RtpExtension("http://google.com/testing/video_something", 4),
206 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700207};
208
jbauch5869f502017-06-29 12:31:36 -0700209static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
210 RtpExtension("http://google.com/testing/video_something", 4),
211 // Use RTP extension that supports encryption.
212 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
213};
214
isheriff6f8d6862016-05-26 11:24:55 -0700215static const RtpExtension kVideoRtpExtensionAnswer[] = {
216 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000217};
218
jbauch5869f502017-06-29 12:31:36 -0700219static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
220 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
221};
222
Johannes Kronce8e8672019-02-22 13:06:44 +0100223static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
224 RtpExtension("http://www.ietf.org/id/"
225 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
226 1),
227};
228
229static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
230 RtpExtension("http://www.ietf.org/id/"
231 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
232 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100233 RtpExtension(
234 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
235 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100236};
237
238static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100239 RtpExtension(
240 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
241 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100242};
243
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100244static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
245 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
246 "generic-frame-descriptor-00",
247 3),
248};
249
Peter Boström0c4e06b2015-10-07 12:23:21 +0200250static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
251static const uint32_t kSimSsrc[] = {10, 20, 30};
252static const uint32_t kFec1Ssrc[] = {10, 11};
253static const uint32_t kFec2Ssrc[] = {20, 21};
254static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255
256static const char kMediaStream1[] = "stream_1";
257static const char kMediaStream2[] = "stream_2";
258static const char kVideoTrack1[] = "video_1";
259static const char kVideoTrack2[] = "video_2";
260static const char kAudioTrack1[] = "audio_1";
261static const char kAudioTrack2[] = "audio_2";
262static const char kAudioTrack3[] = "audio_3";
263static const char kDataTrack1[] = "data_1";
264static const char kDataTrack2[] = "data_2";
265static const char kDataTrack3[] = "data_3";
266
zhihuangcf5b37c2016-05-05 11:44:35 -0700267static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
268 "RTP/SAVPF"};
269static const char* kMediaProtocolsDtls[] = {
270 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
271 "UDP/TLS/RTP/SAVP"};
272
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700273// SRTP cipher name negotiated by the tests. This must be updated if the
274// default changes.
275static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
276static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
277
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800278// These constants are used to make the code using "AddMediaDescriptionOptions"
279// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700280static constexpr bool kStopped = true;
281static constexpr bool kActive = false;
282
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000283static bool IsMediaContentOfType(const ContentInfo* content,
284 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800285 RTC_DCHECK(content);
286 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000287}
288
Steve Anton4e70a722017-11-28 14:57:10 -0800289static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800290 RTC_DCHECK(content);
291 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000292}
293
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000294static void AddRtxCodec(const VideoCodec& rtx_codec,
295 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800296 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000297 codecs->push_back(rtx_codec);
298}
299
300template <class T>
301static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
302 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100303 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000304 for (const auto& codec : codecs) {
305 codec_names.push_back(codec.name);
306 }
307 return codec_names;
308}
309
zhihuang1c378ed2017-08-17 14:10:50 -0700310// This is used for test only. MIDs are not the identification of the
311// MediaDescriptionOptions since some end points may not support MID and the SDP
312// may not contain 'mid'.
313std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
314 const std::string& mid,
315 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800316 return absl::c_find_if(
317 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700318 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
319}
320
321std::vector<MediaDescriptionOptions>::const_iterator
322FindFirstMediaDescriptionByMid(const std::string& mid,
323 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800324 return absl::c_find_if(
325 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700326 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700327}
328
329// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800330static void AddMediaDescriptionOptions(MediaType type,
331 const std::string& mid,
332 RtpTransceiverDirection direction,
333 bool stopped,
334 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800335 opts->media_description_options.push_back(
336 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700337}
338
Steve Anton4e70a722017-11-28 14:57:10 -0800339static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700340 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800341 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
342 opts);
343 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
344 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700345}
346
347static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800348 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700349 MediaSessionOptions* opts) {
350 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800351 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700352}
353
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800354static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700355 const std::string& mid,
356 MediaType type,
357 const std::string& track_id,
358 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800359 const std::vector<RidDescription>& rids,
360 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700361 int num_sim_layer,
362 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700363 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
364 switch (type) {
365 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700366 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700367 break;
368 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800369 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
370 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700371 break;
372 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700373 RTC_CHECK(stream_ids.size() == 1U);
374 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700375 break;
376 default:
377 RTC_NOTREACHED();
378 }
379}
380
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800381static void AttachSenderToMediaDescriptionOptions(
382 const std::string& mid,
383 MediaType type,
384 const std::string& track_id,
385 const std::vector<std::string>& stream_ids,
386 int num_sim_layer,
387 MediaSessionOptions* session_options) {
388 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
389 SimulcastLayerList(), num_sim_layer,
390 session_options);
391}
392
zhihuang1c378ed2017-08-17 14:10:50 -0700393static void DetachSenderFromMediaSection(const std::string& mid,
394 const std::string& track_id,
395 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700396 std::vector<cricket::SenderOptions>& sender_options_list =
397 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
398 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800399 absl::c_find_if(sender_options_list,
400 [track_id](const cricket::SenderOptions& sender_options) {
401 return sender_options.track_id == track_id;
402 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700403 RTC_DCHECK(sender_it != sender_options_list.end());
404 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700405}
406
407// Helper function used to create a default MediaSessionOptions for Plan B SDP.
408// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
409static MediaSessionOptions CreatePlanBMediaSessionOptions() {
410 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800411 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
412 RtpTransceiverDirection::kRecvOnly, kActive,
413 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700414 return session_options;
415}
416
Philipp Hancke1aec2bf2020-05-12 10:11:27 +0200417// prefers GCM SDES crypto suites by removing non-GCM defaults.
418void PreferGcmCryptoParameters(CryptoParamsVec* cryptos) {
419 cryptos->erase(
420 std::remove_if(cryptos->begin(), cryptos->end(),
421 [](const cricket::CryptoParams& crypto) {
422 return crypto.cipher_suite != CS_AEAD_AES_256_GCM &&
423 crypto.cipher_suite != CS_AEAD_AES_128_GCM;
424 }),
425 cryptos->end());
426}
427
zhihuang1c378ed2017-08-17 14:10:50 -0700428// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
429// was designed for Plan B SDP, where only one audio "m=" section and one video
430// "m=" section could be generated, and ordering couldn't be controlled. Many of
431// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200432class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000433 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800434 MediaSessionDescriptionFactoryTest()
435 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700436 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
437 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200438 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
439 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200440 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700441 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
442 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200443 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
444 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200445 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200446 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700447 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200448 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700449 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 }
451
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000452 // Create a video StreamParamsVec object with:
453 // - one video stream with 3 simulcast streams and FEC,
454 StreamParamsVec CreateComplexVideoStreamParamsVec() {
455 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
456 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
457 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
458 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
459
460 std::vector<SsrcGroup> ssrc_groups;
461 ssrc_groups.push_back(sim_group);
462 ssrc_groups.push_back(fec_group1);
463 ssrc_groups.push_back(fec_group2);
464 ssrc_groups.push_back(fec_group3);
465
466 StreamParams simulcast_params;
467 simulcast_params.id = kVideoTrack1;
468 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
469 simulcast_params.ssrc_groups = ssrc_groups;
470 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800471 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000472
473 StreamParamsVec video_streams;
474 video_streams.push_back(simulcast_params);
475
476 return video_streams;
477 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000478
479 bool CompareCryptoParams(const CryptoParamsVec& c1,
480 const CryptoParamsVec& c2) {
481 if (c1.size() != c2.size())
482 return false;
483 for (size_t i = 0; i < c1.size(); ++i)
484 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
485 c1[i].key_params != c2[i].key_params ||
486 c1[i].session_params != c2[i].session_params)
487 return false;
488 return true;
489 }
490
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700491 // Returns true if the transport info contains "renomination" as an
492 // ICE option.
493 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800494 return absl::c_linear_search(transport_info->description.transport_options,
495 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700496 }
497
zhihuang1c378ed2017-08-17 14:10:50 -0700498 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700499 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 bool has_current_desc) {
501 const std::string current_audio_ufrag = "current_audio_ufrag";
502 const std::string current_audio_pwd = "current_audio_pwd";
503 const std::string current_video_ufrag = "current_video_ufrag";
504 const std::string current_video_pwd = "current_video_pwd";
505 const std::string current_data_ufrag = "current_data_ufrag";
506 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800507 std::unique_ptr<SessionDescription> current_desc;
508 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200510 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800511 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200512 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800513 TransportDescription(current_audio_ufrag, current_audio_pwd)));
514 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200515 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800516 TransportDescription(current_video_ufrag, current_video_pwd)));
517 current_desc->AddTransportInfo(TransportInfo(
518 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 }
520 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800521 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522 } else {
kwiberg31022942016-03-11 14:18:21 -0800523 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800524 offer = f1_.CreateOffer(options, NULL);
525 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 }
527 ASSERT_TRUE(desc.get() != NULL);
528 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000529 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 EXPECT_TRUE(ti_audio != NULL);
531 if (has_current_desc) {
532 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
533 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
534 } else {
535 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
536 ti_audio->description.ice_ufrag.size());
537 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
538 ti_audio->description.ice_pwd.size());
539 }
zhihuang1c378ed2017-08-17 14:10:50 -0700540 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700541 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700542 EXPECT_EQ(
543 media_desc_options_it->transport_options.enable_ice_renomination,
544 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 } else {
546 EXPECT_TRUE(ti_audio == NULL);
547 }
548 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000549 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700551 auto media_desc_options_it =
552 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 if (options.bundle_enabled) {
554 EXPECT_EQ(ti_audio->description.ice_ufrag,
555 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200556 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 } else {
558 if (has_current_desc) {
559 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
560 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
561 } else {
562 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
563 ti_video->description.ice_ufrag.size());
564 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
565 ti_video->description.ice_pwd.size());
566 }
567 }
zhihuang1c378ed2017-08-17 14:10:50 -0700568 EXPECT_EQ(
569 media_desc_options_it->transport_options.enable_ice_renomination,
570 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 } else {
572 EXPECT_TRUE(ti_video == NULL);
573 }
574 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
575 if (options.has_data()) {
576 EXPECT_TRUE(ti_data != NULL);
577 if (options.bundle_enabled) {
578 EXPECT_EQ(ti_audio->description.ice_ufrag,
579 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200580 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 } else {
582 if (has_current_desc) {
583 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
584 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
585 } else {
586 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
587 ti_data->description.ice_ufrag.size());
588 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
589 ti_data->description.ice_pwd.size());
590 }
591 }
zhihuang1c378ed2017-08-17 14:10:50 -0700592 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700593 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700594 EXPECT_EQ(
595 media_desc_options_it->transport_options.enable_ice_renomination,
596 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700597
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700599 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 }
601 }
602
603 void TestCryptoWithBundle(bool offer) {
604 f1_.set_secure(SEC_ENABLED);
605 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
607 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
608 &options);
kwiberg31022942016-03-11 14:18:21 -0800609 std::unique_ptr<SessionDescription> ref_desc;
610 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000611 if (offer) {
612 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800613 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800615 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 } else {
617 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800618 ref_desc = f1_.CreateOffer(options, NULL);
619 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800621 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800623 desc->GetContentDescriptionByName("audio");
624 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800626 desc->GetContentDescriptionByName("video");
627 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
629 video_media_desc->cryptos()));
630 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800631 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 audio_media_desc->cryptos()[0].cipher_suite);
633
634 // Verify the selected crypto is one from the reference audio
635 // media content.
636 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800637 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 bool found = false;
639 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
640 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200641 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 found = true;
643 break;
644 }
645 }
646 EXPECT_TRUE(found);
647 }
648
649 // This test that the audio and video media direction is set to
650 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700651 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800653 RtpTransceiverDirection direction_in_offer,
654 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700655 MediaSessionOptions offer_opts;
656 AddAudioVideoSections(direction_in_offer, &offer_opts);
657
Steve Anton6fe1fba2018-12-11 10:15:23 -0800658 std::unique_ptr<SessionDescription> offer =
659 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700661 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700663 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665
zhihuang1c378ed2017-08-17 14:10:50 -0700666 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800667 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800668 std::unique_ptr<SessionDescription> answer =
669 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 const AudioContentDescription* acd_answer =
671 GetFirstAudioContentDescription(answer.get());
672 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
673 const VideoContentDescription* vcd_answer =
674 GetFirstVideoContentDescription(answer.get());
675 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
676 }
677
678 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800679 RTC_DCHECK(content);
680 RTC_CHECK(content->media_description());
681 const cricket::AudioContentDescription* audio_desc =
682 content->media_description()->as_audio();
683 RTC_CHECK(audio_desc);
684 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
685 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800687 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688 }
689 return true;
690 }
691
jbauchcb560652016-08-04 05:20:32 -0700692 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
693 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800694 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700695 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700696
jbauchcb560652016-08-04 05:20:32 -0700697 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800698 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700699 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700700
jbauchcb560652016-08-04 05:20:32 -0700701 f1_.set_secure(SEC_ENABLED);
702 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800703 std::unique_ptr<SessionDescription> offer =
704 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700705 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +0200706 if (gcm_offer && gcm_answer) {
707 for (cricket::ContentInfo& content : offer->contents()) {
708 auto cryptos = content.media_description()->cryptos();
709 PreferGcmCryptoParameters(&cryptos);
710 content.media_description()->set_cryptos(cryptos);
711 }
712 }
Steve Anton6fe1fba2018-12-11 10:15:23 -0800713 std::unique_ptr<SessionDescription> answer =
714 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700715 const ContentInfo* ac = answer->GetContentByName("audio");
716 const ContentInfo* vc = answer->GetContentByName("video");
717 ASSERT_TRUE(ac != NULL);
718 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800719 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
720 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800721 const AudioContentDescription* acd = ac->media_description()->as_audio();
722 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700723 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800724 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700725 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700726 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700727 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
728 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700729 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700730 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700731 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700732 }
733 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800734 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200735 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
736 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700737 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700738 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700739 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700740 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700741 }
Steve Antone38a5a12018-11-21 16:05:15 -0800742 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700743 }
744
Johannes Kronce8e8672019-02-22 13:06:44 +0100745 void TestTransportSequenceNumberNegotiation(
746 const cricket::RtpHeaderExtensions& local,
747 const cricket::RtpHeaderExtensions& offered,
748 const cricket::RtpHeaderExtensions& expectedAnswer) {
749 MediaSessionOptions opts;
750 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +0200751 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100752 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
753 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +0200754 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100755 std::unique_ptr<SessionDescription> answer =
756 f2_.CreateAnswer(offer.get(), opts, NULL);
757
758 EXPECT_EQ(
759 expectedAnswer,
760 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
761 EXPECT_EQ(
762 expectedAnswer,
763 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
764 }
765
Markus Handell755c65d2020-06-24 01:06:10 +0200766 std::vector<webrtc::RtpHeaderExtensionCapability>
767 HeaderExtensionCapabilitiesFromRtpExtensions(
768 cricket::RtpHeaderExtensions extensions) {
769 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
770 for (const auto& extension : extensions) {
771 webrtc::RtpHeaderExtensionCapability capability(
772 extension.uri, extension.id,
773 webrtc::RtpTransceiverDirection::kSendRecv);
774 capabilities.push_back(capability);
775 }
776 return capabilities;
777 }
778
779 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
780 cricket::RtpHeaderExtensions video_exts,
781 MediaSessionOptions* opts) {
782 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
783 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
784 for (auto& entry : opts->media_description_options) {
785 switch (entry.type) {
786 case MEDIA_TYPE_AUDIO:
787 entry.header_extensions = audio_caps;
788 break;
789 case MEDIA_TYPE_VIDEO:
790 entry.header_extensions = video_caps;
791 break;
792 default:
793 break;
794 }
795 }
796 }
797
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800799 UniqueRandomIdGenerator ssrc_generator1;
800 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 MediaSessionDescriptionFactory f1_;
802 MediaSessionDescriptionFactory f2_;
803 TransportDescriptionFactory tdf1_;
804 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805};
806
807// Create a typical audio offer, and ensure it matches what we expect.
808TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
809 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800810 std::unique_ptr<SessionDescription> offer =
811 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812 ASSERT_TRUE(offer.get() != NULL);
813 const ContentInfo* ac = offer->GetContentByName("audio");
814 const ContentInfo* vc = offer->GetContentByName("video");
815 ASSERT_TRUE(ac != NULL);
816 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800817 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800818 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700820 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700821 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
823 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700824 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800825 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826}
827
828// Create a typical video offer, and ensure it matches what we expect.
829TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
830 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800831 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800833 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 ASSERT_TRUE(offer.get() != NULL);
835 const ContentInfo* ac = offer->GetContentByName("audio");
836 const ContentInfo* vc = offer->GetContentByName("video");
837 ASSERT_TRUE(ac != NULL);
838 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800839 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
840 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800841 const AudioContentDescription* acd = ac->media_description()->as_audio();
842 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700844 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700845 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
847 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700848 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800849 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200851 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700852 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
854 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700855 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800856 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857}
858
859// Test creating an offer with bundle where the Codecs have the same dynamic
860// RTP playlod type. The test verifies that the offer don't contain the
861// duplicate RTP payload types.
862TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200863 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700864 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200865 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
867 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
868
869 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800870 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
871 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800873 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874 const VideoContentDescription* vcd =
875 GetFirstVideoContentDescription(offer.get());
876 const AudioContentDescription* acd =
877 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200878 const RtpDataContentDescription* dcd =
879 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 ASSERT_TRUE(NULL != vcd);
881 ASSERT_TRUE(NULL != acd);
882 ASSERT_TRUE(NULL != dcd);
883 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
884 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
885 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
886 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
887 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
888 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
889}
890
zhihuang1c378ed2017-08-17 14:10:50 -0700891// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892// after an audio only session has been negotiated.
893TEST_F(MediaSessionDescriptionFactoryTest,
894 TestCreateUpdatedVideoOfferWithBundle) {
895 f1_.set_secure(SEC_ENABLED);
896 f2_.set_secure(SEC_ENABLED);
897 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800898 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
899 RtpTransceiverDirection::kRecvOnly, kActive,
900 &opts);
901 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
902 RtpTransceiverDirection::kInactive, kStopped,
903 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904 opts.data_channel_type = cricket::DCT_NONE;
905 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800906 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
907 std::unique_ptr<SessionDescription> answer =
908 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909
910 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800911 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
912 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
913 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800915 std::unique_ptr<SessionDescription> updated_offer(
916 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000917
918 const AudioContentDescription* acd =
919 GetFirstAudioContentDescription(updated_offer.get());
920 const VideoContentDescription* vcd =
921 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200922 const RtpDataContentDescription* dcd =
923 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000924 EXPECT_TRUE(NULL != vcd);
925 EXPECT_TRUE(NULL != acd);
926 EXPECT_TRUE(NULL != dcd);
927
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700928 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800929 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700930 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800931 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700932 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800933 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000934}
deadbeef44f08192015-12-15 16:20:09 -0800935
wu@webrtc.org78187522013-10-07 23:32:02 +0000936// Create a RTP data offer, and ensure it matches what we expect.
937TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000938 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800939 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
940 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000941 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800942 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000943 ASSERT_TRUE(offer.get() != NULL);
944 const ContentInfo* ac = offer->GetContentByName("audio");
945 const ContentInfo* dc = offer->GetContentByName("data");
946 ASSERT_TRUE(ac != NULL);
947 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800948 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
949 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800950 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200951 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700953 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700954 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000955 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
956 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700957 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800958 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000959 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200960 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700961 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
Philipp Hanckeafee7082020-10-22 11:55:58 +0200962 EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200963 dcd->bandwidth()); // default bandwidth (auto)
964 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700965 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800966 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000967}
968
wu@webrtc.org78187522013-10-07 23:32:02 +0000969// Create an SCTP data offer with bundle without error.
970TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
971 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000972 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800973 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000974 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800975 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000976 EXPECT_TRUE(offer.get() != NULL);
977 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000978 auto dcd = GetFirstSctpDataContentDescription(offer.get());
979 ASSERT_TRUE(dcd);
980 // Since this transport is insecure, the protocol should be "SCTP".
981 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
982}
983
984// Create an SCTP data offer with bundle without error.
985TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
986 MediaSessionOptions opts;
987 opts.bundle_enabled = true;
988 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
989 f1_.set_secure(SEC_ENABLED);
990 tdf1_.set_secure(SEC_ENABLED);
991 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
992 EXPECT_TRUE(offer.get() != NULL);
993 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
994 auto dcd = GetFirstSctpDataContentDescription(offer.get());
995 ASSERT_TRUE(dcd);
996 // The protocol should now be "UDP/DTLS/SCTP"
997 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000998}
999
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001000// Test creating an sctp data channel from an already generated offer.
1001TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
1002 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001003 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -08001004 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001005 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001006 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001007 ASSERT_TRUE(offer1.get() != NULL);
1008 const ContentInfo* data = offer1->GetContentByName("data");
1009 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001010 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001011
1012 // Now set data_channel_type to 'none' (default) and make sure that the
1013 // datachannel type that gets generated from the previous offer, is of the
1014 // same type.
1015 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -08001016 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001017 f1_.CreateOffer(opts, offer1.get()));
1018 data = offer2->GetContentByName("data");
1019 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001020 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001021}
1022
Steve Anton2bed3972019-01-04 17:04:30 -08001023// Test that if BUNDLE is enabled and all media sections are rejected then the
1024// BUNDLE group is not present in the re-offer.
1025TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
1026 MediaSessionOptions opts;
1027 opts.bundle_enabled = true;
1028 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1029 RtpTransceiverDirection::kSendRecv, kActive,
1030 &opts);
1031 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1032
1033 opts.media_description_options[0].stopped = true;
1034 std::unique_ptr<SessionDescription> reoffer =
1035 f1_.CreateOffer(opts, offer.get());
1036
1037 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1038}
1039
1040// Test that if BUNDLE is enabled and the remote re-offer does not include a
1041// BUNDLE group since all media sections are rejected, then the re-answer also
1042// does not include a BUNDLE group.
1043TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
1044 MediaSessionOptions opts;
1045 opts.bundle_enabled = true;
1046 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1047 RtpTransceiverDirection::kSendRecv, kActive,
1048 &opts);
1049 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1050 std::unique_ptr<SessionDescription> answer =
1051 f2_.CreateAnswer(offer.get(), opts, nullptr);
1052
1053 opts.media_description_options[0].stopped = true;
1054 std::unique_ptr<SessionDescription> reoffer =
1055 f1_.CreateOffer(opts, offer.get());
1056 std::unique_ptr<SessionDescription> reanswer =
1057 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1058
1059 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1060}
1061
1062// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1063// was rejected then the new offerer-tagged media section is the non-rejected
1064// media section.
1065TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1066 MediaSessionOptions opts;
1067 opts.bundle_enabled = true;
1068 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1069 RtpTransceiverDirection::kSendRecv, kActive,
1070 &opts);
1071 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1072
1073 // Reject the audio m= section and add a video m= section.
1074 opts.media_description_options[0].stopped = true;
1075 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1076 RtpTransceiverDirection::kSendRecv, kActive,
1077 &opts);
1078 std::unique_ptr<SessionDescription> reoffer =
1079 f1_.CreateOffer(opts, offer.get());
1080
1081 const cricket::ContentGroup* bundle_group =
1082 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1083 ASSERT_TRUE(bundle_group);
1084 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1085 EXPECT_TRUE(bundle_group->HasContentName("video"));
1086}
1087
1088// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1089// was rejected and a new media section is added, then the re-answer BUNDLE
1090// group will contain only the non-rejected media section.
1091TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1092 MediaSessionOptions opts;
1093 opts.bundle_enabled = true;
1094 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1095 RtpTransceiverDirection::kSendRecv, kActive,
1096 &opts);
1097 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1098 std::unique_ptr<SessionDescription> answer =
1099 f2_.CreateAnswer(offer.get(), opts, nullptr);
1100
1101 // Reject the audio m= section and add a video m= section.
1102 opts.media_description_options[0].stopped = true;
1103 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1104 RtpTransceiverDirection::kSendRecv, kActive,
1105 &opts);
1106 std::unique_ptr<SessionDescription> reoffer =
1107 f1_.CreateOffer(opts, offer.get());
1108 std::unique_ptr<SessionDescription> reanswer =
1109 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1110
1111 const cricket::ContentGroup* bundle_group =
1112 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1113 ASSERT_TRUE(bundle_group);
1114 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1115 EXPECT_TRUE(bundle_group->HasContentName("video"));
1116}
1117
1118// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1119// and there is still a non-rejected media section that was in the initial
1120// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1121// media section.
1122TEST_F(MediaSessionDescriptionFactoryTest,
1123 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1124 MediaSessionOptions opts;
1125 opts.bundle_enabled = true;
1126 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1127 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1128 std::unique_ptr<SessionDescription> answer =
1129 f2_.CreateAnswer(offer.get(), opts, nullptr);
1130
1131 // Reject the audio m= section.
1132 opts.media_description_options[0].stopped = true;
1133 std::unique_ptr<SessionDescription> reoffer =
1134 f1_.CreateOffer(opts, offer.get());
1135
1136 const TransportDescription* offer_tagged =
1137 offer->GetTransportDescriptionByName("audio");
1138 ASSERT_TRUE(offer_tagged);
1139 const TransportDescription* reoffer_tagged =
1140 reoffer->GetTransportDescriptionByName("video");
1141 ASSERT_TRUE(reoffer_tagged);
1142 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1143 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1144}
1145
1146// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1147// and there is still a non-rejected media section that was in the initial
1148// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1149// media section.
1150TEST_F(MediaSessionDescriptionFactoryTest,
1151 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1152 MediaSessionOptions opts;
1153 opts.bundle_enabled = true;
1154 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1155 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1156 std::unique_ptr<SessionDescription> answer =
1157 f2_.CreateAnswer(offer.get(), opts, nullptr);
1158
1159 // Reject the audio m= section.
1160 opts.media_description_options[0].stopped = true;
1161 std::unique_ptr<SessionDescription> reoffer =
1162 f1_.CreateOffer(opts, offer.get());
1163 std::unique_ptr<SessionDescription> reanswer =
1164 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1165
1166 const TransportDescription* answer_tagged =
1167 answer->GetTransportDescriptionByName("audio");
1168 ASSERT_TRUE(answer_tagged);
1169 const TransportDescription* reanswer_tagged =
1170 reanswer->GetTransportDescriptionByName("video");
1171 ASSERT_TRUE(reanswer_tagged);
1172 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1173 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1174}
1175
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001176// Create an audio, video offer without legacy StreamParams.
1177TEST_F(MediaSessionDescriptionFactoryTest,
1178 TestCreateOfferWithoutLegacyStreams) {
1179 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001180 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001181 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001182 ASSERT_TRUE(offer.get() != NULL);
1183 const ContentInfo* ac = offer->GetContentByName("audio");
1184 const ContentInfo* vc = offer->GetContentByName("video");
1185 ASSERT_TRUE(ac != NULL);
1186 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001187 const AudioContentDescription* acd = ac->media_description()->as_audio();
1188 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189
Yves Gerey665174f2018-06-19 15:03:05 +02001190 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1191 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001192}
1193
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001194// Creates an audio+video sendonly offer.
1195TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001196 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001197 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001198 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1199 {kMediaStream1}, 1, &opts);
1200 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1201 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001202
Steve Anton6fe1fba2018-12-11 10:15:23 -08001203 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001204 ASSERT_TRUE(offer.get() != NULL);
1205 EXPECT_EQ(2u, offer->contents().size());
1206 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1207 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1208
Steve Anton4e70a722017-11-28 14:57:10 -08001209 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1210 GetMediaDirection(&offer->contents()[0]));
1211 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1212 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001213}
1214
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001215// Verifies that the order of the media contents in the current
1216// SessionDescription is preserved in the new SessionDescription.
1217TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1218 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001219 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001220
kwiberg31022942016-03-11 14:18:21 -08001221 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001222 ASSERT_TRUE(offer1.get() != NULL);
1223 EXPECT_EQ(1u, offer1->contents().size());
1224 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1225
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001226 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1227 RtpTransceiverDirection::kRecvOnly, kActive,
1228 &opts);
kwiberg31022942016-03-11 14:18:21 -08001229 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001230 f1_.CreateOffer(opts, offer1.get()));
1231 ASSERT_TRUE(offer2.get() != NULL);
1232 EXPECT_EQ(2u, offer2->contents().size());
1233 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1234 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1235
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001236 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1237 RtpTransceiverDirection::kRecvOnly, kActive,
1238 &opts);
kwiberg31022942016-03-11 14:18:21 -08001239 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001240 f1_.CreateOffer(opts, offer2.get()));
1241 ASSERT_TRUE(offer3.get() != NULL);
1242 EXPECT_EQ(3u, offer3->contents().size());
1243 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1244 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1245 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001246}
1247
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248// Create a typical audio answer, and ensure it matches what we expect.
1249TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1250 f1_.set_secure(SEC_ENABLED);
1251 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001252 std::unique_ptr<SessionDescription> offer =
1253 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001255 std::unique_ptr<SessionDescription> answer =
1256 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257 const ContentInfo* ac = answer->GetContentByName("audio");
1258 const ContentInfo* vc = answer->GetContentByName("video");
1259 ASSERT_TRUE(ac != NULL);
1260 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001261 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001262 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001264 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001265 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1267 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001268 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001269 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270}
1271
jbauchcb560652016-08-04 05:20:32 -07001272// Create a typical audio answer with GCM ciphers enabled, and ensure it
1273// matches what we expect.
1274TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1275 f1_.set_secure(SEC_ENABLED);
1276 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001277 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001278 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001279 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001280 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +02001281 for (cricket::ContentInfo& content : offer->contents()) {
1282 auto cryptos = content.media_description()->cryptos();
1283 PreferGcmCryptoParameters(&cryptos);
1284 content.media_description()->set_cryptos(cryptos);
1285 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08001286 std::unique_ptr<SessionDescription> answer =
1287 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001288 const ContentInfo* ac = answer->GetContentByName("audio");
1289 const ContentInfo* vc = answer->GetContentByName("video");
1290 ASSERT_TRUE(ac != NULL);
1291 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001292 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001293 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001294 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001295 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001296 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001297 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1298 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001299 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001300 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001301}
1302
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303// Create a typical video answer, and ensure it matches what we expect.
1304TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1305 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001306 AddAudioVideoSections(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");
1314 const ContentInfo* vc = answer->GetContentByName("video");
1315 ASSERT_TRUE(ac != NULL);
1316 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001317 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1318 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001319 const AudioContentDescription* acd = ac->media_description()->as_audio();
1320 const VideoContentDescription* vcd = vc->media_description()->as_video();
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);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001327 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001328 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001329 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1330 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001331 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001332 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333}
1334
jbauchcb560652016-08-04 05:20:32 -07001335// Create a typical video answer with GCM ciphers enabled, and ensure it
1336// matches what we expect.
1337TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1338 TestVideoGcmCipher(true, true);
1339}
1340
1341// Create a typical video answer with GCM ciphers enabled for the offer only,
1342// and ensure it matches what we expect.
1343TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1344 TestVideoGcmCipher(true, false);
1345}
1346
1347// Create a typical video answer with GCM ciphers enabled for the answer only,
1348// and ensure it matches what we expect.
1349TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1350 TestVideoGcmCipher(false, true);
1351}
1352
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001353TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001354 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001355 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001356 f1_.set_secure(SEC_ENABLED);
1357 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001358 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001359 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001360 std::unique_ptr<SessionDescription> answer =
1361 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001362 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001363 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001364 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001365 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001366 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1367 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001368 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001369 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001370 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001371 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001372 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001373 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001374 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001375 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001376 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001377 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001378 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001379 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001380 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001381 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001382}
1383
jbauchcb560652016-08-04 05:20:32 -07001384TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001385 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001386 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001387 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001388 f1_.set_secure(SEC_ENABLED);
1389 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001390 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001391 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +02001392 for (cricket::ContentInfo& content : offer->contents()) {
1393 auto cryptos = content.media_description()->cryptos();
1394 PreferGcmCryptoParameters(&cryptos);
1395 content.media_description()->set_cryptos(cryptos);
1396 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08001397 std::unique_ptr<SessionDescription> answer =
1398 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001399 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001400 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001401 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001402 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001403 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1404 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001405 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001406 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001407 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001408 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001409 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001410 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001411 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001412 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001413 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001414 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001415 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001416 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001417 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001418 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001419}
1420
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001421// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1422// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001423TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1424 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001425 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001426 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001427 ASSERT_TRUE(offer.get() != NULL);
1428 ContentInfo* dc_offer = offer->GetContentByName("data");
1429 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001430 SctpDataContentDescription* dcd_offer =
1431 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001432 EXPECT_TRUE(dcd_offer->use_sctpmap());
1433
Steve Anton6fe1fba2018-12-11 10:15:23 -08001434 std::unique_ptr<SessionDescription> answer =
1435 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001436 const ContentInfo* dc_answer = answer->GetContentByName("data");
1437 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001438 const SctpDataContentDescription* dcd_answer =
1439 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001440 EXPECT_TRUE(dcd_answer->use_sctpmap());
1441}
1442
1443// The answer's use_sctpmap flag should match the offer's.
1444TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1445 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001446 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001447 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001448 ASSERT_TRUE(offer.get() != NULL);
1449 ContentInfo* dc_offer = offer->GetContentByName("data");
1450 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001451 SctpDataContentDescription* dcd_offer =
1452 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001453 dcd_offer->set_use_sctpmap(false);
1454
Steve Anton6fe1fba2018-12-11 10:15:23 -08001455 std::unique_ptr<SessionDescription> answer =
1456 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001457 const ContentInfo* dc_answer = answer->GetContentByName("data");
1458 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001459 const SctpDataContentDescription* dcd_answer =
1460 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001461 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001462}
1463
deadbeef8b7e9ad2017-05-25 09:38:55 -07001464// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1465// and "TCP/DTLS/SCTP" offers.
1466TEST_F(MediaSessionDescriptionFactoryTest,
1467 TestCreateDataAnswerToDifferentOfferedProtos) {
1468 // Need to enable DTLS offer/answer generation (disabled by default in this
1469 // test).
1470 f1_.set_secure(SEC_ENABLED);
1471 f2_.set_secure(SEC_ENABLED);
1472 tdf1_.set_secure(SEC_ENABLED);
1473 tdf2_.set_secure(SEC_ENABLED);
1474
1475 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001476 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001477 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001478 ASSERT_TRUE(offer.get() != nullptr);
1479 ContentInfo* dc_offer = offer->GetContentByName("data");
1480 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001481 SctpDataContentDescription* dcd_offer =
1482 dc_offer->media_description()->as_sctp();
1483 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001484
1485 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1486 "TCP/DTLS/SCTP"};
1487 for (const std::string& proto : protos) {
1488 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001489 std::unique_ptr<SessionDescription> answer =
1490 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001491 const ContentInfo* dc_answer = answer->GetContentByName("data");
1492 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001493 const SctpDataContentDescription* dcd_answer =
1494 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001495 EXPECT_FALSE(dc_answer->rejected);
1496 EXPECT_EQ(proto, dcd_answer->protocol());
1497 }
1498}
1499
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001500TEST_F(MediaSessionDescriptionFactoryTest,
1501 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1502 // Need to enable DTLS offer/answer generation (disabled by default in this
1503 // test).
1504 f1_.set_secure(SEC_ENABLED);
1505 f2_.set_secure(SEC_ENABLED);
1506 tdf1_.set_secure(SEC_ENABLED);
1507 tdf2_.set_secure(SEC_ENABLED);
1508
1509 MediaSessionOptions opts;
1510 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1511 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1512 ASSERT_TRUE(offer.get() != nullptr);
1513 ContentInfo* dc_offer = offer->GetContentByName("data");
1514 ASSERT_TRUE(dc_offer != nullptr);
1515 SctpDataContentDescription* dcd_offer =
1516 dc_offer->media_description()->as_sctp();
1517 ASSERT_TRUE(dcd_offer);
1518 dcd_offer->set_max_message_size(1234);
1519 std::unique_ptr<SessionDescription> answer =
1520 f2_.CreateAnswer(offer.get(), opts, nullptr);
1521 const ContentInfo* dc_answer = answer->GetContentByName("data");
1522 ASSERT_TRUE(dc_answer != nullptr);
1523 const SctpDataContentDescription* dcd_answer =
1524 dc_answer->media_description()->as_sctp();
1525 EXPECT_FALSE(dc_answer->rejected);
1526 EXPECT_EQ(1234, dcd_answer->max_message_size());
1527}
1528
1529TEST_F(MediaSessionDescriptionFactoryTest,
1530 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1531 // Need to enable DTLS offer/answer generation (disabled by default in this
1532 // test).
1533 f1_.set_secure(SEC_ENABLED);
1534 f2_.set_secure(SEC_ENABLED);
1535 tdf1_.set_secure(SEC_ENABLED);
1536 tdf2_.set_secure(SEC_ENABLED);
1537
1538 MediaSessionOptions opts;
1539 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1540 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1541 ASSERT_TRUE(offer.get() != nullptr);
1542 ContentInfo* dc_offer = offer->GetContentByName("data");
1543 ASSERT_TRUE(dc_offer != nullptr);
1544 SctpDataContentDescription* dcd_offer =
1545 dc_offer->media_description()->as_sctp();
1546 ASSERT_TRUE(dcd_offer);
1547 dcd_offer->set_max_message_size(0);
1548 std::unique_ptr<SessionDescription> answer =
1549 f2_.CreateAnswer(offer.get(), opts, nullptr);
1550 const ContentInfo* dc_answer = answer->GetContentByName("data");
1551 ASSERT_TRUE(dc_answer != nullptr);
1552 const SctpDataContentDescription* dcd_answer =
1553 dc_answer->media_description()->as_sctp();
1554 EXPECT_FALSE(dc_answer->rejected);
1555 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1556}
1557
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001558// Verifies that the order of the media contents in the offer is preserved in
1559// the answer.
1560TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1561 MediaSessionOptions opts;
1562
1563 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001564 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001565 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001566 ASSERT_TRUE(offer1.get() != NULL);
1567
1568 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001569 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1570 RtpTransceiverDirection::kRecvOnly, kActive,
1571 &opts);
kwiberg31022942016-03-11 14:18:21 -08001572 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001573 f1_.CreateOffer(opts, offer1.get()));
1574 ASSERT_TRUE(offer2.get() != NULL);
1575
1576 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001577 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1578 RtpTransceiverDirection::kRecvOnly, kActive,
1579 &opts);
kwiberg31022942016-03-11 14:18:21 -08001580 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001581 f1_.CreateOffer(opts, offer2.get()));
1582 ASSERT_TRUE(offer3.get() != NULL);
1583
Steve Anton6fe1fba2018-12-11 10:15:23 -08001584 std::unique_ptr<SessionDescription> answer =
1585 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001586 ASSERT_TRUE(answer.get() != NULL);
1587 EXPECT_EQ(3u, answer->contents().size());
1588 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1589 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1590 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1591}
1592
ossu075af922016-06-14 03:29:38 -07001593// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1594// answerer settings.
1595
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001596// This test that the media direction is set to send/receive in an answer if
1597// the offer is send receive.
1598TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001599 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1600 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001601}
1602
1603// This test that the media direction is set to receive only in an answer if
1604// the offer is send only.
1605TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001606 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1607 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001608}
1609
1610// This test that the media direction is set to send only in an answer if
1611// the offer is recv only.
1612TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001613 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1614 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001615}
1616
1617// This test that the media direction is set to inactive in an answer if
1618// the offer is inactive.
1619TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001620 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1621 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622}
1623
1624// Test that a data content with an unknown protocol is rejected in an answer.
1625TEST_F(MediaSessionDescriptionFactoryTest,
1626 CreateDataAnswerToOfferWithUnknownProtocol) {
1627 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001628 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001629 f1_.set_secure(SEC_ENABLED);
1630 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001631 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001632 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001634 RtpDataContentDescription* dcd_offer =
1635 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001636 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001637 // Offer must be acceptable as an RTP protocol in order to be set.
1638 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639 dcd_offer->set_protocol(protocol);
1640
Steve Anton6fe1fba2018-12-11 10:15:23 -08001641 std::unique_ptr<SessionDescription> answer =
1642 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001643
1644 const ContentInfo* dc_answer = answer->GetContentByName("data");
1645 ASSERT_TRUE(dc_answer != NULL);
1646 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001647 const RtpDataContentDescription* dcd_answer =
1648 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001649 ASSERT_TRUE(dcd_answer != NULL);
1650 EXPECT_EQ(protocol, dcd_answer->protocol());
1651}
1652
1653// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1654TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001655 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001656 f1_.set_secure(SEC_DISABLED);
1657 f2_.set_secure(SEC_DISABLED);
1658 tdf1_.set_secure(SEC_DISABLED);
1659 tdf2_.set_secure(SEC_DISABLED);
1660
Steve Anton6fe1fba2018-12-11 10:15:23 -08001661 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001662 const AudioContentDescription* offer_acd =
1663 GetFirstAudioContentDescription(offer.get());
1664 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001665 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001666
Steve Anton6fe1fba2018-12-11 10:15:23 -08001667 std::unique_ptr<SessionDescription> answer =
1668 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001669
1670 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1671 ASSERT_TRUE(ac_answer != NULL);
1672 EXPECT_FALSE(ac_answer->rejected);
1673
1674 const AudioContentDescription* answer_acd =
1675 GetFirstAudioContentDescription(answer.get());
1676 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001677 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001678}
1679
1680// Create a video offer and answer and ensure the RTP header extensions
1681// matches what we expect.
1682TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1683 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001684 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +02001685 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1686 MAKE_VECTOR(kVideoRtpExtension1), &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001687
Steve Anton6fe1fba2018-12-11 10:15:23 -08001688 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001689 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001690 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1691 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001692 std::unique_ptr<SessionDescription> answer =
1693 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001694
Yves Gerey665174f2018-06-19 15:03:05 +02001695 EXPECT_EQ(
1696 MAKE_VECTOR(kAudioRtpExtension1),
1697 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1698 EXPECT_EQ(
1699 MAKE_VECTOR(kVideoRtpExtension1),
1700 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1701 EXPECT_EQ(
1702 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1703 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1704 EXPECT_EQ(
1705 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1706 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001707}
1708
Johannes Kronce8e8672019-02-22 13:06:44 +01001709// Create a audio/video offer and answer and ensure that the
1710// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1711// supported and should take precedence even though not listed among locally
1712// supported extensions.
1713TEST_F(MediaSessionDescriptionFactoryTest,
1714 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1715 TestTransportSequenceNumberNegotiation(
1716 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1717 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1718 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1719}
1720TEST_F(MediaSessionDescriptionFactoryTest,
1721 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1722 TestTransportSequenceNumberNegotiation(
1723 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1724 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1725 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1726}
1727TEST_F(MediaSessionDescriptionFactoryTest,
1728 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1729 TestTransportSequenceNumberNegotiation(
1730 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1731 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1732 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1733}
1734
jbauch5869f502017-06-29 12:31:36 -07001735TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001736 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1737 MediaSessionOptions opts;
1738 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1739
Markus Handell755c65d2020-06-24 01:06:10 +02001740 SetAudioVideoRtpHeaderExtensions(
1741 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1742 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001743 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001744 SetAudioVideoRtpHeaderExtensions(
1745 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1746 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001747 std::unique_ptr<SessionDescription> answer =
1748 f2_.CreateAnswer(offer.get(), opts, nullptr);
1749 EXPECT_THAT(
1750 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001751 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001752 EXPECT_THAT(
1753 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001754 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001755}
1756
1757TEST_F(MediaSessionDescriptionFactoryTest,
1758 TestNegotiateFrameDescriptorWhenExposedLocally) {
1759 MediaSessionOptions opts;
1760 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1761
Markus Handell755c65d2020-06-24 01:06:10 +02001762 SetAudioVideoRtpHeaderExtensions(
1763 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1764 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001765 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1766 std::unique_ptr<SessionDescription> answer =
1767 f2_.CreateAnswer(offer.get(), opts, nullptr);
1768 EXPECT_THAT(
1769 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001770 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001771 EXPECT_THAT(
1772 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001773 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001774}
1775
1776TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001777 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1778 MediaSessionOptions opts;
1779 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1780
1781 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell755c65d2020-06-24 01:06:10 +02001782 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +00001783 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001784 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1785 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001786 std::unique_ptr<SessionDescription> answer =
1787 f2_.CreateAnswer(offer.get(), opts, nullptr);
1788 EXPECT_THAT(
1789 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1790 ElementsAre(offer_dd));
1791}
1792
1793TEST_F(MediaSessionDescriptionFactoryTest,
1794 NegotiateDependencyDescriptorWhenExposedLocally) {
1795 MediaSessionOptions opts;
1796 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1797
1798 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1799 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell755c65d2020-06-24 01:06:10 +02001800 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001801 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001802 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001803 std::unique_ptr<SessionDescription> answer =
1804 f2_.CreateAnswer(offer.get(), opts, nullptr);
1805 EXPECT_THAT(
1806 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1807 ElementsAre(offer_dd));
1808}
1809
1810TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001811 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1812 MediaSessionOptions opts;
1813 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1814
1815 const cricket::RtpHeaderExtensions offered_extensions = {
1816 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1817 const cricket::RtpHeaderExtensions local_extensions = {
1818 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001819 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1820 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001821 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001822 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001823 std::unique_ptr<SessionDescription> answer =
1824 f2_.CreateAnswer(offer.get(), opts, nullptr);
1825 EXPECT_THAT(
1826 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1827 ElementsAreArray(offered_extensions));
1828 EXPECT_THAT(
1829 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1830 ElementsAreArray(offered_extensions));
1831}
1832
1833TEST_F(MediaSessionDescriptionFactoryTest,
1834 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1835 MediaSessionOptions opts;
1836 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1837
1838 const cricket::RtpHeaderExtensions offered_extensions = {
1839 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1840 const cricket::RtpHeaderExtensions local_extensions = {
1841 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001842 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1843 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001844 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001845 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001846 std::unique_ptr<SessionDescription> answer =
1847 f2_.CreateAnswer(offer.get(), opts, nullptr);
1848 EXPECT_THAT(
1849 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1850 ElementsAreArray(offered_extensions));
1851 EXPECT_THAT(
1852 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1853 ElementsAreArray(offered_extensions));
1854}
1855
1856TEST_F(MediaSessionDescriptionFactoryTest,
1857 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1858 MediaSessionOptions opts;
1859 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1860
1861 const cricket::RtpHeaderExtensions offered_extensions = {
1862 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1863 const cricket::RtpHeaderExtensions local_extensions = {
1864 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001865 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1866 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001867 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001868 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001869 std::unique_ptr<SessionDescription> answer =
1870 f2_.CreateAnswer(offer.get(), opts, nullptr);
1871 EXPECT_THAT(
1872 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1873 IsEmpty());
1874 EXPECT_THAT(
1875 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1876 IsEmpty());
1877}
1878
1879TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handell755c65d2020-06-24 01:06:10 +02001880 OffersUnstoppedExtensionsWithAudioVideoExtensionStopped) {
1881 MediaSessionOptions opts;
1882 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1883 RtpTransceiverDirection::kSendRecv, kActive,
1884 &opts);
1885 opts.media_description_options.back().header_extensions = {
1886 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1887 RtpTransceiverDirection::kStopped),
1888 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1889 RtpTransceiverDirection::kSendOnly)};
1890 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1891 RtpTransceiverDirection::kSendRecv, kActive,
1892 &opts);
1893 opts.media_description_options.back().header_extensions = {
1894 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1895 RtpTransceiverDirection::kStopped),
1896 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1897 RtpTransceiverDirection::kSendOnly)};
1898 auto offer = f1_.CreateOffer(opts, nullptr);
1899 EXPECT_THAT(
1900 offer->contents(),
1901 ElementsAre(
1902 Property(&ContentInfo::media_description,
1903 Pointee(Property(
1904 &MediaContentDescription::rtp_header_extensions,
1905 ElementsAre(Field(&RtpExtension::uri, "uri2"))))),
1906 Property(&ContentInfo::media_description,
1907 Pointee(Property(
1908 &MediaContentDescription::rtp_header_extensions,
1909 ElementsAre(Field(&RtpExtension::uri, "uri3")))))));
1910}
1911
1912TEST_F(MediaSessionDescriptionFactoryTest,
1913 OffersUnstoppedExtensionsWithAudioExtensionStopped) {
1914 MediaSessionOptions opts;
1915 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1916 RtpTransceiverDirection::kSendRecv, kActive,
1917 &opts);
1918 opts.media_description_options.back().header_extensions = {
1919 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1920 RtpTransceiverDirection::kSendOnly),
1921 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1922 RtpTransceiverDirection::kStopped)};
1923 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1924 RtpTransceiverDirection::kSendRecv, kActive,
1925 &opts);
1926 opts.media_description_options.back().header_extensions = {
1927 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1928 RtpTransceiverDirection::kSendRecv),
1929 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1930 RtpTransceiverDirection::kSendOnly)};
1931 auto offer = f1_.CreateOffer(opts, nullptr);
1932 EXPECT_THAT(
1933 offer->contents(),
1934 ElementsAre(
1935 Property(&ContentInfo::media_description,
1936 Pointee(Property(
1937 &MediaContentDescription::rtp_header_extensions,
1938 ElementsAre(Field(&RtpExtension::uri, "uri1"))))),
1939 Property(
1940 &ContentInfo::media_description,
1941 Pointee(Property(
1942 &MediaContentDescription::rtp_header_extensions,
1943 UnorderedElementsAre(Field(&RtpExtension::uri, "uri3"),
1944 Field(&RtpExtension::uri, "uri42")))))));
1945}
1946
1947TEST_F(MediaSessionDescriptionFactoryTest,
1948 OffersUnstoppedExtensionsWithVideoExtensionStopped) {
1949 MediaSessionOptions opts;
1950 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1951 RtpTransceiverDirection::kSendRecv, kActive,
1952 &opts);
1953 opts.media_description_options.back().header_extensions = {
1954 webrtc::RtpHeaderExtensionCapability("uri1", 5,
1955 RtpTransceiverDirection::kSendOnly),
1956 webrtc::RtpHeaderExtensionCapability("uri2", 7,
1957 RtpTransceiverDirection::kSendRecv)};
1958 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1959 RtpTransceiverDirection::kSendRecv, kActive,
1960 &opts);
1961 opts.media_description_options.back().header_extensions = {
1962 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1963 RtpTransceiverDirection::kSendRecv),
1964 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1965 RtpTransceiverDirection::kStopped)};
1966 auto offer = f1_.CreateOffer(opts, nullptr);
1967 EXPECT_THAT(
1968 offer->contents(),
1969 ElementsAre(
1970 Property(
1971 &ContentInfo::media_description,
1972 Pointee(Property(
1973 &MediaContentDescription::rtp_header_extensions,
1974 UnorderedElementsAre(Field(&RtpExtension::uri, "uri1"),
1975 Field(&RtpExtension::uri, "uri2"))))),
1976 Property(&ContentInfo::media_description,
1977 Pointee(Property(
1978 &MediaContentDescription::rtp_header_extensions,
1979 ElementsAre(Field(&RtpExtension::uri, "uri42")))))));
1980}
1981
1982TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1983 MediaSessionOptions opts;
1984 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1985 RtpTransceiverDirection::kSendRecv, kActive,
1986 &opts);
1987 opts.media_description_options.back().header_extensions = {
1988 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1989 RtpTransceiverDirection::kStopped),
1990 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1991 RtpTransceiverDirection::kSendOnly),
1992 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1993 RtpTransceiverDirection::kRecvOnly),
1994 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1995 RtpTransceiverDirection::kSendRecv)};
1996 auto offer = f1_.CreateOffer(opts, nullptr);
1997 opts.media_description_options.back().header_extensions = {
1998 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1999 RtpTransceiverDirection::kSendOnly),
2000 webrtc::RtpHeaderExtensionCapability("uri2", 3,
2001 RtpTransceiverDirection::kRecvOnly),
2002 webrtc::RtpHeaderExtensionCapability("uri3", 2,
2003 RtpTransceiverDirection::kStopped),
2004 webrtc::RtpHeaderExtensionCapability("uri4", 1,
2005 RtpTransceiverDirection::kSendRecv)};
2006 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
2007 EXPECT_THAT(
2008 answer->contents(),
2009 ElementsAre(Property(
2010 &ContentInfo::media_description,
2011 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2012 ElementsAre(Field(&RtpExtension::uri, "uri2"),
2013 Field(&RtpExtension::uri, "uri4")))))));
2014}
2015
2016TEST_F(MediaSessionDescriptionFactoryTest,
2017 AppendsUnstoppedExtensionsToCurrentDescription) {
2018 MediaSessionOptions opts;
2019 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2020 RtpTransceiverDirection::kSendRecv, kActive,
2021 &opts);
2022 opts.media_description_options.back().header_extensions = {
2023 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2024 RtpTransceiverDirection::kSendRecv)};
2025 auto offer = f1_.CreateOffer(opts, nullptr);
2026 opts.media_description_options.back().header_extensions = {
2027 webrtc::RtpHeaderExtensionCapability("uri1", 2,
2028 RtpTransceiverDirection::kSendRecv),
2029 webrtc::RtpHeaderExtensionCapability("uri2", 3,
2030 RtpTransceiverDirection::kRecvOnly),
2031 webrtc::RtpHeaderExtensionCapability("uri3", 5,
2032 RtpTransceiverDirection::kStopped),
2033 webrtc::RtpHeaderExtensionCapability("uri4", 6,
2034 RtpTransceiverDirection::kSendRecv)};
2035 auto offer2 = f1_.CreateOffer(opts, offer.get());
2036 EXPECT_THAT(
2037 offer2->contents(),
2038 ElementsAre(Property(
2039 &ContentInfo::media_description,
2040 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2041 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2042 Field(&RtpExtension::uri, "uri2"),
2043 Field(&RtpExtension::uri, "uri4")))))));
2044}
2045
2046TEST_F(MediaSessionDescriptionFactoryTest,
2047 AppendsStoppedExtensionIfKnownAndPresentInTheOffer) {
2048 MediaSessionOptions opts;
2049 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2050 RtpTransceiverDirection::kSendRecv, kActive,
2051 &opts);
2052 opts.media_description_options.back().header_extensions = {
2053 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2054 RtpTransceiverDirection::kSendRecv),
2055 webrtc::RtpHeaderExtensionCapability("uri2", 1,
2056 RtpTransceiverDirection::kSendRecv)};
2057 auto offer = f1_.CreateOffer(opts, nullptr);
2058
2059 // Now add "uri2" as stopped to the options verify that the offer contains
2060 // uri2 since it's already present since before.
2061 opts.media_description_options.back().header_extensions = {
2062 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2063 RtpTransceiverDirection::kSendRecv),
2064 webrtc::RtpHeaderExtensionCapability("uri2", 2,
2065 RtpTransceiverDirection::kStopped)};
2066 auto offer2 = f1_.CreateOffer(opts, offer.get());
2067 EXPECT_THAT(
2068 offer2->contents(),
2069 ElementsAre(Property(
2070 &ContentInfo::media_description,
2071 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2072 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2073 Field(&RtpExtension::uri, "uri2")))))));
2074}
2075
2076TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002077 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07002078 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002079 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002080
2081 f1_.set_enable_encrypted_rtp_header_extensions(true);
2082 f2_.set_enable_encrypted_rtp_header_extensions(true);
2083
Markus Handell755c65d2020-06-24 01:06:10 +02002084 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2085 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002086 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002087 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002088 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2089 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002090 std::unique_ptr<SessionDescription> answer =
2091 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002092
Yves Gerey665174f2018-06-19 15:03:05 +02002093 EXPECT_EQ(
2094 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2095 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2096 EXPECT_EQ(
2097 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2098 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2099 EXPECT_EQ(
2100 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
2101 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2102 EXPECT_EQ(
2103 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
2104 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002105}
2106
2107TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002108 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07002109 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002110 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002111
2112 f1_.set_enable_encrypted_rtp_header_extensions(true);
2113
Markus Handell755c65d2020-06-24 01:06:10 +02002114 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2115 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002116 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002117 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002118 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2119 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002120 std::unique_ptr<SessionDescription> answer =
2121 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002122
Yves Gerey665174f2018-06-19 15:03:05 +02002123 EXPECT_EQ(
2124 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2125 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2126 EXPECT_EQ(
2127 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2128 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2129 EXPECT_EQ(
2130 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2131 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2132 EXPECT_EQ(
2133 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2134 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002135}
2136
2137TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002138 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07002139 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002140 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002141
2142 f2_.set_enable_encrypted_rtp_header_extensions(true);
2143
Markus Handell755c65d2020-06-24 01:06:10 +02002144 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2145 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002146 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002147 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002148 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2149 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002150 std::unique_ptr<SessionDescription> answer =
2151 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002152
Yves Gerey665174f2018-06-19 15:03:05 +02002153 EXPECT_EQ(
2154 MAKE_VECTOR(kAudioRtpExtension1),
2155 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2156 EXPECT_EQ(
2157 MAKE_VECTOR(kVideoRtpExtension1),
2158 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2159 EXPECT_EQ(
2160 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2161 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2162 EXPECT_EQ(
2163 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2164 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002165}
2166
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002167// Create an audio, video, data answer without legacy StreamParams.
2168TEST_F(MediaSessionDescriptionFactoryTest,
2169 TestCreateAnswerWithoutLegacyStreams) {
2170 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002171 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2172 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002173 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002175 std::unique_ptr<SessionDescription> answer =
2176 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002177 const ContentInfo* ac = answer->GetContentByName("audio");
2178 const ContentInfo* vc = answer->GetContentByName("video");
2179 const ContentInfo* dc = answer->GetContentByName("data");
2180 ASSERT_TRUE(ac != NULL);
2181 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002182 const AudioContentDescription* acd = ac->media_description()->as_audio();
2183 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002184 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002185
2186 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2187 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
2188 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
2189}
2190
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002191// Create a typical video answer, and ensure it matches what we expect.
2192TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2193 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002194 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
2195 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
2196 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002197
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002198 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002199 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
2200 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
2201 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002202
kwiberg31022942016-03-11 14:18:21 -08002203 std::unique_ptr<SessionDescription> offer;
2204 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002205
2206 offer_opts.rtcp_mux_enabled = true;
2207 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002208 offer = f1_.CreateOffer(offer_opts, NULL);
2209 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002210 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2211 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002212 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002213 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2214 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002215 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002216 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2217 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002218 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002219 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2220 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002221 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002222
2223 offer_opts.rtcp_mux_enabled = true;
2224 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002225 offer = f1_.CreateOffer(offer_opts, NULL);
2226 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002227 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2228 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002229 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002230 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2231 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002232 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002233 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2234 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002235 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002236 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2237 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002238 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239
2240 offer_opts.rtcp_mux_enabled = false;
2241 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002242 offer = f1_.CreateOffer(offer_opts, NULL);
2243 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2245 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002246 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002247 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2248 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002249 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002250 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2251 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002252 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002253 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2254 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002255 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002256
2257 offer_opts.rtcp_mux_enabled = false;
2258 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002259 offer = f1_.CreateOffer(offer_opts, NULL);
2260 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002261 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2262 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002263 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002264 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2265 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002266 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002267 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2268 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002269 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002270 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2271 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002272 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002273}
2274
2275// Create an audio-only answer to a video offer.
2276TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2277 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002278 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2279 RtpTransceiverDirection::kRecvOnly, kActive,
2280 &opts);
2281 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2282 RtpTransceiverDirection::kRecvOnly, kActive,
2283 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002284 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002285 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002286
2287 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002288 std::unique_ptr<SessionDescription> answer =
2289 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002290 const ContentInfo* ac = answer->GetContentByName("audio");
2291 const ContentInfo* vc = answer->GetContentByName("video");
2292 ASSERT_TRUE(ac != NULL);
2293 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002294 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002295 EXPECT_TRUE(vc->rejected);
2296}
2297
2298// Create an audio-only answer to an offer with data.
2299TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002300 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002301 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002302 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2303 RtpTransceiverDirection::kRecvOnly, kActive,
2304 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002305 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002306 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002307
2308 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002309 std::unique_ptr<SessionDescription> answer =
2310 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002311 const ContentInfo* ac = answer->GetContentByName("audio");
2312 const ContentInfo* dc = answer->GetContentByName("data");
2313 ASSERT_TRUE(ac != NULL);
2314 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002315 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002316 EXPECT_TRUE(dc->rejected);
2317}
2318
2319// Create an answer that rejects the contents which are rejected in the offer.
2320TEST_F(MediaSessionDescriptionFactoryTest,
2321 CreateAnswerToOfferWithRejectedMedia) {
2322 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002323 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2324 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002325 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002326 ASSERT_TRUE(offer.get() != NULL);
2327 ContentInfo* ac = offer->GetContentByName("audio");
2328 ContentInfo* vc = offer->GetContentByName("video");
2329 ContentInfo* dc = offer->GetContentByName("data");
2330 ASSERT_TRUE(ac != NULL);
2331 ASSERT_TRUE(vc != NULL);
2332 ASSERT_TRUE(dc != NULL);
2333 ac->rejected = true;
2334 vc->rejected = true;
2335 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002336 std::unique_ptr<SessionDescription> answer =
2337 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002338 ac = answer->GetContentByName("audio");
2339 vc = answer->GetContentByName("video");
2340 dc = answer->GetContentByName("data");
2341 ASSERT_TRUE(ac != NULL);
2342 ASSERT_TRUE(vc != NULL);
2343 ASSERT_TRUE(dc != NULL);
2344 EXPECT_TRUE(ac->rejected);
2345 EXPECT_TRUE(vc->rejected);
2346 EXPECT_TRUE(dc->rejected);
2347}
2348
Johannes Kron0854eb62018-10-10 22:33:20 +02002349TEST_F(MediaSessionDescriptionFactoryTest,
2350 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2351 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002352 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002353 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002354 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002355 ASSERT_TRUE(offer.get() != NULL);
2356 std::unique_ptr<SessionDescription> answer_no_support(
2357 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002358 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002359
2360 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002361 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002362 ASSERT_TRUE(offer.get() != NULL);
2363 std::unique_ptr<SessionDescription> answer_support(
2364 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002365 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002366}
2367
2368TEST_F(MediaSessionDescriptionFactoryTest,
2369 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2370 MediaSessionOptions opts;
2371 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002372 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002373 MediaContentDescription* video_offer =
2374 offer->GetContentDescriptionByName("video");
2375 ASSERT_TRUE(video_offer);
2376 MediaContentDescription* audio_offer =
2377 offer->GetContentDescriptionByName("audio");
2378 ASSERT_TRUE(audio_offer);
2379
2380 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002381 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2382 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002383
2384 ASSERT_TRUE(offer.get() != NULL);
2385 std::unique_ptr<SessionDescription> answer_no_support(
2386 f2_.CreateAnswer(offer.get(), opts, NULL));
2387 MediaContentDescription* video_answer =
2388 answer_no_support->GetContentDescriptionByName("video");
2389 MediaContentDescription* audio_answer =
2390 answer_no_support->GetContentDescriptionByName("audio");
2391 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002392 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002393 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002394 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002395
2396 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002397 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2398 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002399 ASSERT_TRUE(offer.get() != NULL);
2400 std::unique_ptr<SessionDescription> answer_support(
2401 f2_.CreateAnswer(offer.get(), opts, NULL));
2402 video_answer = answer_support->GetContentDescriptionByName("video");
2403 audio_answer = answer_support->GetContentDescriptionByName("audio");
2404 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002405 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002406 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002407 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002408}
2409
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002410// Create an audio and video offer with:
2411// - one video track
2412// - two audio tracks
2413// - two data tracks
2414// and ensure it matches what we expect. Also updates the initial offer by
2415// adding a new video track and replaces one of the audio tracks.
2416TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2417 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002418 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002419 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2420 {kMediaStream1}, 1, &opts);
2421 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2422 {kMediaStream1}, 1, &opts);
2423 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2424 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002425
Steve Anton4e70a722017-11-28 14:57:10 -08002426 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002427 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2428 {kMediaStream1}, 1, &opts);
2429 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2430 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002431
2432 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002433 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002434
2435 ASSERT_TRUE(offer.get() != NULL);
2436 const ContentInfo* ac = offer->GetContentByName("audio");
2437 const ContentInfo* vc = offer->GetContentByName("video");
2438 const ContentInfo* dc = offer->GetContentByName("data");
2439 ASSERT_TRUE(ac != NULL);
2440 ASSERT_TRUE(vc != NULL);
2441 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002442 const AudioContentDescription* acd = ac->media_description()->as_audio();
2443 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002444 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002445 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002446 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002447
2448 const StreamParamsVec& audio_streams = acd->streams();
2449 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002450 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002451 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2452 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2453 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2454 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2455 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2456 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2457
2458 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2459 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002460 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002461
2462 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002463 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002464 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002465
2466 const StreamParamsVec& video_streams = vcd->streams();
2467 ASSERT_EQ(1U, video_streams.size());
2468 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2469 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2470 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2471 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2472
2473 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002474 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002475 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002476
2477 const StreamParamsVec& data_streams = dcd->streams();
2478 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002479 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002480 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2481 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2482 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2483 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2484 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2485 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2486
Philipp Hanckeafee7082020-10-22 11:55:58 +02002487 EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002488 dcd->bandwidth()); // default bandwidth (auto)
2489 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002490 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002491
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002492 // Update the offer. Add a new video track that is not synched to the
2493 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002494 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2495 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002496 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002497 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2498 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002499 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002500 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2501 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002502 std::unique_ptr<SessionDescription> updated_offer(
2503 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002504
2505 ASSERT_TRUE(updated_offer.get() != NULL);
2506 ac = updated_offer->GetContentByName("audio");
2507 vc = updated_offer->GetContentByName("video");
2508 dc = updated_offer->GetContentByName("data");
2509 ASSERT_TRUE(ac != NULL);
2510 ASSERT_TRUE(vc != NULL);
2511 ASSERT_TRUE(dc != NULL);
2512 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002513 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002515 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002516 const RtpDataContentDescription* updated_dcd =
2517 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002518
2519 EXPECT_EQ(acd->type(), updated_acd->type());
2520 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2521 EXPECT_EQ(vcd->type(), updated_vcd->type());
2522 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2523 EXPECT_EQ(dcd->type(), updated_dcd->type());
2524 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002525 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002527 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002529 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2531
2532 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2533 ASSERT_EQ(2U, updated_audio_streams.size());
2534 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2535 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2536 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2537 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2538 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2539
2540 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2541 ASSERT_EQ(2U, updated_video_streams.size());
2542 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2543 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002544 // All the media streams in one PeerConnection share one RTCP CNAME.
2545 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002546
2547 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2548 ASSERT_EQ(2U, updated_data_streams.size());
2549 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2550 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2551 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2552 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2553 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002554 // The stream correctly got the CNAME from the MediaSessionOptions.
2555 // The Expected RTCP CNAME is the default one as we are using the default
2556 // MediaSessionOptions.
2557 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002558}
2559
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002560// Create an offer with simulcast video stream.
2561TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2562 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002563 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2564 RtpTransceiverDirection::kRecvOnly, kActive,
2565 &opts);
2566 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2567 RtpTransceiverDirection::kSendRecv, kActive,
2568 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002569 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002570 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2571 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002572 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002573
2574 ASSERT_TRUE(offer.get() != NULL);
2575 const ContentInfo* vc = offer->GetContentByName("video");
2576 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002577 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002578
2579 const StreamParamsVec& video_streams = vcd->streams();
2580 ASSERT_EQ(1U, video_streams.size());
2581 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2582 const SsrcGroup* sim_ssrc_group =
2583 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2584 ASSERT_TRUE(sim_ssrc_group != NULL);
2585 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2586}
2587
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002588MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2589 const RidDescription& rid1 = ::testing::get<0>(arg);
2590 const RidDescription& rid2 = ::testing::get<1>(arg);
2591 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2592}
2593
2594static void CheckSimulcastInSessionDescription(
2595 const SessionDescription* description,
2596 const std::string& content_name,
2597 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002598 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002599 ASSERT_NE(description, nullptr);
2600 const ContentInfo* content = description->GetContentByName(content_name);
2601 ASSERT_NE(content, nullptr);
2602 const MediaContentDescription* cd = content->media_description();
2603 ASSERT_NE(cd, nullptr);
2604 const StreamParamsVec& streams = cd->streams();
2605 ASSERT_THAT(streams, SizeIs(1));
2606 const StreamParams& stream = streams[0];
2607 ASSERT_THAT(stream.ssrcs, IsEmpty());
2608 EXPECT_TRUE(stream.has_rids());
2609 const std::vector<RidDescription> rids = stream.rids();
2610
2611 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2612
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002613 EXPECT_TRUE(cd->HasSimulcast());
2614 const SimulcastDescription& simulcast = cd->simulcast_description();
2615 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2616 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2617
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002618 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002619}
2620
2621// Create an offer with spec-compliant simulcast video stream.
2622TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2623 MediaSessionOptions opts;
2624 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2625 RtpTransceiverDirection::kSendRecv, kActive,
2626 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002627 std::vector<RidDescription> send_rids;
2628 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2629 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2630 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2631 SimulcastLayerList simulcast_layers;
2632 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2633 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2634 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2635 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2636 {kMediaStream1}, send_rids,
2637 simulcast_layers, 0, &opts);
2638 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2639
2640 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002641 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002642}
2643
2644// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2645// In this scenario, RIDs do not need to be negotiated (there is only one).
2646TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2647 MediaSessionOptions opts;
2648 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2649 RtpTransceiverDirection::kSendRecv, kActive,
2650 &opts);
2651 RidDescription rid("f", RidDirection::kSend);
2652 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2653 {kMediaStream1}, {rid},
2654 SimulcastLayerList(), 0, &opts);
2655 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2656
2657 ASSERT_NE(offer.get(), nullptr);
2658 const ContentInfo* content = offer->GetContentByName("video");
2659 ASSERT_NE(content, nullptr);
2660 const MediaContentDescription* cd = content->media_description();
2661 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002662 const StreamParamsVec& streams = cd->streams();
2663 ASSERT_THAT(streams, SizeIs(1));
2664 const StreamParams& stream = streams[0];
2665 ASSERT_THAT(stream.ssrcs, IsEmpty());
2666 EXPECT_FALSE(stream.has_rids());
2667 EXPECT_FALSE(cd->HasSimulcast());
2668}
2669
2670// Create an answer with spec-compliant simulcast video stream.
2671// In this scenario, the SFU is the caller requesting that we send Simulcast.
2672TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2673 MediaSessionOptions offer_opts;
2674 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2675 RtpTransceiverDirection::kSendRecv, kActive,
2676 &offer_opts);
2677 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2678 {kMediaStream1}, 1, &offer_opts);
2679 std::unique_ptr<SessionDescription> offer =
2680 f1_.CreateOffer(offer_opts, nullptr);
2681
2682 MediaSessionOptions answer_opts;
2683 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2684 RtpTransceiverDirection::kSendRecv, kActive,
2685 &answer_opts);
2686
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002687 std::vector<RidDescription> rid_descriptions{
2688 RidDescription("f", RidDirection::kSend),
2689 RidDescription("h", RidDirection::kSend),
2690 RidDescription("q", RidDirection::kSend),
2691 };
2692 SimulcastLayerList simulcast_layers;
2693 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2694 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2695 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2696 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2697 {kMediaStream1}, rid_descriptions,
2698 simulcast_layers, 0, &answer_opts);
2699 std::unique_ptr<SessionDescription> answer =
2700 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2701
2702 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002703 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002704}
2705
2706// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2707// In this scenario, RIDs do not need to be negotiated (there is only one).
2708// Note that RID Direction is not the same as the transceiver direction.
2709TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2710 MediaSessionOptions offer_opts;
2711 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2712 RtpTransceiverDirection::kSendRecv, kActive,
2713 &offer_opts);
2714 RidDescription rid_offer("f", RidDirection::kSend);
2715 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2716 {kMediaStream1}, {rid_offer},
2717 SimulcastLayerList(), 0, &offer_opts);
2718 std::unique_ptr<SessionDescription> offer =
2719 f1_.CreateOffer(offer_opts, nullptr);
2720
2721 MediaSessionOptions answer_opts;
2722 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2723 RtpTransceiverDirection::kSendRecv, kActive,
2724 &answer_opts);
2725
2726 RidDescription rid_answer("f", RidDirection::kReceive);
2727 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2728 {kMediaStream1}, {rid_answer},
2729 SimulcastLayerList(), 0, &answer_opts);
2730 std::unique_ptr<SessionDescription> answer =
2731 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2732
2733 ASSERT_NE(answer.get(), nullptr);
2734 const ContentInfo* content = offer->GetContentByName("video");
2735 ASSERT_NE(content, nullptr);
2736 const MediaContentDescription* cd = content->media_description();
2737 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002738 const StreamParamsVec& streams = cd->streams();
2739 ASSERT_THAT(streams, SizeIs(1));
2740 const StreamParams& stream = streams[0];
2741 ASSERT_THAT(stream.ssrcs, IsEmpty());
2742 EXPECT_FALSE(stream.has_rids());
2743 EXPECT_FALSE(cd->HasSimulcast());
2744}
2745
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002746// Create an audio and video answer to a standard video offer with:
2747// - one video track
2748// - two audio tracks
2749// - two data tracks
2750// and ensure it matches what we expect. Also updates the initial answer by
2751// adding a new video track and removes one of the audio tracks.
2752TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2753 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002754 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2755 RtpTransceiverDirection::kRecvOnly, kActive,
2756 &offer_opts);
2757 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2758 RtpTransceiverDirection::kRecvOnly, kActive,
2759 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002760 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002761 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2762 RtpTransceiverDirection::kRecvOnly, kActive,
2763 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002764 f1_.set_secure(SEC_ENABLED);
2765 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002766 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002767
zhihuang1c378ed2017-08-17 14:10:50 -07002768 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002769 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2770 RtpTransceiverDirection::kSendRecv, kActive,
2771 &answer_opts);
2772 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2773 RtpTransceiverDirection::kSendRecv, kActive,
2774 &answer_opts);
2775 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2776 {kMediaStream1}, 1, &answer_opts);
2777 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2778 {kMediaStream1}, 1, &answer_opts);
2779 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2780 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002781
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002782 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2783 RtpTransceiverDirection::kSendRecv, kActive,
2784 &answer_opts);
2785 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2786 {kMediaStream1}, 1, &answer_opts);
2787 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2788 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002789 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002790
Steve Anton6fe1fba2018-12-11 10:15:23 -08002791 std::unique_ptr<SessionDescription> answer =
2792 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793
2794 ASSERT_TRUE(answer.get() != NULL);
2795 const ContentInfo* ac = answer->GetContentByName("audio");
2796 const ContentInfo* vc = answer->GetContentByName("video");
2797 const ContentInfo* dc = answer->GetContentByName("data");
2798 ASSERT_TRUE(ac != NULL);
2799 ASSERT_TRUE(vc != NULL);
2800 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002801 const AudioContentDescription* acd = ac->media_description()->as_audio();
2802 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002803 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002804 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2805 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2806 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002807
2808 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002809 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002810
2811 const StreamParamsVec& audio_streams = acd->streams();
2812 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002813 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2815 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2816 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2817 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2818 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2819 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2820
2821 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2822 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2823
2824 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002825 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002826
2827 const StreamParamsVec& video_streams = vcd->streams();
2828 ASSERT_EQ(1U, video_streams.size());
2829 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2830 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2831 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2832 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2833
2834 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002835 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002836
2837 const StreamParamsVec& data_streams = dcd->streams();
2838 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002839 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002840 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2841 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2842 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2843 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2844 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2845 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2846
Philipp Hanckeafee7082020-10-22 11:55:58 +02002847 EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002848 dcd->bandwidth()); // default bandwidth (auto)
2849 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002850
2851 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002852 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002853 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2854 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002855 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2856 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002857 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002858 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002859
2860 ASSERT_TRUE(updated_answer.get() != NULL);
2861 ac = updated_answer->GetContentByName("audio");
2862 vc = updated_answer->GetContentByName("video");
2863 dc = updated_answer->GetContentByName("data");
2864 ASSERT_TRUE(ac != NULL);
2865 ASSERT_TRUE(vc != NULL);
2866 ASSERT_TRUE(dc != NULL);
2867 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002868 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002869 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002870 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002871 const RtpDataContentDescription* updated_dcd =
2872 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002873
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002874 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002875 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002876 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002877 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002878 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002879 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2880
2881 EXPECT_EQ(acd->type(), updated_acd->type());
2882 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2883 EXPECT_EQ(vcd->type(), updated_vcd->type());
2884 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2885 EXPECT_EQ(dcd->type(), updated_dcd->type());
2886 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2887
2888 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2889 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002890 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002891
2892 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2893 ASSERT_EQ(2U, updated_video_streams.size());
2894 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2895 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002896 // All media streams in one PeerConnection share one CNAME.
2897 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002898
2899 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2900 ASSERT_EQ(1U, updated_data_streams.size());
2901 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2902}
2903
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002904// Create an updated offer after creating an answer to the original offer and
2905// verify that the codecs that were part of the original answer are not changed
2906// in the updated offer.
2907TEST_F(MediaSessionDescriptionFactoryTest,
2908 RespondentCreatesOfferAfterCreatingAnswer) {
2909 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002910 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002911
Steve Anton6fe1fba2018-12-11 10:15:23 -08002912 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2913 std::unique_ptr<SessionDescription> answer =
2914 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002915
2916 const AudioContentDescription* acd =
2917 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002918 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002919
2920 const VideoContentDescription* vcd =
2921 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002922 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002923
kwiberg31022942016-03-11 14:18:21 -08002924 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002925 f2_.CreateOffer(opts, answer.get()));
2926
2927 // The expected audio codecs are the common audio codecs from the first
2928 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2929 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002930 // TODO(wu): |updated_offer| should not include the codec
2931 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002932 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002933 kAudioCodecsAnswer[0],
2934 kAudioCodecsAnswer[1],
2935 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002936 };
2937
2938 // The expected video codecs are the common video codecs from the first
2939 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2940 // preference order.
2941 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002942 kVideoCodecsAnswer[0],
2943 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002944 };
2945
2946 const AudioContentDescription* updated_acd =
2947 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002948 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002949
2950 const VideoContentDescription* updated_vcd =
2951 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002952 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002953}
2954
Steve Anton5c72e712018-12-10 14:25:30 -08002955// Test that a reoffer does not reuse audio codecs from a previous media section
2956// that is being recycled.
2957TEST_F(MediaSessionDescriptionFactoryTest,
2958 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002959 f1_.set_video_codecs({}, {});
2960 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002961
2962 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002963 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2964 RtpTransceiverDirection::kSendRecv, kActive,
2965 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002966 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2967 std::unique_ptr<SessionDescription> answer =
2968 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002969
2970 // Recycle the media section by changing its mid.
2971 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002972 std::unique_ptr<SessionDescription> reoffer =
2973 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002974
2975 // Expect that the results of the first negotiation are ignored. If the m=
2976 // section was not recycled the payload types would match the initial offerer.
2977 const AudioContentDescription* acd =
2978 GetFirstAudioContentDescription(reoffer.get());
2979 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2980}
2981
2982// Test that a reoffer does not reuse video codecs from a previous media section
2983// that is being recycled.
2984TEST_F(MediaSessionDescriptionFactoryTest,
2985 ReOfferDoesNotReUseRecycledVideoCodecs) {
2986 f1_.set_audio_codecs({}, {});
2987 f2_.set_audio_codecs({}, {});
2988
2989 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002990 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2991 RtpTransceiverDirection::kSendRecv, kActive,
2992 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002993 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2994 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002995
2996 // Recycle the media section by changing its mid.
2997 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002998 std::unique_ptr<SessionDescription> reoffer =
2999 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003000
3001 // Expect that the results of the first negotiation are ignored. If the m=
3002 // section was not recycled the payload types would match the initial offerer.
3003 const VideoContentDescription* vcd =
3004 GetFirstVideoContentDescription(reoffer.get());
3005 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
3006}
3007
3008// Test that a reanswer does not reuse audio codecs from a previous media
3009// section that is being recycled.
3010TEST_F(MediaSessionDescriptionFactoryTest,
3011 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02003012 f1_.set_video_codecs({}, {});
3013 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08003014
3015 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
3016 // second offer/answer is forward (|f1_| as offerer).
3017 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003018 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
3019 RtpTransceiverDirection::kSendRecv, kActive,
3020 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003021 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
3022 std::unique_ptr<SessionDescription> answer =
3023 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08003024
3025 // Recycle the media section by changing its mid.
3026 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08003027 std::unique_ptr<SessionDescription> reoffer =
3028 f1_.CreateOffer(opts, answer.get());
3029 std::unique_ptr<SessionDescription> reanswer =
3030 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003031
3032 // Expect that the results of the first negotiation are ignored. If the m=
3033 // section was not recycled the payload types would match the initial offerer.
3034 const AudioContentDescription* acd =
3035 GetFirstAudioContentDescription(reanswer.get());
3036 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
3037}
3038
3039// Test that a reanswer does not reuse video codecs from a previous media
3040// section that is being recycled.
3041TEST_F(MediaSessionDescriptionFactoryTest,
3042 ReAnswerDoesNotReUseRecycledVideoCodecs) {
3043 f1_.set_audio_codecs({}, {});
3044 f2_.set_audio_codecs({}, {});
3045
3046 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
3047 // second offer/answer is forward (|f1_| as offerer).
3048 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003049 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
3050 RtpTransceiverDirection::kSendRecv, kActive,
3051 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003052 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
3053 std::unique_ptr<SessionDescription> answer =
3054 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08003055
3056 // Recycle the media section by changing its mid.
3057 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08003058 std::unique_ptr<SessionDescription> reoffer =
3059 f1_.CreateOffer(opts, answer.get());
3060 std::unique_ptr<SessionDescription> reanswer =
3061 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003062
3063 // Expect that the results of the first negotiation are ignored. If the m=
3064 // section was not recycled the payload types would match the initial offerer.
3065 const VideoContentDescription* vcd =
3066 GetFirstVideoContentDescription(reanswer.get());
3067 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
3068}
3069
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003070// Create an updated offer after creating an answer to the original offer and
3071// verify that the codecs that were part of the original answer are not changed
3072// in the updated offer. In this test Rtx is enabled.
3073TEST_F(MediaSessionDescriptionFactoryTest,
3074 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
3075 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003076 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3077 RtpTransceiverDirection::kRecvOnly, kActive,
3078 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003079 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003080 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003081 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003082 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003083
3084 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003085 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003086 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003087 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003088
Steve Anton6fe1fba2018-12-11 10:15:23 -08003089 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003090 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003091 std::unique_ptr<SessionDescription> answer =
3092 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003093
3094 const VideoContentDescription* vcd =
3095 GetFirstVideoContentDescription(answer.get());
3096
3097 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003098 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3099 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003100
3101 EXPECT_EQ(expected_codecs, vcd->codecs());
3102
deadbeef67cf2c12016-04-13 10:07:16 -07003103 // Now, make sure we get same result (except for the order) if |f2_| creates
3104 // an updated offer even though the default payload types between |f1_| and
3105 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08003106 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003107 f2_.CreateOffer(opts, answer.get()));
3108 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003109 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003110 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3111
3112 const VideoContentDescription* updated_vcd =
3113 GetFirstVideoContentDescription(updated_answer.get());
3114
3115 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3116}
3117
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003118// Regression test for:
3119// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
3120// Existing codecs should always appear before new codecs in re-offers. But
3121// under a specific set of circumstances, the existing RTX codec was ending up
3122// added to the end of the list.
3123TEST_F(MediaSessionDescriptionFactoryTest,
3124 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
3125 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003126 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3127 RtpTransceiverDirection::kRecvOnly, kActive,
3128 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003129 // We specifically choose different preferred payload types for VP8 to
3130 // trigger the issue.
3131 cricket::VideoCodec vp8_offerer(100, "VP8");
3132 cricket::VideoCodec vp8_offerer_rtx =
3133 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
3134 cricket::VideoCodec vp8_answerer(110, "VP8");
3135 cricket::VideoCodec vp8_answerer_rtx =
3136 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
3137 cricket::VideoCodec vp9(120, "VP9");
3138 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
3139
3140 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
3141 // We also specifically cause the answerer to prefer VP9, such that if it
3142 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
3143 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
3144 vp8_answerer_rtx};
3145
Johannes Kron3e983682020-03-29 22:17:00 +02003146 f1_.set_video_codecs(f1_codecs, f1_codecs);
3147 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003148 std::vector<AudioCodec> audio_codecs;
3149 f1_.set_audio_codecs(audio_codecs, audio_codecs);
3150 f2_.set_audio_codecs(audio_codecs, audio_codecs);
3151
3152 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003153 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003154 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003155 std::unique_ptr<SessionDescription> answer =
3156 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003157
3158 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
3159 // But if the bug is triggered, RTX for VP8 ends up last.
3160 std::unique_ptr<SessionDescription> updated_offer(
3161 f2_.CreateOffer(opts, answer.get()));
3162
3163 const VideoContentDescription* vcd =
3164 GetFirstVideoContentDescription(updated_offer.get());
3165 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
3166 ASSERT_EQ(4u, codecs.size());
3167 EXPECT_EQ(vp8_offerer, codecs[0]);
3168 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
3169 EXPECT_EQ(vp9, codecs[2]);
3170 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003171}
3172
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003173// Create an updated offer that adds video after creating an audio only answer
3174// to the original offer. This test verifies that if a video codec and the RTX
3175// codec have the same default payload type as an audio codec that is already in
3176// use, the added codecs payload types are changed.
3177TEST_F(MediaSessionDescriptionFactoryTest,
3178 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
3179 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003180 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003181 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003182 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003183
3184 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003185 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3186 RtpTransceiverDirection::kRecvOnly, kActive,
3187 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003188
Steve Anton6fe1fba2018-12-11 10:15:23 -08003189 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3190 std::unique_ptr<SessionDescription> answer =
3191 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003192
3193 const AudioContentDescription* acd =
3194 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003195 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003196
3197 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
3198 // reference be the same as an audio codec that was negotiated in the
3199 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07003200 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08003201 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003202
3203 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3204 int used_pl_type = acd->codecs()[0].id;
3205 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003206 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003207 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003208
kwiberg31022942016-03-11 14:18:21 -08003209 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003210 f2_.CreateOffer(opts, answer.get()));
3211 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003212 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003213 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3214
3215 const AudioContentDescription* updated_acd =
3216 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003217 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003218
3219 const VideoContentDescription* updated_vcd =
3220 GetFirstVideoContentDescription(updated_answer.get());
3221
3222 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003223 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003224 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003225 EXPECT_NE(used_pl_type, new_h264_pl_type);
3226 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003227 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003228 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3229 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3230}
3231
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003232// Create an updated offer with RTX after creating an answer to an offer
3233// without RTX, and with different default payload types.
3234// Verify that the added RTX codec references the correct payload type.
3235TEST_F(MediaSessionDescriptionFactoryTest,
3236 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3237 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003238 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003239
3240 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3241 // This creates rtx for H264 with the payload type |f2_| uses.
3242 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003243 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003244
Steve Anton6fe1fba2018-12-11 10:15:23 -08003245 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003246 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003247 std::unique_ptr<SessionDescription> answer =
3248 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003249
3250 const VideoContentDescription* vcd =
3251 GetFirstVideoContentDescription(answer.get());
3252
3253 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3254 EXPECT_EQ(expected_codecs, vcd->codecs());
3255
3256 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
3257 // updated offer, even though the default payload types are different from
3258 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08003259 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003260 f2_.CreateOffer(opts, answer.get()));
3261 ASSERT_TRUE(updated_offer);
3262
3263 const VideoContentDescription* updated_vcd =
3264 GetFirstVideoContentDescription(updated_offer.get());
3265
3266 // New offer should attempt to add H263, and RTX for H264.
3267 expected_codecs.push_back(kVideoCodecs2[1]);
3268 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3269 &expected_codecs);
3270 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3271}
3272
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003273// Test that RTX is ignored when there is no associated payload type parameter.
3274TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3275 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003276 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3277 RtpTransceiverDirection::kRecvOnly, kActive,
3278 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003279 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003280 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003281 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003282 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003283
3284 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003285 // This creates RTX for H264 with the payload type |f2_| uses.
3286 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003287 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003288
Steve Anton6fe1fba2018-12-11 10:15:23 -08003289 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003290 ASSERT_TRUE(offer.get() != NULL);
3291 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3292 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3293 // is possible to test that that RTX is dropped when
3294 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003295 MediaContentDescription* media_desc =
3296 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3297 ASSERT_TRUE(media_desc);
3298 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003299 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003300 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003301 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003302 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003303 }
3304 }
3305 desc->set_codecs(codecs);
3306
Steve Anton6fe1fba2018-12-11 10:15:23 -08003307 std::unique_ptr<SessionDescription> answer =
3308 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003309
Steve Anton64b626b2019-01-28 17:25:26 -08003310 EXPECT_THAT(
3311 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3312 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003313}
3314
3315// Test that RTX will be filtered out in the answer if its associated payload
3316// type doesn't match the local value.
3317TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3318 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003319 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3320 RtpTransceiverDirection::kRecvOnly, kActive,
3321 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003322 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3323 // This creates RTX for H264 in sender.
3324 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003325 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003326
3327 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3328 // This creates RTX for H263 in receiver.
3329 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003330 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003331
Steve Anton6fe1fba2018-12-11 10:15:23 -08003332 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003333 ASSERT_TRUE(offer.get() != NULL);
3334 // Associated payload type doesn't match, therefore, RTX codec is removed in
3335 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003336 std::unique_ptr<SessionDescription> answer =
3337 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003338
Steve Anton64b626b2019-01-28 17:25:26 -08003339 EXPECT_THAT(
3340 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3341 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003342}
3343
3344// Test that when multiple RTX codecs are offered, only the matched RTX codec
3345// is added in the answer, and the unsupported RTX codec is filtered out.
3346TEST_F(MediaSessionDescriptionFactoryTest,
3347 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3348 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003349 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3350 RtpTransceiverDirection::kRecvOnly, kActive,
3351 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003352 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3353 // This creates RTX for H264-SVC in sender.
3354 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003355 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003356
3357 // This creates RTX for H264 in sender.
3358 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003359 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003360
3361 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3362 // This creates RTX for H264 in receiver.
3363 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003364 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003365
3366 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3367 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003368 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003369 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003370 std::unique_ptr<SessionDescription> answer =
3371 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003372 const VideoContentDescription* vcd =
3373 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003374 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3375 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3376 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003377
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003378 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003379}
3380
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003381// Test that after one RTX codec has been negotiated, a new offer can attempt
3382// to add another.
3383TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3384 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003385 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3386 RtpTransceiverDirection::kRecvOnly, kActive,
3387 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003388 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3389 // This creates RTX for H264 for the offerer.
3390 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003391 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003392
Steve Anton6fe1fba2018-12-11 10:15:23 -08003393 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003394 ASSERT_TRUE(offer);
3395 const VideoContentDescription* vcd =
3396 GetFirstVideoContentDescription(offer.get());
3397
3398 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3399 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3400 &expected_codecs);
3401 EXPECT_EQ(expected_codecs, vcd->codecs());
3402
3403 // Now, attempt to add RTX for H264-SVC.
3404 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003405 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003406
kwiberg31022942016-03-11 14:18:21 -08003407 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003408 f1_.CreateOffer(opts, offer.get()));
3409 ASSERT_TRUE(updated_offer);
3410 vcd = GetFirstVideoContentDescription(updated_offer.get());
3411
3412 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3413 &expected_codecs);
3414 EXPECT_EQ(expected_codecs, vcd->codecs());
3415}
3416
Noah Richards2e7a0982015-05-18 14:02:54 -07003417// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3418// generated for each simulcast ssrc and correctly grouped.
3419TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3420 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003421 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3422 RtpTransceiverDirection::kSendRecv, kActive,
3423 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003424 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003425 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3426 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003427
3428 // Use a single real codec, and then add RTX for it.
3429 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003430 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003431 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003432 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003433
3434 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3435 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003436 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003437 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003438 MediaContentDescription* media_desc =
3439 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3440 ASSERT_TRUE(media_desc);
3441 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003442 const StreamParamsVec& streams = desc->streams();
3443 // Single stream.
3444 ASSERT_EQ(1u, streams.size());
3445 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3446 EXPECT_EQ(6u, streams[0].ssrcs.size());
3447 // And should have a SIM group for the simulcast.
3448 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3449 // And a FID group for RTX.
3450 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003451 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003452 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3453 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003454 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003455 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3456 EXPECT_EQ(3u, fid_ssrcs.size());
3457}
3458
brandtr03d5fb12016-11-22 03:37:59 -08003459// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003460// together with a FEC-FR grouping. Guarded by WebRTC-FlexFEC-03 trial.
brandtr03d5fb12016-11-22 03:37:59 -08003461TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003462 webrtc::test::ScopedFieldTrials override_field_trials(
3463 "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003464 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003465 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3466 RtpTransceiverDirection::kSendRecv, kActive,
3467 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003468 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003469 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3470 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003471
3472 // Use a single real codec, and then add FlexFEC for it.
3473 std::vector<VideoCodec> f1_codecs;
3474 f1_codecs.push_back(VideoCodec(97, "H264"));
3475 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003476 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003477
3478 // Ensure that the offer has a single FlexFEC ssrc and that
3479 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003480 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003481 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003482 MediaContentDescription* media_desc =
3483 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3484 ASSERT_TRUE(media_desc);
3485 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003486 const StreamParamsVec& streams = desc->streams();
3487 // Single stream.
3488 ASSERT_EQ(1u, streams.size());
3489 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3490 EXPECT_EQ(2u, streams[0].ssrcs.size());
3491 // And should have a FEC-FR group for FlexFEC.
3492 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3493 std::vector<uint32_t> primary_ssrcs;
3494 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3495 ASSERT_EQ(1u, primary_ssrcs.size());
3496 uint32_t flexfec_ssrc;
3497 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3498 EXPECT_NE(flexfec_ssrc, 0u);
3499}
3500
3501// Test that FlexFEC is disabled for simulcast.
3502// TODO(brandtr): Remove this test when we support simulcast, either through
3503// multiple FlexfecSenders, or through multistream protection.
3504TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003505 webrtc::test::ScopedFieldTrials override_field_trials(
3506 "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003507 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003508 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3509 RtpTransceiverDirection::kSendRecv, kActive,
3510 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003511 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003512 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3513 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003514
3515 // Use a single real codec, and then add FlexFEC for it.
3516 std::vector<VideoCodec> f1_codecs;
3517 f1_codecs.push_back(VideoCodec(97, "H264"));
3518 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003519 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003520
3521 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3522 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003523 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003524 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003525 MediaContentDescription* media_desc =
3526 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3527 ASSERT_TRUE(media_desc);
3528 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003529 const StreamParamsVec& streams = desc->streams();
3530 // Single stream.
3531 ASSERT_EQ(1u, streams.size());
3532 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3533 EXPECT_EQ(3u, streams[0].ssrcs.size());
3534 // And should have a SIM group for the simulcast.
3535 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3536 // And not a FEC-FR group for FlexFEC.
3537 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3538 std::vector<uint32_t> primary_ssrcs;
3539 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3540 EXPECT_EQ(3u, primary_ssrcs.size());
3541 for (uint32_t primary_ssrc : primary_ssrcs) {
3542 uint32_t flexfec_ssrc;
3543 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3544 }
3545}
3546
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003547// Create an updated offer after creating an answer to the original offer and
3548// verify that the RTP header extensions that were part of the original answer
3549// are not changed in the updated offer.
3550TEST_F(MediaSessionDescriptionFactoryTest,
3551 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3552 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003553 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003554
Markus Handell755c65d2020-06-24 01:06:10 +02003555 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3556 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003557 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02003558 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3559 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003560 std::unique_ptr<SessionDescription> answer =
3561 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003562
Yves Gerey665174f2018-06-19 15:03:05 +02003563 EXPECT_EQ(
3564 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3565 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3566 EXPECT_EQ(
3567 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3568 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003569
kwiberg31022942016-03-11 14:18:21 -08003570 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003571 f2_.CreateOffer(opts, answer.get()));
3572
3573 // The expected RTP header extensions in the new offer are the resulting
3574 // extensions from the first offer/answer exchange plus the extensions only
3575 // |f2_| offer.
3576 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003577 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003578 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003579 kAudioRtpExtensionAnswer[0],
3580 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003581 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003582 };
3583
3584 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003585 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003586 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003587 kVideoRtpExtensionAnswer[0],
3588 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003589 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003590 };
3591
3592 const AudioContentDescription* updated_acd =
3593 GetFirstAudioContentDescription(updated_offer.get());
3594 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3595 updated_acd->rtp_header_extensions());
3596
3597 const VideoContentDescription* updated_vcd =
3598 GetFirstVideoContentDescription(updated_offer.get());
3599 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3600 updated_vcd->rtp_header_extensions());
3601}
3602
deadbeefa5b273a2015-08-20 17:30:13 -07003603// Verify that if the same RTP extension URI is used for audio and video, the
3604// same ID is used. Also verify that the ID isn't changed when creating an
3605// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003606TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003607 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003608 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003609
Markus Handell755c65d2020-06-24 01:06:10 +02003610 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3611 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003612 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003613
3614 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3615 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003616 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003617 kVideoRtpExtension3[0],
3618 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003619 };
3620
Yves Gerey665174f2018-06-19 15:03:05 +02003621 EXPECT_EQ(
3622 MAKE_VECTOR(kAudioRtpExtension3),
3623 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3624 EXPECT_EQ(
3625 MAKE_VECTOR(kExpectedVideoRtpExtension),
3626 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003627
3628 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003629 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003630 f1_.CreateOffer(opts, offer.get()));
3631
3632 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003633 GetFirstAudioContentDescription(updated_offer.get())
3634 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003635 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003636 GetFirstVideoContentDescription(updated_offer.get())
3637 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003638}
3639
jbauch5869f502017-06-29 12:31:36 -07003640// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3641TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3642 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003643 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003644
3645 f1_.set_enable_encrypted_rtp_header_extensions(true);
3646 f2_.set_enable_encrypted_rtp_header_extensions(true);
3647
Markus Handell755c65d2020-06-24 01:06:10 +02003648 SetAudioVideoRtpHeaderExtensions(
3649 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3650 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003651 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003652
3653 // The extensions that are shared between audio and video should use the same
3654 // id.
3655 const RtpExtension kExpectedVideoRtpExtension[] = {
3656 kVideoRtpExtension3ForEncryption[0],
3657 kAudioRtpExtension3ForEncryptionOffer[1],
3658 kAudioRtpExtension3ForEncryptionOffer[2],
3659 };
3660
Yves Gerey665174f2018-06-19 15:03:05 +02003661 EXPECT_EQ(
3662 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3663 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3664 EXPECT_EQ(
3665 MAKE_VECTOR(kExpectedVideoRtpExtension),
3666 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003667
3668 // Nothing should change when creating a new offer
3669 std::unique_ptr<SessionDescription> updated_offer(
3670 f1_.CreateOffer(opts, offer.get()));
3671
3672 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003673 GetFirstAudioContentDescription(updated_offer.get())
3674 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003675 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003676 GetFirstVideoContentDescription(updated_offer.get())
3677 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003678}
3679
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003680TEST(MediaSessionDescription, CopySessionDescription) {
3681 SessionDescription source;
3682 cricket::ContentGroup group(cricket::CN_AUDIO);
3683 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003684 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003685 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003686 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3687 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003688 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003689 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003690 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003691 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3692 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003693 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003694
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003695 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003696 ASSERT_TRUE(copy.get() != NULL);
3697 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3698 const ContentInfo* ac = copy->GetContentByName("audio");
3699 const ContentInfo* vc = copy->GetContentByName("video");
3700 ASSERT_TRUE(ac != NULL);
3701 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003702 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003703 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003704 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3705 EXPECT_EQ(1u, acd->first_ssrc());
3706
Steve Anton5adfafd2017-12-20 16:34:00 -08003707 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003708 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003709 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3710 EXPECT_EQ(2u, vcd->first_ssrc());
3711}
3712
3713// The below TestTransportInfoXXX tests create different offers/answers, and
3714// ensure the TransportInfo in the SessionDescription matches what we expect.
3715TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3716 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003717 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3718 RtpTransceiverDirection::kRecvOnly, kActive,
3719 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003720 TestTransportInfo(true, options, false);
3721}
3722
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003723TEST_F(MediaSessionDescriptionFactoryTest,
3724 TestTransportInfoOfferIceRenomination) {
3725 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003726 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3727 RtpTransceiverDirection::kRecvOnly, kActive,
3728 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003729 options.media_description_options[0]
3730 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003731 TestTransportInfo(true, options, false);
3732}
3733
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003734TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3735 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003736 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3737 RtpTransceiverDirection::kRecvOnly, kActive,
3738 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003739 TestTransportInfo(true, options, true);
3740}
3741
3742TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3743 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003744 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3745 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3746 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003747 TestTransportInfo(true, options, false);
3748}
3749
3750TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003751 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003752 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003753 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3754 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3755 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003756 TestTransportInfo(true, options, true);
3757}
3758
3759TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3760 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003761 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3762 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3763 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003764 options.bundle_enabled = true;
3765 TestTransportInfo(true, options, false);
3766}
3767
3768TEST_F(MediaSessionDescriptionFactoryTest,
3769 TestTransportInfoOfferBundleCurrent) {
3770 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003771 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3772 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3773 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003774 options.bundle_enabled = true;
3775 TestTransportInfo(true, options, true);
3776}
3777
3778TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3779 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003780 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3781 RtpTransceiverDirection::kRecvOnly, kActive,
3782 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003783 TestTransportInfo(false, options, false);
3784}
3785
3786TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003787 TestTransportInfoAnswerIceRenomination) {
3788 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003789 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3790 RtpTransceiverDirection::kRecvOnly, kActive,
3791 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003792 options.media_description_options[0]
3793 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003794 TestTransportInfo(false, options, false);
3795}
3796
3797TEST_F(MediaSessionDescriptionFactoryTest,
3798 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003799 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003800 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3801 RtpTransceiverDirection::kRecvOnly, kActive,
3802 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003803 TestTransportInfo(false, options, true);
3804}
3805
3806TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3807 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003808 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3809 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3810 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003811 TestTransportInfo(false, options, false);
3812}
3813
3814TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003815 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003816 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003817 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3818 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3819 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003820 TestTransportInfo(false, options, true);
3821}
3822
3823TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3824 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003825 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3826 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3827 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003828 options.bundle_enabled = true;
3829 TestTransportInfo(false, options, false);
3830}
3831
3832TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003833 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003834 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003835 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3836 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3837 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003838 options.bundle_enabled = true;
3839 TestTransportInfo(false, options, true);
3840}
3841
3842// Create an offer with bundle enabled and verify the crypto parameters are
3843// the common set of the available cryptos.
3844TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3845 TestCryptoWithBundle(true);
3846}
3847
3848// Create an answer with bundle enabled and verify the crypto parameters are
3849// the common set of the available cryptos.
3850TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3851 TestCryptoWithBundle(false);
3852}
3853
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003854// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3855// DTLS is not enabled locally.
3856TEST_F(MediaSessionDescriptionFactoryTest,
3857 TestOfferDtlsSavpfWithoutDtlsFailed) {
3858 f1_.set_secure(SEC_ENABLED);
3859 f2_.set_secure(SEC_ENABLED);
3860 tdf1_.set_secure(SEC_DISABLED);
3861 tdf2_.set_secure(SEC_DISABLED);
3862
Steve Anton6fe1fba2018-12-11 10:15:23 -08003863 std::unique_ptr<SessionDescription> offer =
3864 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003865 ASSERT_TRUE(offer.get() != NULL);
3866 ContentInfo* offer_content = offer->GetContentByName("audio");
3867 ASSERT_TRUE(offer_content != NULL);
3868 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003869 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003870 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3871
Steve Anton6fe1fba2018-12-11 10:15:23 -08003872 std::unique_ptr<SessionDescription> answer =
3873 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003874 ASSERT_TRUE(answer != NULL);
3875 ContentInfo* answer_content = answer->GetContentByName("audio");
3876 ASSERT_TRUE(answer_content != NULL);
3877
3878 ASSERT_TRUE(answer_content->rejected);
3879}
3880
3881// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3882// UDP/TLS/RTP/SAVPF.
3883TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3884 f1_.set_secure(SEC_ENABLED);
3885 f2_.set_secure(SEC_ENABLED);
3886 tdf1_.set_secure(SEC_ENABLED);
3887 tdf2_.set_secure(SEC_ENABLED);
3888
Steve Anton6fe1fba2018-12-11 10:15:23 -08003889 std::unique_ptr<SessionDescription> offer =
3890 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003891 ASSERT_TRUE(offer.get() != NULL);
3892 ContentInfo* offer_content = offer->GetContentByName("audio");
3893 ASSERT_TRUE(offer_content != NULL);
3894 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003895 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003896 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3897
Steve Anton6fe1fba2018-12-11 10:15:23 -08003898 std::unique_ptr<SessionDescription> answer =
3899 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003900 ASSERT_TRUE(answer != NULL);
3901
3902 const ContentInfo* answer_content = answer->GetContentByName("audio");
3903 ASSERT_TRUE(answer_content != NULL);
3904 ASSERT_FALSE(answer_content->rejected);
3905
3906 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003907 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003908 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003909}
3910
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003911// Test that we include both SDES and DTLS in the offer, but only include SDES
3912// in the answer if DTLS isn't negotiated.
3913TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3914 f1_.set_secure(SEC_ENABLED);
3915 f2_.set_secure(SEC_ENABLED);
3916 tdf1_.set_secure(SEC_ENABLED);
3917 tdf2_.set_secure(SEC_DISABLED);
3918 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003919 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003920 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003921 const cricket::MediaContentDescription* audio_media_desc;
3922 const cricket::MediaContentDescription* video_media_desc;
3923 const cricket::TransportDescription* audio_trans_desc;
3924 const cricket::TransportDescription* video_trans_desc;
3925
3926 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003927 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003928 ASSERT_TRUE(offer.get() != NULL);
3929
Steve Antonb1c1de12017-12-21 15:14:30 -08003930 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003931 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003932 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003933 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003934 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003935 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3936
3937 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3938 ASSERT_TRUE(audio_trans_desc != NULL);
3939 video_trans_desc = offer->GetTransportDescriptionByName("video");
3940 ASSERT_TRUE(video_trans_desc != NULL);
3941 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3942 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3943
3944 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003945 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003946 ASSERT_TRUE(answer.get() != NULL);
3947
Steve Antonb1c1de12017-12-21 15:14:30 -08003948 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003949 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003950 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003951 ASSERT_TRUE(video_media_desc != NULL);
3952 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3953 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3954
3955 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3956 ASSERT_TRUE(audio_trans_desc != NULL);
3957 video_trans_desc = answer->GetTransportDescriptionByName("video");
3958 ASSERT_TRUE(video_trans_desc != NULL);
3959 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3960 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3961
3962 // Enable DTLS; the answer should now only have DTLS support.
3963 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003964 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003965 ASSERT_TRUE(answer.get() != NULL);
3966
Steve Antonb1c1de12017-12-21 15:14:30 -08003967 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003968 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003969 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003970 ASSERT_TRUE(video_media_desc != NULL);
3971 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3972 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003973 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3974 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003975
3976 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3977 ASSERT_TRUE(audio_trans_desc != NULL);
3978 video_trans_desc = answer->GetTransportDescriptionByName("video");
3979 ASSERT_TRUE(video_trans_desc != NULL);
3980 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3981 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003982
3983 // Try creating offer again. DTLS enabled now, crypto's should be empty
3984 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003985 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003986 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003987 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003988 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003989 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003990 ASSERT_TRUE(video_media_desc != NULL);
3991 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3992 EXPECT_TRUE(video_media_desc->cryptos().empty());
3993
3994 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3995 ASSERT_TRUE(audio_trans_desc != NULL);
3996 video_trans_desc = offer->GetTransportDescriptionByName("video");
3997 ASSERT_TRUE(video_trans_desc != NULL);
3998 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3999 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004000}
4001
4002// Test that an answer can't be created if cryptos are required but the offer is
4003// unsecure.
4004TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004005 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004006 f1_.set_secure(SEC_DISABLED);
4007 tdf1_.set_secure(SEC_DISABLED);
4008 f2_.set_secure(SEC_REQUIRED);
4009 tdf1_.set_secure(SEC_ENABLED);
4010
Steve Anton6fe1fba2018-12-11 10:15:23 -08004011 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004012 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004013 std::unique_ptr<SessionDescription> answer =
4014 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004015 EXPECT_TRUE(answer.get() == NULL);
4016}
4017
4018// Test that we accept a DTLS offer without SDES and create an appropriate
4019// answer.
4020TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
4021 f1_.set_secure(SEC_DISABLED);
4022 f2_.set_secure(SEC_ENABLED);
4023 tdf1_.set_secure(SEC_ENABLED);
4024 tdf2_.set_secure(SEC_ENABLED);
4025 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004026 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
4027 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
4028 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004029
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004030 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004031 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004032 ASSERT_TRUE(offer.get() != NULL);
4033
4034 const AudioContentDescription* audio_offer =
4035 GetFirstAudioContentDescription(offer.get());
4036 ASSERT_TRUE(audio_offer->cryptos().empty());
4037 const VideoContentDescription* video_offer =
4038 GetFirstVideoContentDescription(offer.get());
4039 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004040 const RtpDataContentDescription* data_offer =
4041 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004042 ASSERT_TRUE(data_offer->cryptos().empty());
4043
4044 const cricket::TransportDescription* audio_offer_trans_desc =
4045 offer->GetTransportDescriptionByName("audio");
4046 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
4047 const cricket::TransportDescription* video_offer_trans_desc =
4048 offer->GetTransportDescriptionByName("video");
4049 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
4050 const cricket::TransportDescription* data_offer_trans_desc =
4051 offer->GetTransportDescriptionByName("data");
4052 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
4053
4054 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004055 std::unique_ptr<SessionDescription> answer =
4056 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004057 ASSERT_TRUE(answer.get() != NULL);
4058
4059 const cricket::TransportDescription* audio_answer_trans_desc =
4060 answer->GetTransportDescriptionByName("audio");
4061 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
4062 const cricket::TransportDescription* video_answer_trans_desc =
4063 answer->GetTransportDescriptionByName("video");
4064 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
4065 const cricket::TransportDescription* data_answer_trans_desc =
4066 answer->GetTransportDescriptionByName("data");
4067 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
4068}
4069
4070// Verifies if vad_enabled option is set to false, CN codecs are not present in
4071// offer or answer.
4072TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
4073 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004074 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004075 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004076 ASSERT_TRUE(offer.get() != NULL);
4077 const ContentInfo* audio_content = offer->GetContentByName("audio");
4078 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
4079
4080 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08004081 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004082 ASSERT_TRUE(offer.get() != NULL);
4083 audio_content = offer->GetContentByName("audio");
4084 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08004085 std::unique_ptr<SessionDescription> answer =
4086 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004087 ASSERT_TRUE(answer.get() != NULL);
4088 audio_content = answer->GetContentByName("audio");
4089 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
4090}
deadbeef44f08192015-12-15 16:20:09 -08004091
zhihuang1c378ed2017-08-17 14:10:50 -07004092// Test that the generated MIDs match the existing offer.
4093TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08004094 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004095 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
4096 RtpTransceiverDirection::kRecvOnly, kActive,
4097 &opts);
4098 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
4099 RtpTransceiverDirection::kRecvOnly, kActive,
4100 &opts);
deadbeef44f08192015-12-15 16:20:09 -08004101 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004102 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
4103 RtpTransceiverDirection::kSendRecv, kActive,
4104 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004105 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004106 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08004107 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08004108 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07004109
deadbeef44f08192015-12-15 16:20:09 -08004110 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
4111 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
4112 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
4113 ASSERT_TRUE(audio_content != nullptr);
4114 ASSERT_TRUE(video_content != nullptr);
4115 ASSERT_TRUE(data_content != nullptr);
4116 EXPECT_EQ("audio_modified", audio_content->name);
4117 EXPECT_EQ("video_modified", video_content->name);
4118 EXPECT_EQ("data_modified", data_content->name);
4119}
zhihuangcf5b37c2016-05-05 11:44:35 -07004120
zhihuang1c378ed2017-08-17 14:10:50 -07004121// The following tests verify that the unified plan SDP is supported.
4122// Test that we can create an offer with multiple media sections of same media
4123// type.
4124TEST_F(MediaSessionDescriptionFactoryTest,
4125 CreateOfferWithMultipleAVMediaSections) {
4126 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004127 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4128 RtpTransceiverDirection::kSendRecv, kActive,
4129 &opts);
4130 AttachSenderToMediaDescriptionOptions(
4131 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004132
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004133 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4134 RtpTransceiverDirection::kSendRecv, kActive,
4135 &opts);
4136 AttachSenderToMediaDescriptionOptions(
4137 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004138
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004139 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4140 RtpTransceiverDirection::kSendRecv, kActive,
4141 &opts);
4142 AttachSenderToMediaDescriptionOptions(
4143 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004144
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004145 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4146 RtpTransceiverDirection::kSendRecv, kActive,
4147 &opts);
4148 AttachSenderToMediaDescriptionOptions(
4149 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004150 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004151 ASSERT_TRUE(offer);
4152
4153 ASSERT_EQ(4u, offer->contents().size());
4154 EXPECT_FALSE(offer->contents()[0].rejected);
4155 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004156 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004157 ASSERT_EQ(1u, acd->streams().size());
4158 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004159 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004160
4161 EXPECT_FALSE(offer->contents()[1].rejected);
4162 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004163 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004164 ASSERT_EQ(1u, vcd->streams().size());
4165 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004166 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004167
4168 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004169 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004170 ASSERT_EQ(1u, acd->streams().size());
4171 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004172 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004173
4174 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004175 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004176 ASSERT_EQ(1u, vcd->streams().size());
4177 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004178 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004179}
4180
4181// Test that we can create an answer with multiple media sections of same media
4182// type.
4183TEST_F(MediaSessionDescriptionFactoryTest,
4184 CreateAnswerWithMultipleAVMediaSections) {
4185 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004186 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4187 RtpTransceiverDirection::kSendRecv, kActive,
4188 &opts);
4189 AttachSenderToMediaDescriptionOptions(
4190 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004191
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004192 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4193 RtpTransceiverDirection::kSendRecv, kActive,
4194 &opts);
4195 AttachSenderToMediaDescriptionOptions(
4196 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004197
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004198 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4199 RtpTransceiverDirection::kSendRecv, kActive,
4200 &opts);
4201 AttachSenderToMediaDescriptionOptions(
4202 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004203
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004204 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4205 RtpTransceiverDirection::kSendRecv, kActive,
4206 &opts);
4207 AttachSenderToMediaDescriptionOptions(
4208 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004209
Steve Anton6fe1fba2018-12-11 10:15:23 -08004210 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004211 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004212 std::unique_ptr<SessionDescription> answer =
4213 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004214
4215 ASSERT_EQ(4u, answer->contents().size());
4216 EXPECT_FALSE(answer->contents()[0].rejected);
4217 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004218 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004219 ASSERT_EQ(1u, acd->streams().size());
4220 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004221 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004222
4223 EXPECT_FALSE(answer->contents()[1].rejected);
4224 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004225 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004226 ASSERT_EQ(1u, vcd->streams().size());
4227 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004228 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004229
4230 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004231 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004232 ASSERT_EQ(1u, acd->streams().size());
4233 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004234 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004235
4236 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004237 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004238 ASSERT_EQ(1u, vcd->streams().size());
4239 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004240 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004241}
4242
4243// Test that the media section will be rejected in offer if the corresponding
4244// MediaDescriptionOptions is stopped by the offerer.
4245TEST_F(MediaSessionDescriptionFactoryTest,
4246 CreateOfferWithMediaSectionStoppedByOfferer) {
4247 // Create an offer with two audio sections and one of them is stopped.
4248 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004249 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4250 RtpTransceiverDirection::kSendRecv, kActive,
4251 &offer_opts);
4252 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4253 RtpTransceiverDirection::kInactive, kStopped,
4254 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004255 std::unique_ptr<SessionDescription> offer =
4256 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004257 ASSERT_TRUE(offer);
4258 ASSERT_EQ(2u, offer->contents().size());
4259 EXPECT_FALSE(offer->contents()[0].rejected);
4260 EXPECT_TRUE(offer->contents()[1].rejected);
4261}
4262
4263// Test that the media section will be rejected in answer if the corresponding
4264// MediaDescriptionOptions is stopped by the offerer.
4265TEST_F(MediaSessionDescriptionFactoryTest,
4266 CreateAnswerWithMediaSectionStoppedByOfferer) {
4267 // Create an offer with two audio sections and one of them is stopped.
4268 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004269 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4270 RtpTransceiverDirection::kSendRecv, kActive,
4271 &offer_opts);
4272 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4273 RtpTransceiverDirection::kInactive, kStopped,
4274 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004275 std::unique_ptr<SessionDescription> offer =
4276 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004277 ASSERT_TRUE(offer);
4278 ASSERT_EQ(2u, offer->contents().size());
4279 EXPECT_FALSE(offer->contents()[0].rejected);
4280 EXPECT_TRUE(offer->contents()[1].rejected);
4281
4282 // Create an answer based on the offer.
4283 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004284 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4285 RtpTransceiverDirection::kSendRecv, kActive,
4286 &answer_opts);
4287 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4288 RtpTransceiverDirection::kSendRecv, kActive,
4289 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004290 std::unique_ptr<SessionDescription> answer =
4291 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004292 ASSERT_EQ(2u, answer->contents().size());
4293 EXPECT_FALSE(answer->contents()[0].rejected);
4294 EXPECT_TRUE(answer->contents()[1].rejected);
4295}
4296
4297// Test that the media section will be rejected in answer if the corresponding
4298// MediaDescriptionOptions is stopped by the answerer.
4299TEST_F(MediaSessionDescriptionFactoryTest,
4300 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4301 // Create an offer with two audio sections.
4302 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004303 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4304 RtpTransceiverDirection::kSendRecv, kActive,
4305 &offer_opts);
4306 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4307 RtpTransceiverDirection::kSendRecv, kActive,
4308 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004309 std::unique_ptr<SessionDescription> offer =
4310 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004311 ASSERT_TRUE(offer);
4312 ASSERT_EQ(2u, offer->contents().size());
4313 ASSERT_FALSE(offer->contents()[0].rejected);
4314 ASSERT_FALSE(offer->contents()[1].rejected);
4315
4316 // The answerer rejects one of the audio sections.
4317 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004318 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4319 RtpTransceiverDirection::kSendRecv, kActive,
4320 &answer_opts);
4321 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4322 RtpTransceiverDirection::kInactive, kStopped,
4323 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004324 std::unique_ptr<SessionDescription> answer =
4325 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004326 ASSERT_EQ(2u, answer->contents().size());
4327 EXPECT_FALSE(answer->contents()[0].rejected);
4328 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004329
4330 // The TransportInfo of the rejected m= section is expected to be added in the
4331 // answer.
4332 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004333}
4334
4335// Test the generated media sections has the same order of the
4336// corresponding MediaDescriptionOptions.
4337TEST_F(MediaSessionDescriptionFactoryTest,
4338 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4339 MediaSessionOptions opts;
4340 // This tests put video section first because normally audio comes first by
4341 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004342 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4343 RtpTransceiverDirection::kSendRecv, kActive,
4344 &opts);
4345 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4346 RtpTransceiverDirection::kSendRecv, kActive,
4347 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004348 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004349
4350 ASSERT_TRUE(offer);
4351 ASSERT_EQ(2u, offer->contents().size());
4352 EXPECT_EQ("video", offer->contents()[0].name);
4353 EXPECT_EQ("audio", offer->contents()[1].name);
4354}
4355
4356// Test that different media sections using the same codec have same payload
4357// type.
4358TEST_F(MediaSessionDescriptionFactoryTest,
4359 PayloadTypesSharedByMediaSectionsOfSameType) {
4360 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004361 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4362 RtpTransceiverDirection::kSendRecv, kActive,
4363 &opts);
4364 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4365 RtpTransceiverDirection::kSendRecv, kActive,
4366 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004367 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004368 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004369 ASSERT_TRUE(offer);
4370 ASSERT_EQ(2u, offer->contents().size());
4371 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004372 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004373 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004374 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004375 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4376 ASSERT_EQ(2u, vcd1->codecs().size());
4377 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4378 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4379 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4380 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4381
4382 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004383 std::unique_ptr<SessionDescription> answer =
4384 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004385 ASSERT_TRUE(answer);
4386 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004387 vcd1 = answer->contents()[0].media_description()->as_video();
4388 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004389 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4390 ASSERT_EQ(1u, vcd1->codecs().size());
4391 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4392 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4393}
4394
4395// Test that the codec preference order per media section is respected in
4396// subsequent offer.
4397TEST_F(MediaSessionDescriptionFactoryTest,
4398 CreateOfferRespectsCodecPreferenceOrder) {
4399 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004400 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4401 RtpTransceiverDirection::kSendRecv, kActive,
4402 &opts);
4403 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4404 RtpTransceiverDirection::kSendRecv, kActive,
4405 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004406 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004407 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004408 ASSERT_TRUE(offer);
4409 ASSERT_EQ(2u, offer->contents().size());
4410 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004411 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004412 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004413 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004414 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4415 EXPECT_EQ(video_codecs, vcd1->codecs());
4416 EXPECT_EQ(video_codecs, vcd2->codecs());
4417
4418 // Change the codec preference of the first video section and create a
4419 // follow-up offer.
4420 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4421 vcd1->set_codecs(video_codecs_reverse);
4422 std::unique_ptr<SessionDescription> updated_offer(
4423 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004424 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4425 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004426 // The video codec preference order should be respected.
4427 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4428 EXPECT_EQ(video_codecs, vcd2->codecs());
4429}
4430
4431// Test that the codec preference order per media section is respected in
4432// the answer.
4433TEST_F(MediaSessionDescriptionFactoryTest,
4434 CreateAnswerRespectsCodecPreferenceOrder) {
4435 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004436 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4437 RtpTransceiverDirection::kSendRecv, kActive,
4438 &opts);
4439 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4440 RtpTransceiverDirection::kSendRecv, kActive,
4441 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004442 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004443 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004444 ASSERT_TRUE(offer);
4445 ASSERT_EQ(2u, offer->contents().size());
4446 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004447 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004448 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004449 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004450 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4451 EXPECT_EQ(video_codecs, vcd1->codecs());
4452 EXPECT_EQ(video_codecs, vcd2->codecs());
4453
4454 // Change the codec preference of the first video section and create an
4455 // answer.
4456 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4457 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004458 std::unique_ptr<SessionDescription> answer =
4459 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004460 vcd1 = answer->contents()[0].media_description()->as_video();
4461 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004462 // The video codec preference order should be respected.
4463 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4464 EXPECT_EQ(video_codecs, vcd2->codecs());
4465}
4466
Zhi Huang6f367472017-11-22 13:20:02 -08004467// Test that when creating an answer, the codecs use local parameters instead of
4468// the remote ones.
4469TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4470 const std::string audio_param_name = "audio_param";
4471 const std::string audio_value1 = "audio_v1";
4472 const std::string audio_value2 = "audio_v2";
4473 const std::string video_param_name = "video_param";
4474 const std::string video_value1 = "video_v1";
4475 const std::string video_value2 = "video_v2";
4476
4477 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4478 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4479 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4480 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4481
4482 // Set the parameters for codecs.
4483 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4484 video_codecs1[0].SetParam(video_param_name, video_value1);
4485 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4486 video_codecs2[0].SetParam(video_param_name, video_value2);
4487
4488 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004489 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004490 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004491 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004492
4493 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004494 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4495 RtpTransceiverDirection::kSendRecv, kActive,
4496 &opts);
4497 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4498 RtpTransceiverDirection::kSendRecv, kActive,
4499 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004500
Steve Anton6fe1fba2018-12-11 10:15:23 -08004501 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004502 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004503 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4504 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004505 std::string value;
4506 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4507 EXPECT_EQ(audio_value1, value);
4508 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4509 EXPECT_EQ(video_value1, value);
4510
Steve Anton6fe1fba2018-12-11 10:15:23 -08004511 std::unique_ptr<SessionDescription> answer =
4512 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004513 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004514 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4515 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004516 // Use the parameters from the local codecs.
4517 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4518 EXPECT_EQ(audio_value2, value);
4519 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4520 EXPECT_EQ(video_value2, value);
4521}
4522
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004523// Test that matching packetization-mode is part of the criteria for matching
4524// H264 codecs (in addition to profile-level-id). Previously, this was not the
4525// case, so the first H264 codec with the same profile-level-id would match and
4526// the payload type in the answer would be incorrect.
4527// This is a regression test for bugs.webrtc.org/8808
4528TEST_F(MediaSessionDescriptionFactoryTest,
4529 H264MatchCriteriaIncludesPacketizationMode) {
4530 // Create two H264 codecs with the same profile level ID and different
4531 // packetization modes.
4532 VideoCodec h264_pm0(96, "H264");
4533 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4534 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4535 VideoCodec h264_pm1(97, "H264");
4536 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4537 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4538
4539 // Offerer will send both codecs, answerer should choose the one with matching
4540 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004541 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4542 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004543
4544 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004545 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4546 RtpTransceiverDirection::kSendRecv, kActive,
4547 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004548
Steve Anton6fe1fba2018-12-11 10:15:23 -08004549 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004550 ASSERT_TRUE(offer);
4551
Steve Anton6fe1fba2018-12-11 10:15:23 -08004552 std::unique_ptr<SessionDescription> answer =
4553 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004554 ASSERT_TRUE(answer);
4555
4556 // Answer should have one negotiated codec with packetization-mode=1 using the
4557 // offered payload type.
4558 ASSERT_EQ(1u, answer->contents().size());
4559 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4560 ASSERT_EQ(1u, answer_vcd->codecs().size());
4561 auto answer_codec = answer_vcd->codecs()[0];
4562 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4563}
4564
zhihuangcf5b37c2016-05-05 11:44:35 -07004565class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4566 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004567 MediaProtocolTest()
4568 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004569 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4570 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004571 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4572 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004573 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004574 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4575 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004576 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4577 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004578 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004579 f1_.set_secure(SEC_ENABLED);
4580 f2_.set_secure(SEC_ENABLED);
4581 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004582 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004583 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004584 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004585 tdf1_.set_secure(SEC_ENABLED);
4586 tdf2_.set_secure(SEC_ENABLED);
4587 }
4588
4589 protected:
4590 MediaSessionDescriptionFactory f1_;
4591 MediaSessionDescriptionFactory f2_;
4592 TransportDescriptionFactory tdf1_;
4593 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004594 UniqueRandomIdGenerator ssrc_generator1;
4595 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004596};
4597
4598TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4599 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004600 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004601 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004602 ASSERT_TRUE(offer.get() != nullptr);
4603 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004604 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004605 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004606 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004607 std::unique_ptr<SessionDescription> answer =
4608 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004609 const ContentInfo* ac = answer->GetContentByName("audio");
4610 const ContentInfo* vc = answer->GetContentByName("video");
4611 ASSERT_TRUE(ac != nullptr);
4612 ASSERT_TRUE(vc != nullptr);
4613 EXPECT_FALSE(ac->rejected); // the offer is accepted
4614 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004615 const AudioContentDescription* acd = ac->media_description()->as_audio();
4616 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004617 EXPECT_EQ(GetParam(), acd->protocol());
4618 EXPECT_EQ(GetParam(), vcd->protocol());
4619}
4620
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004621INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4622 MediaProtocolTest,
4623 ::testing::ValuesIn(kMediaProtocols));
4624INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4625 MediaProtocolTest,
4626 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004627
4628TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4629 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004630 UniqueRandomIdGenerator ssrc_generator;
4631 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004632 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4633 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4634
4635 // The merged list of codecs should contain any send codecs that are also
4636 // nominally in the recieve codecs list. Payload types should be picked from
4637 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4638 // (set to 1). This equals what happens when the send codecs are used in an
4639 // offer and the receive codecs are used in the following answer.
4640 const std::vector<AudioCodec> sendrecv_codecs =
4641 MAKE_VECTOR(kAudioCodecsAnswer);
4642 const std::vector<AudioCodec> no_codecs;
4643
4644 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4645 << "Please don't change shared test data!";
4646 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4647 << "Please don't change shared test data!";
4648 // Alter iLBC send codec to have zero channels, to test that that is handled
4649 // properly.
4650 send_codecs[1].channels = 0;
4651
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004652 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004653 // are handled properly.
4654 recv_codecs[2].name = "ilbc";
4655
4656 // Test proper merge
4657 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004658 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4659 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4660 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004661
4662 // Test empty send codecs list
4663 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004664 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4665 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4666 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004667
4668 // Test empty recv codecs list
4669 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004670 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4671 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4672 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004673
4674 // Test all empty codec lists
4675 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004676 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4677 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4678 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004679}
4680
4681namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004682// Compare the two vectors of codecs ignoring the payload type.
4683template <class Codec>
4684bool CodecsMatch(const std::vector<Codec>& codecs1,
4685 const std::vector<Codec>& codecs2) {
4686 if (codecs1.size() != codecs2.size()) {
4687 return false;
4688 }
4689
4690 for (size_t i = 0; i < codecs1.size(); ++i) {
4691 if (!codecs1[i].Matches(codecs2[i])) {
4692 return false;
4693 }
4694 }
4695 return true;
4696}
4697
Steve Anton4e70a722017-11-28 14:57:10 -08004698void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004699 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004700 UniqueRandomIdGenerator ssrc_generator;
4701 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004702 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4703 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4704 const std::vector<AudioCodec> sendrecv_codecs =
4705 MAKE_VECTOR(kAudioCodecsAnswer);
4706 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004707
4708 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004709 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4710 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004711
Steve Anton4e70a722017-11-28 14:57:10 -08004712 if (direction == RtpTransceiverDirection::kSendRecv ||
4713 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004714 AttachSenderToMediaDescriptionOptions(
4715 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004716 }
ossu075af922016-06-14 03:29:38 -07004717
Steve Anton6fe1fba2018-12-11 10:15:23 -08004718 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004719 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004720 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004721
4722 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004723 // that the codecs put in are right. This happens when we neither want to
4724 // send nor receive audio. The checks are still in place if at some point
4725 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004726 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004727 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004728 // sendrecv and inactive should both present lists as if the channel was
4729 // to be used for sending and receiving. Inactive essentially means it
4730 // might eventually be used anything, but we don't know more at this
4731 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004732 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004733 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004734 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004735 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004736 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004737 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004738 }
4739 }
4740}
4741
4742static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004743 AudioCodec(0, "codec0", 16000, -1, 1),
4744 AudioCodec(1, "codec1", 8000, 13300, 1),
4745 AudioCodec(2, "codec2", 8000, 64000, 1),
4746 AudioCodec(3, "codec3", 8000, 64000, 1),
4747 AudioCodec(4, "codec4", 8000, 0, 2),
4748 AudioCodec(5, "codec5", 32000, 0, 1),
4749 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004750
zhihuang1c378ed2017-08-17 14:10:50 -07004751/* The codecs groups below are chosen as per the matrix below. The objective
4752 * is to have different sets of codecs in the inputs, to get unique sets of
4753 * codecs after negotiation, depending on offer and answer communication
4754 * directions. One-way directions in the offer should either result in the
4755 * opposite direction in the answer, or an inactive answer. Regardless, the
4756 * choice of codecs should be as if the answer contained the opposite
4757 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004758 *
4759 * | Offer | Answer | Result
4760 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4761 * 0 | x - - | - x - | x - - - -
4762 * 1 | x x x | - x - | x - - x -
4763 * 2 | - x - | x - - | - x - - -
4764 * 3 | x x x | x - - | - x x - -
4765 * 4 | - x - | x x x | - x - - -
4766 * 5 | x - - | x x x | x - - - -
4767 * 6 | x x x | x x x | x x x x x
4768 */
4769// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004770static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4771static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004772// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4773// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004774static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4775static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004776// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004777static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4778static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4779static const int kResultSendrecv_SendCodecs[] = {3, 6};
4780static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4781static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004782
4783template <typename T, int IDXS>
4784std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4785 std::vector<T> out;
4786 out.reserve(IDXS);
4787 for (int idx : indices)
4788 out.push_back(array[idx]);
4789
4790 return out;
4791}
4792
Steve Anton4e70a722017-11-28 14:57:10 -08004793void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4794 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004795 bool add_legacy_stream) {
4796 TransportDescriptionFactory offer_tdf;
4797 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004798 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4799 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4800 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004801 offer_factory.set_audio_codecs(
4802 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4803 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4804 answer_factory.set_audio_codecs(
4805 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4806 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4807
ossu075af922016-06-14 03:29:38 -07004808 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004809 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4810 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004811
Steve Anton4e70a722017-11-28 14:57:10 -08004812 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004813 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4814 kAudioTrack1, {kMediaStream1}, 1,
4815 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004816 }
4817
Steve Anton6fe1fba2018-12-11 10:15:23 -08004818 std::unique_ptr<SessionDescription> offer =
4819 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004820 ASSERT_TRUE(offer.get() != NULL);
4821
4822 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004823 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4824 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004825
Steve Anton4e70a722017-11-28 14:57:10 -08004826 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004827 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4828 kAudioTrack1, {kMediaStream1}, 1,
4829 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004830 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004831 std::unique_ptr<SessionDescription> answer =
4832 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004833 const ContentInfo* ac = answer->GetContentByName("audio");
4834
zhihuang1c378ed2017-08-17 14:10:50 -07004835 // If the factory didn't add any audio content to the answer, we cannot
4836 // check that the codecs put in are right. This happens when we neither want
4837 // to send nor receive audio. The checks are still in place if at some point
4838 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004839 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004840 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4841 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004842
ossu075af922016-06-14 03:29:38 -07004843 std::vector<AudioCodec> target_codecs;
4844 // For offers with sendrecv or inactive, we should never reply with more
4845 // codecs than offered, with these codec sets.
4846 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004847 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004848 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4849 kResultSendrecv_SendrecvCodecs);
4850 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004851 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004852 target_codecs =
4853 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004854 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004855 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004856 target_codecs =
4857 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004858 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004859 case RtpTransceiverDirection::kSendRecv:
4860 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004861 target_codecs =
4862 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004863 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004864 target_codecs =
4865 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004866 } else {
4867 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4868 kResultSendrecv_SendrecvCodecs);
4869 }
4870 break;
Harald Alvestrand6060df52020-08-11 09:54:02 +02004871 case RtpTransceiverDirection::kStopped:
4872 // This does not happen in any current test.
Markus Handell45c104b2020-03-11 10:51:13 +01004873 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004874 }
4875
zhihuang1c378ed2017-08-17 14:10:50 -07004876 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004877 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004878 bool first = true;
4879 os << "{";
4880 for (const auto& c : codecs) {
4881 os << (first ? " " : ", ") << c.id;
4882 first = false;
4883 }
4884 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004885 return os.Release();
ossu075af922016-06-14 03:29:38 -07004886 };
4887
4888 EXPECT_TRUE(acd->codecs() == target_codecs)
4889 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004890 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4891 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004892 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004893 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4894 << "; got: "
4895 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004896 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004897 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004898 << "Only inactive offers are allowed to not generate any audio "
4899 "content";
ossu075af922016-06-14 03:29:38 -07004900 }
4901}
brandtr03d5fb12016-11-22 03:37:59 -08004902
4903} // namespace
ossu075af922016-06-14 03:29:38 -07004904
4905class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004906 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004907
4908TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004909 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004910}
4911
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004912INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4913 AudioCodecsOfferTest,
4914 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4915 RtpTransceiverDirection::kRecvOnly,
4916 RtpTransceiverDirection::kSendRecv,
4917 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004918
4919class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004920 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4921 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004922 bool>> {};
ossu075af922016-06-14 03:29:38 -07004923
4924TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004925 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4926 ::testing::get<1>(GetParam()),
4927 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004928}
4929
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004930INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004931 MediaSessionDescriptionFactoryTest,
4932 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004933 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4934 RtpTransceiverDirection::kRecvOnly,
4935 RtpTransceiverDirection::kSendRecv,
4936 RtpTransceiverDirection::kInactive),
4937 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4938 RtpTransceiverDirection::kRecvOnly,
4939 RtpTransceiverDirection::kSendRecv,
4940 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004941 ::testing::Bool()));