blob: 940d746e5f2c7988108a6b8c5624e2e083a0d924 [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,
Emil Lundmark801c9992021-01-19 13:06:32 +01002350 OfferAndAnswerDoesNotHaveMixedByteSessionAttribute) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002351 MediaSessionOptions opts;
Emil Lundmark801c9992021-01-19 13:06:32 +01002352 std::unique_ptr<SessionDescription> offer =
2353 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002354 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002355
Emil Lundmark801c9992021-01-19 13:06:32 +01002356 std::unique_ptr<SessionDescription> answer(
2357 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2358
2359 EXPECT_FALSE(answer->extmap_allow_mixed());
2360}
2361
2362TEST_F(MediaSessionDescriptionFactoryTest,
2363 OfferAndAnswerHaveMixedByteSessionAttribute) {
2364 MediaSessionOptions opts;
2365 std::unique_ptr<SessionDescription> offer =
2366 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002367 offer->set_extmap_allow_mixed(true);
Emil Lundmark801c9992021-01-19 13:06:32 +01002368
Johannes Kron0854eb62018-10-10 22:33:20 +02002369 std::unique_ptr<SessionDescription> answer_support(
Emil Lundmark801c9992021-01-19 13:06:32 +01002370 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2371
Johannes Kron9581bc42018-10-23 10:17:39 +02002372 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002373}
2374
2375TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002376 OfferAndAnswerDoesNotHaveMixedByteMediaAttributes) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002377 MediaSessionOptions opts;
2378 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Emil Lundmark801c9992021-01-19 13:06:32 +01002379 std::unique_ptr<SessionDescription> offer =
2380 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2381 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002382 MediaContentDescription* audio_offer =
2383 offer->GetContentDescriptionByName("audio");
Emil Lundmark801c9992021-01-19 13:06:32 +01002384 MediaContentDescription* video_offer =
2385 offer->GetContentDescriptionByName("video");
2386 ASSERT_EQ(MediaContentDescription::kNo,
2387 audio_offer->extmap_allow_mixed_enum());
2388 ASSERT_EQ(MediaContentDescription::kNo,
2389 video_offer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002390
Emil Lundmark801c9992021-01-19 13:06:32 +01002391 std::unique_ptr<SessionDescription> answer(
2392 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
Johannes Kron0854eb62018-10-10 22:33:20 +02002393
Johannes Kron0854eb62018-10-10 22:33:20 +02002394 MediaContentDescription* audio_answer =
Emil Lundmark801c9992021-01-19 13:06:32 +01002395 answer->GetContentDescriptionByName("audio");
2396 MediaContentDescription* video_answer =
2397 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002398 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002399 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002400 EXPECT_EQ(MediaContentDescription::kNo,
2401 video_answer->extmap_allow_mixed_enum());
2402}
Johannes Kron0854eb62018-10-10 22:33:20 +02002403
Emil Lundmark801c9992021-01-19 13:06:32 +01002404TEST_F(MediaSessionDescriptionFactoryTest,
2405 OfferAndAnswerHaveSameMixedByteMediaAttributes) {
2406 MediaSessionOptions opts;
2407 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2408 std::unique_ptr<SessionDescription> offer =
2409 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2410 offer->set_extmap_allow_mixed(false);
2411 MediaContentDescription* audio_offer =
2412 offer->GetContentDescriptionByName("audio");
Johannes Kron9581bc42018-10-23 10:17:39 +02002413 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Emil Lundmark801c9992021-01-19 13:06:32 +01002414 MediaContentDescription* video_offer =
2415 offer->GetContentDescriptionByName("video");
2416 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2417
2418 std::unique_ptr<SessionDescription> answer(
2419 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2420
2421 MediaContentDescription* audio_answer =
2422 answer->GetContentDescriptionByName("audio");
2423 MediaContentDescription* video_answer =
2424 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002425 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002426 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002427 EXPECT_EQ(MediaContentDescription::kMedia,
2428 video_answer->extmap_allow_mixed_enum());
2429}
2430
2431TEST_F(MediaSessionDescriptionFactoryTest,
2432 OfferAndAnswerHaveDifferentMixedByteMediaAttributes) {
2433 MediaSessionOptions opts;
2434 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2435 std::unique_ptr<SessionDescription> offer =
2436 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2437 offer->set_extmap_allow_mixed(false);
2438 MediaContentDescription* audio_offer =
2439 offer->GetContentDescriptionByName("audio");
2440 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2441 MediaContentDescription* video_offer =
2442 offer->GetContentDescriptionByName("video");
2443 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2444
2445 std::unique_ptr<SessionDescription> answer(
2446 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2447
2448 MediaContentDescription* audio_answer =
2449 answer->GetContentDescriptionByName("audio");
2450 MediaContentDescription* video_answer =
2451 answer->GetContentDescriptionByName("video");
2452 EXPECT_EQ(MediaContentDescription::kNo,
2453 audio_answer->extmap_allow_mixed_enum());
2454 EXPECT_EQ(MediaContentDescription::kMedia,
2455 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002456}
2457
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002458// Create an audio and video offer with:
2459// - one video track
2460// - two audio tracks
2461// - two data tracks
2462// and ensure it matches what we expect. Also updates the initial offer by
2463// adding a new video track and replaces one of the audio tracks.
2464TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2465 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002466 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002467 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2468 {kMediaStream1}, 1, &opts);
2469 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2470 {kMediaStream1}, 1, &opts);
2471 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2472 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002473
Steve Anton4e70a722017-11-28 14:57:10 -08002474 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002475 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2476 {kMediaStream1}, 1, &opts);
2477 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2478 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002479
2480 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002481 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002482
2483 ASSERT_TRUE(offer.get() != NULL);
2484 const ContentInfo* ac = offer->GetContentByName("audio");
2485 const ContentInfo* vc = offer->GetContentByName("video");
2486 const ContentInfo* dc = offer->GetContentByName("data");
2487 ASSERT_TRUE(ac != NULL);
2488 ASSERT_TRUE(vc != NULL);
2489 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002490 const AudioContentDescription* acd = ac->media_description()->as_audio();
2491 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002492 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002493 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002494 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002495
2496 const StreamParamsVec& audio_streams = acd->streams();
2497 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002498 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002499 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2500 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2501 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2502 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2503 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2504 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2505
2506 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2507 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002508 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002509
2510 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002511 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002512 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002513
2514 const StreamParamsVec& video_streams = vcd->streams();
2515 ASSERT_EQ(1U, video_streams.size());
2516 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2517 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2518 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2519 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2520
2521 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002522 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002523 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002524
2525 const StreamParamsVec& data_streams = dcd->streams();
2526 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002527 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2529 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2530 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2531 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2532 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2533 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2534
Philipp Hanckeafee7082020-10-22 11:55:58 +02002535 EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002536 dcd->bandwidth()); // default bandwidth (auto)
2537 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002538 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002539
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002540 // Update the offer. Add a new video track that is not synched to the
2541 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002542 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2543 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002544 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002545 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2546 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002547 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002548 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2549 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002550 std::unique_ptr<SessionDescription> updated_offer(
2551 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002552
2553 ASSERT_TRUE(updated_offer.get() != NULL);
2554 ac = updated_offer->GetContentByName("audio");
2555 vc = updated_offer->GetContentByName("video");
2556 dc = updated_offer->GetContentByName("data");
2557 ASSERT_TRUE(ac != NULL);
2558 ASSERT_TRUE(vc != NULL);
2559 ASSERT_TRUE(dc != NULL);
2560 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002561 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002562 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002563 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002564 const RtpDataContentDescription* updated_dcd =
2565 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002566
2567 EXPECT_EQ(acd->type(), updated_acd->type());
2568 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2569 EXPECT_EQ(vcd->type(), updated_vcd->type());
2570 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2571 EXPECT_EQ(dcd->type(), updated_dcd->type());
2572 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002573 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002574 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002575 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002576 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002577 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002578 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2579
2580 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2581 ASSERT_EQ(2U, updated_audio_streams.size());
2582 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2583 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2584 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2585 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2586 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2587
2588 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2589 ASSERT_EQ(2U, updated_video_streams.size());
2590 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2591 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002592 // All the media streams in one PeerConnection share one RTCP CNAME.
2593 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002594
2595 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2596 ASSERT_EQ(2U, updated_data_streams.size());
2597 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2598 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2599 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2600 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2601 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002602 // The stream correctly got the CNAME from the MediaSessionOptions.
2603 // The Expected RTCP CNAME is the default one as we are using the default
2604 // MediaSessionOptions.
2605 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002606}
2607
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002608// Create an offer with simulcast video stream.
2609TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2610 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002611 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2612 RtpTransceiverDirection::kRecvOnly, kActive,
2613 &opts);
2614 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2615 RtpTransceiverDirection::kSendRecv, kActive,
2616 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002617 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002618 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2619 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002620 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002621
2622 ASSERT_TRUE(offer.get() != NULL);
2623 const ContentInfo* vc = offer->GetContentByName("video");
2624 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002625 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002626
2627 const StreamParamsVec& video_streams = vcd->streams();
2628 ASSERT_EQ(1U, video_streams.size());
2629 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2630 const SsrcGroup* sim_ssrc_group =
2631 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2632 ASSERT_TRUE(sim_ssrc_group != NULL);
2633 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2634}
2635
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002636MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2637 const RidDescription& rid1 = ::testing::get<0>(arg);
2638 const RidDescription& rid2 = ::testing::get<1>(arg);
2639 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2640}
2641
2642static void CheckSimulcastInSessionDescription(
2643 const SessionDescription* description,
2644 const std::string& content_name,
2645 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002646 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002647 ASSERT_NE(description, nullptr);
2648 const ContentInfo* content = description->GetContentByName(content_name);
2649 ASSERT_NE(content, nullptr);
2650 const MediaContentDescription* cd = content->media_description();
2651 ASSERT_NE(cd, nullptr);
2652 const StreamParamsVec& streams = cd->streams();
2653 ASSERT_THAT(streams, SizeIs(1));
2654 const StreamParams& stream = streams[0];
2655 ASSERT_THAT(stream.ssrcs, IsEmpty());
2656 EXPECT_TRUE(stream.has_rids());
2657 const std::vector<RidDescription> rids = stream.rids();
2658
2659 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2660
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002661 EXPECT_TRUE(cd->HasSimulcast());
2662 const SimulcastDescription& simulcast = cd->simulcast_description();
2663 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2664 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2665
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002666 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002667}
2668
2669// Create an offer with spec-compliant simulcast video stream.
2670TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2671 MediaSessionOptions opts;
2672 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2673 RtpTransceiverDirection::kSendRecv, kActive,
2674 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002675 std::vector<RidDescription> send_rids;
2676 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2677 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2678 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2679 SimulcastLayerList simulcast_layers;
2680 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2681 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2682 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2683 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2684 {kMediaStream1}, send_rids,
2685 simulcast_layers, 0, &opts);
2686 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2687
2688 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002689 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002690}
2691
2692// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2693// In this scenario, RIDs do not need to be negotiated (there is only one).
2694TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2695 MediaSessionOptions opts;
2696 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2697 RtpTransceiverDirection::kSendRecv, kActive,
2698 &opts);
2699 RidDescription rid("f", RidDirection::kSend);
2700 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2701 {kMediaStream1}, {rid},
2702 SimulcastLayerList(), 0, &opts);
2703 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2704
2705 ASSERT_NE(offer.get(), nullptr);
2706 const ContentInfo* content = offer->GetContentByName("video");
2707 ASSERT_NE(content, nullptr);
2708 const MediaContentDescription* cd = content->media_description();
2709 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002710 const StreamParamsVec& streams = cd->streams();
2711 ASSERT_THAT(streams, SizeIs(1));
2712 const StreamParams& stream = streams[0];
2713 ASSERT_THAT(stream.ssrcs, IsEmpty());
2714 EXPECT_FALSE(stream.has_rids());
2715 EXPECT_FALSE(cd->HasSimulcast());
2716}
2717
2718// Create an answer with spec-compliant simulcast video stream.
2719// In this scenario, the SFU is the caller requesting that we send Simulcast.
2720TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2721 MediaSessionOptions offer_opts;
2722 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2723 RtpTransceiverDirection::kSendRecv, kActive,
2724 &offer_opts);
2725 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2726 {kMediaStream1}, 1, &offer_opts);
2727 std::unique_ptr<SessionDescription> offer =
2728 f1_.CreateOffer(offer_opts, nullptr);
2729
2730 MediaSessionOptions answer_opts;
2731 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2732 RtpTransceiverDirection::kSendRecv, kActive,
2733 &answer_opts);
2734
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002735 std::vector<RidDescription> rid_descriptions{
2736 RidDescription("f", RidDirection::kSend),
2737 RidDescription("h", RidDirection::kSend),
2738 RidDescription("q", RidDirection::kSend),
2739 };
2740 SimulcastLayerList simulcast_layers;
2741 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2742 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2743 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2744 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2745 {kMediaStream1}, rid_descriptions,
2746 simulcast_layers, 0, &answer_opts);
2747 std::unique_ptr<SessionDescription> answer =
2748 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2749
2750 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002751 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002752}
2753
2754// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2755// In this scenario, RIDs do not need to be negotiated (there is only one).
2756// Note that RID Direction is not the same as the transceiver direction.
2757TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2758 MediaSessionOptions offer_opts;
2759 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2760 RtpTransceiverDirection::kSendRecv, kActive,
2761 &offer_opts);
2762 RidDescription rid_offer("f", RidDirection::kSend);
2763 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2764 {kMediaStream1}, {rid_offer},
2765 SimulcastLayerList(), 0, &offer_opts);
2766 std::unique_ptr<SessionDescription> offer =
2767 f1_.CreateOffer(offer_opts, nullptr);
2768
2769 MediaSessionOptions answer_opts;
2770 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2771 RtpTransceiverDirection::kSendRecv, kActive,
2772 &answer_opts);
2773
2774 RidDescription rid_answer("f", RidDirection::kReceive);
2775 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2776 {kMediaStream1}, {rid_answer},
2777 SimulcastLayerList(), 0, &answer_opts);
2778 std::unique_ptr<SessionDescription> answer =
2779 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2780
2781 ASSERT_NE(answer.get(), nullptr);
2782 const ContentInfo* content = offer->GetContentByName("video");
2783 ASSERT_NE(content, nullptr);
2784 const MediaContentDescription* cd = content->media_description();
2785 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002786 const StreamParamsVec& streams = cd->streams();
2787 ASSERT_THAT(streams, SizeIs(1));
2788 const StreamParams& stream = streams[0];
2789 ASSERT_THAT(stream.ssrcs, IsEmpty());
2790 EXPECT_FALSE(stream.has_rids());
2791 EXPECT_FALSE(cd->HasSimulcast());
2792}
2793
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002794// Create an audio and video answer to a standard video offer with:
2795// - one video track
2796// - two audio tracks
2797// - two data tracks
2798// and ensure it matches what we expect. Also updates the initial answer by
2799// adding a new video track and removes one of the audio tracks.
2800TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2801 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002802 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2803 RtpTransceiverDirection::kRecvOnly, kActive,
2804 &offer_opts);
2805 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2806 RtpTransceiverDirection::kRecvOnly, kActive,
2807 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002808 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002809 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2810 RtpTransceiverDirection::kRecvOnly, kActive,
2811 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002812 f1_.set_secure(SEC_ENABLED);
2813 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002814 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002815
zhihuang1c378ed2017-08-17 14:10:50 -07002816 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002817 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2818 RtpTransceiverDirection::kSendRecv, kActive,
2819 &answer_opts);
2820 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2821 RtpTransceiverDirection::kSendRecv, kActive,
2822 &answer_opts);
2823 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2824 {kMediaStream1}, 1, &answer_opts);
2825 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2826 {kMediaStream1}, 1, &answer_opts);
2827 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2828 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002829
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002830 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2831 RtpTransceiverDirection::kSendRecv, kActive,
2832 &answer_opts);
2833 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2834 {kMediaStream1}, 1, &answer_opts);
2835 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2836 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002837 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002838
Steve Anton6fe1fba2018-12-11 10:15:23 -08002839 std::unique_ptr<SessionDescription> answer =
2840 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002841
2842 ASSERT_TRUE(answer.get() != NULL);
2843 const ContentInfo* ac = answer->GetContentByName("audio");
2844 const ContentInfo* vc = answer->GetContentByName("video");
2845 const ContentInfo* dc = answer->GetContentByName("data");
2846 ASSERT_TRUE(ac != NULL);
2847 ASSERT_TRUE(vc != NULL);
2848 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002849 const AudioContentDescription* acd = ac->media_description()->as_audio();
2850 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002851 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002852 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2853 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2854 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002855
2856 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002857 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002858
2859 const StreamParamsVec& audio_streams = acd->streams();
2860 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002861 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002862 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2863 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2864 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2865 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2866 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2867 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2868
2869 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2870 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2871
2872 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002873 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874
2875 const StreamParamsVec& video_streams = vcd->streams();
2876 ASSERT_EQ(1U, video_streams.size());
2877 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2878 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2879 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2880 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2881
2882 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002883 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002884
2885 const StreamParamsVec& data_streams = dcd->streams();
2886 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002887 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002888 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2889 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2890 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2891 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2892 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2893 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2894
Philipp Hanckeafee7082020-10-22 11:55:58 +02002895 EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002896 dcd->bandwidth()); // default bandwidth (auto)
2897 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002898
2899 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002900 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002901 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2902 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002903 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2904 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002905 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002906 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002907
2908 ASSERT_TRUE(updated_answer.get() != NULL);
2909 ac = updated_answer->GetContentByName("audio");
2910 vc = updated_answer->GetContentByName("video");
2911 dc = updated_answer->GetContentByName("data");
2912 ASSERT_TRUE(ac != NULL);
2913 ASSERT_TRUE(vc != NULL);
2914 ASSERT_TRUE(dc != NULL);
2915 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002916 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002917 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002918 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002919 const RtpDataContentDescription* updated_dcd =
2920 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002921
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002922 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002923 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002924 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002925 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002926 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002927 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2928
2929 EXPECT_EQ(acd->type(), updated_acd->type());
2930 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2931 EXPECT_EQ(vcd->type(), updated_vcd->type());
2932 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2933 EXPECT_EQ(dcd->type(), updated_dcd->type());
2934 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2935
2936 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2937 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002938 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002939
2940 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2941 ASSERT_EQ(2U, updated_video_streams.size());
2942 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2943 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002944 // All media streams in one PeerConnection share one CNAME.
2945 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002946
2947 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2948 ASSERT_EQ(1U, updated_data_streams.size());
2949 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2950}
2951
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002952// Create an updated offer after creating an answer to the original offer and
2953// verify that the codecs that were part of the original answer are not changed
2954// in the updated offer.
2955TEST_F(MediaSessionDescriptionFactoryTest,
2956 RespondentCreatesOfferAfterCreatingAnswer) {
2957 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002958 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002959
Steve Anton6fe1fba2018-12-11 10:15:23 -08002960 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2961 std::unique_ptr<SessionDescription> answer =
2962 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002963
2964 const AudioContentDescription* acd =
2965 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002966 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002967
2968 const VideoContentDescription* vcd =
2969 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002970 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002971
kwiberg31022942016-03-11 14:18:21 -08002972 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002973 f2_.CreateOffer(opts, answer.get()));
2974
2975 // The expected audio codecs are the common audio codecs from the first
2976 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2977 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002978 // TODO(wu): |updated_offer| should not include the codec
2979 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002981 kAudioCodecsAnswer[0],
2982 kAudioCodecsAnswer[1],
2983 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002984 };
2985
2986 // The expected video codecs are the common video codecs from the first
2987 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2988 // preference order.
2989 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002990 kVideoCodecsAnswer[0],
2991 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002992 };
2993
2994 const AudioContentDescription* updated_acd =
2995 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002996 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002997
2998 const VideoContentDescription* updated_vcd =
2999 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003000 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003001}
3002
Steve Anton5c72e712018-12-10 14:25:30 -08003003// Test that a reoffer does not reuse audio codecs from a previous media section
3004// that is being recycled.
3005TEST_F(MediaSessionDescriptionFactoryTest,
3006 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02003007 f1_.set_video_codecs({}, {});
3008 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08003009
3010 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003011 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
3012 RtpTransceiverDirection::kSendRecv, kActive,
3013 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003014 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
3015 std::unique_ptr<SessionDescription> answer =
3016 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08003017
3018 // Recycle the media section by changing its mid.
3019 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08003020 std::unique_ptr<SessionDescription> reoffer =
3021 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003022
3023 // Expect that the results of the first negotiation are ignored. If the m=
3024 // section was not recycled the payload types would match the initial offerer.
3025 const AudioContentDescription* acd =
3026 GetFirstAudioContentDescription(reoffer.get());
3027 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
3028}
3029
3030// Test that a reoffer does not reuse video codecs from a previous media section
3031// that is being recycled.
3032TEST_F(MediaSessionDescriptionFactoryTest,
3033 ReOfferDoesNotReUseRecycledVideoCodecs) {
3034 f1_.set_audio_codecs({}, {});
3035 f2_.set_audio_codecs({}, {});
3036
3037 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003038 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
3039 RtpTransceiverDirection::kSendRecv, kActive,
3040 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003041 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
3042 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08003043
3044 // Recycle the media section by changing its mid.
3045 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08003046 std::unique_ptr<SessionDescription> reoffer =
3047 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003048
3049 // Expect that the results of the first negotiation are ignored. If the m=
3050 // section was not recycled the payload types would match the initial offerer.
3051 const VideoContentDescription* vcd =
3052 GetFirstVideoContentDescription(reoffer.get());
3053 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
3054}
3055
3056// Test that a reanswer does not reuse audio codecs from a previous media
3057// section that is being recycled.
3058TEST_F(MediaSessionDescriptionFactoryTest,
3059 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02003060 f1_.set_video_codecs({}, {});
3061 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08003062
3063 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
3064 // second offer/answer is forward (|f1_| as offerer).
3065 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003066 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
3067 RtpTransceiverDirection::kSendRecv, kActive,
3068 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003069 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
3070 std::unique_ptr<SessionDescription> answer =
3071 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08003072
3073 // Recycle the media section by changing its mid.
3074 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08003075 std::unique_ptr<SessionDescription> reoffer =
3076 f1_.CreateOffer(opts, answer.get());
3077 std::unique_ptr<SessionDescription> reanswer =
3078 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003079
3080 // Expect that the results of the first negotiation are ignored. If the m=
3081 // section was not recycled the payload types would match the initial offerer.
3082 const AudioContentDescription* acd =
3083 GetFirstAudioContentDescription(reanswer.get());
3084 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
3085}
3086
3087// Test that a reanswer does not reuse video codecs from a previous media
3088// section that is being recycled.
3089TEST_F(MediaSessionDescriptionFactoryTest,
3090 ReAnswerDoesNotReUseRecycledVideoCodecs) {
3091 f1_.set_audio_codecs({}, {});
3092 f2_.set_audio_codecs({}, {});
3093
3094 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
3095 // second offer/answer is forward (|f1_| as offerer).
3096 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003097 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
3098 RtpTransceiverDirection::kSendRecv, kActive,
3099 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003100 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
3101 std::unique_ptr<SessionDescription> answer =
3102 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08003103
3104 // Recycle the media section by changing its mid.
3105 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08003106 std::unique_ptr<SessionDescription> reoffer =
3107 f1_.CreateOffer(opts, answer.get());
3108 std::unique_ptr<SessionDescription> reanswer =
3109 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003110
3111 // Expect that the results of the first negotiation are ignored. If the m=
3112 // section was not recycled the payload types would match the initial offerer.
3113 const VideoContentDescription* vcd =
3114 GetFirstVideoContentDescription(reanswer.get());
3115 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
3116}
3117
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003118// Create an updated offer after creating an answer to the original offer and
3119// verify that the codecs that were part of the original answer are not changed
3120// in the updated offer. In this test Rtx is enabled.
3121TEST_F(MediaSessionDescriptionFactoryTest,
3122 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
3123 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003124 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3125 RtpTransceiverDirection::kRecvOnly, kActive,
3126 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003127 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003128 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003129 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003130 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003131
3132 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003133 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003134 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003135 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003136
Steve Anton6fe1fba2018-12-11 10:15:23 -08003137 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003138 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003139 std::unique_ptr<SessionDescription> answer =
3140 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003141
3142 const VideoContentDescription* vcd =
3143 GetFirstVideoContentDescription(answer.get());
3144
3145 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003146 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3147 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003148
3149 EXPECT_EQ(expected_codecs, vcd->codecs());
3150
deadbeef67cf2c12016-04-13 10:07:16 -07003151 // Now, make sure we get same result (except for the order) if |f2_| creates
3152 // an updated offer even though the default payload types between |f1_| and
3153 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08003154 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003155 f2_.CreateOffer(opts, answer.get()));
3156 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003157 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003158 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3159
3160 const VideoContentDescription* updated_vcd =
3161 GetFirstVideoContentDescription(updated_answer.get());
3162
3163 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3164}
3165
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003166// Regression test for:
3167// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
3168// Existing codecs should always appear before new codecs in re-offers. But
3169// under a specific set of circumstances, the existing RTX codec was ending up
3170// added to the end of the list.
3171TEST_F(MediaSessionDescriptionFactoryTest,
3172 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
3173 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003174 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3175 RtpTransceiverDirection::kRecvOnly, kActive,
3176 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003177 // We specifically choose different preferred payload types for VP8 to
3178 // trigger the issue.
3179 cricket::VideoCodec vp8_offerer(100, "VP8");
3180 cricket::VideoCodec vp8_offerer_rtx =
3181 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
3182 cricket::VideoCodec vp8_answerer(110, "VP8");
3183 cricket::VideoCodec vp8_answerer_rtx =
3184 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
3185 cricket::VideoCodec vp9(120, "VP9");
3186 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
3187
3188 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
3189 // We also specifically cause the answerer to prefer VP9, such that if it
3190 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
3191 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
3192 vp8_answerer_rtx};
3193
Johannes Kron3e983682020-03-29 22:17:00 +02003194 f1_.set_video_codecs(f1_codecs, f1_codecs);
3195 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003196 std::vector<AudioCodec> audio_codecs;
3197 f1_.set_audio_codecs(audio_codecs, audio_codecs);
3198 f2_.set_audio_codecs(audio_codecs, audio_codecs);
3199
3200 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003201 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003202 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003203 std::unique_ptr<SessionDescription> answer =
3204 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003205
3206 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
3207 // But if the bug is triggered, RTX for VP8 ends up last.
3208 std::unique_ptr<SessionDescription> updated_offer(
3209 f2_.CreateOffer(opts, answer.get()));
3210
3211 const VideoContentDescription* vcd =
3212 GetFirstVideoContentDescription(updated_offer.get());
3213 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
3214 ASSERT_EQ(4u, codecs.size());
3215 EXPECT_EQ(vp8_offerer, codecs[0]);
3216 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
3217 EXPECT_EQ(vp9, codecs[2]);
3218 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003219}
3220
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003221// Create an updated offer that adds video after creating an audio only answer
3222// to the original offer. This test verifies that if a video codec and the RTX
3223// codec have the same default payload type as an audio codec that is already in
3224// use, the added codecs payload types are changed.
3225TEST_F(MediaSessionDescriptionFactoryTest,
3226 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
3227 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003228 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003229 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003230 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003231
3232 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003233 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3234 RtpTransceiverDirection::kRecvOnly, kActive,
3235 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003236
Steve Anton6fe1fba2018-12-11 10:15:23 -08003237 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3238 std::unique_ptr<SessionDescription> answer =
3239 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003240
3241 const AudioContentDescription* acd =
3242 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003243 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003244
3245 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
3246 // reference be the same as an audio codec that was negotiated in the
3247 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07003248 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08003249 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003250
3251 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3252 int used_pl_type = acd->codecs()[0].id;
3253 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003254 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003255 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003256
kwiberg31022942016-03-11 14:18:21 -08003257 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003258 f2_.CreateOffer(opts, answer.get()));
3259 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003260 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003261 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3262
3263 const AudioContentDescription* updated_acd =
3264 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003265 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003266
3267 const VideoContentDescription* updated_vcd =
3268 GetFirstVideoContentDescription(updated_answer.get());
3269
3270 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003271 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003272 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003273 EXPECT_NE(used_pl_type, new_h264_pl_type);
3274 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003275 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003276 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3277 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3278}
3279
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003280// Create an updated offer with RTX after creating an answer to an offer
3281// without RTX, and with different default payload types.
3282// Verify that the added RTX codec references the correct payload type.
3283TEST_F(MediaSessionDescriptionFactoryTest,
3284 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3285 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003286 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003287
3288 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3289 // This creates rtx for H264 with the payload type |f2_| uses.
3290 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003291 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003292
Steve Anton6fe1fba2018-12-11 10:15:23 -08003293 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003294 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003295 std::unique_ptr<SessionDescription> answer =
3296 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003297
3298 const VideoContentDescription* vcd =
3299 GetFirstVideoContentDescription(answer.get());
3300
3301 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3302 EXPECT_EQ(expected_codecs, vcd->codecs());
3303
3304 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
3305 // updated offer, even though the default payload types are different from
3306 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08003307 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003308 f2_.CreateOffer(opts, answer.get()));
3309 ASSERT_TRUE(updated_offer);
3310
3311 const VideoContentDescription* updated_vcd =
3312 GetFirstVideoContentDescription(updated_offer.get());
3313
3314 // New offer should attempt to add H263, and RTX for H264.
3315 expected_codecs.push_back(kVideoCodecs2[1]);
3316 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3317 &expected_codecs);
3318 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3319}
3320
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003321// Test that RTX is ignored when there is no associated payload type parameter.
3322TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3323 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003324 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3325 RtpTransceiverDirection::kRecvOnly, kActive,
3326 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003327 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003328 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003329 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003330 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003331
3332 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003333 // This creates RTX for H264 with the payload type |f2_| uses.
3334 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003335 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003336
Steve Anton6fe1fba2018-12-11 10:15:23 -08003337 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003338 ASSERT_TRUE(offer.get() != NULL);
3339 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3340 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3341 // is possible to test that that RTX is dropped when
3342 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003343 MediaContentDescription* media_desc =
3344 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3345 ASSERT_TRUE(media_desc);
3346 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003347 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003348 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003349 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003350 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003351 }
3352 }
3353 desc->set_codecs(codecs);
3354
Steve Anton6fe1fba2018-12-11 10:15:23 -08003355 std::unique_ptr<SessionDescription> answer =
3356 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003357
Steve Anton64b626b2019-01-28 17:25:26 -08003358 EXPECT_THAT(
3359 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3360 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003361}
3362
3363// Test that RTX will be filtered out in the answer if its associated payload
3364// type doesn't match the local value.
3365TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3366 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003367 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3368 RtpTransceiverDirection::kRecvOnly, kActive,
3369 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003370 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3371 // This creates RTX for H264 in sender.
3372 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003373 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003374
3375 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3376 // This creates RTX for H263 in receiver.
3377 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003378 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003379
Steve Anton6fe1fba2018-12-11 10:15:23 -08003380 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003381 ASSERT_TRUE(offer.get() != NULL);
3382 // Associated payload type doesn't match, therefore, RTX codec is removed in
3383 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003384 std::unique_ptr<SessionDescription> answer =
3385 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003386
Steve Anton64b626b2019-01-28 17:25:26 -08003387 EXPECT_THAT(
3388 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3389 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003390}
3391
3392// Test that when multiple RTX codecs are offered, only the matched RTX codec
3393// is added in the answer, and the unsupported RTX codec is filtered out.
3394TEST_F(MediaSessionDescriptionFactoryTest,
3395 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3396 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003397 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3398 RtpTransceiverDirection::kRecvOnly, kActive,
3399 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003400 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3401 // This creates RTX for H264-SVC in sender.
3402 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003403 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003404
3405 // This creates RTX for H264 in sender.
3406 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003407 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003408
3409 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3410 // This creates RTX for H264 in receiver.
3411 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003412 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003413
3414 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3415 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003416 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003417 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003418 std::unique_ptr<SessionDescription> answer =
3419 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003420 const VideoContentDescription* vcd =
3421 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003422 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3423 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3424 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003425
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003426 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003427}
3428
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003429// Test that after one RTX codec has been negotiated, a new offer can attempt
3430// to add another.
3431TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3432 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003433 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3434 RtpTransceiverDirection::kRecvOnly, kActive,
3435 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003436 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3437 // This creates RTX for H264 for the offerer.
3438 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003439 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003440
Steve Anton6fe1fba2018-12-11 10:15:23 -08003441 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003442 ASSERT_TRUE(offer);
3443 const VideoContentDescription* vcd =
3444 GetFirstVideoContentDescription(offer.get());
3445
3446 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3447 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3448 &expected_codecs);
3449 EXPECT_EQ(expected_codecs, vcd->codecs());
3450
3451 // Now, attempt to add RTX for H264-SVC.
3452 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003453 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003454
kwiberg31022942016-03-11 14:18:21 -08003455 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003456 f1_.CreateOffer(opts, offer.get()));
3457 ASSERT_TRUE(updated_offer);
3458 vcd = GetFirstVideoContentDescription(updated_offer.get());
3459
3460 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3461 &expected_codecs);
3462 EXPECT_EQ(expected_codecs, vcd->codecs());
3463}
3464
Noah Richards2e7a0982015-05-18 14:02:54 -07003465// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3466// generated for each simulcast ssrc and correctly grouped.
3467TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3468 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003469 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3470 RtpTransceiverDirection::kSendRecv, kActive,
3471 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003472 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003473 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3474 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003475
3476 // Use a single real codec, and then add RTX for it.
3477 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003478 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003479 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003480 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003481
3482 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3483 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003484 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003485 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003486 MediaContentDescription* media_desc =
3487 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3488 ASSERT_TRUE(media_desc);
3489 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003490 const StreamParamsVec& streams = desc->streams();
3491 // Single stream.
3492 ASSERT_EQ(1u, streams.size());
3493 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3494 EXPECT_EQ(6u, streams[0].ssrcs.size());
3495 // And should have a SIM group for the simulcast.
3496 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3497 // And a FID group for RTX.
3498 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003499 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003500 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3501 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003502 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003503 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3504 EXPECT_EQ(3u, fid_ssrcs.size());
3505}
3506
brandtr03d5fb12016-11-22 03:37:59 -08003507// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003508// together with a FEC-FR grouping. Guarded by WebRTC-FlexFEC-03 trial.
brandtr03d5fb12016-11-22 03:37:59 -08003509TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003510 webrtc::test::ScopedFieldTrials override_field_trials(
3511 "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003512 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003513 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3514 RtpTransceiverDirection::kSendRecv, kActive,
3515 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003516 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003517 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3518 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003519
3520 // Use a single real codec, and then add FlexFEC for it.
3521 std::vector<VideoCodec> f1_codecs;
3522 f1_codecs.push_back(VideoCodec(97, "H264"));
3523 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003524 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003525
3526 // Ensure that the offer has a single FlexFEC ssrc and that
3527 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003528 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003529 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003530 MediaContentDescription* media_desc =
3531 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3532 ASSERT_TRUE(media_desc);
3533 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003534 const StreamParamsVec& streams = desc->streams();
3535 // Single stream.
3536 ASSERT_EQ(1u, streams.size());
3537 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3538 EXPECT_EQ(2u, streams[0].ssrcs.size());
3539 // And should have a FEC-FR group for FlexFEC.
3540 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3541 std::vector<uint32_t> primary_ssrcs;
3542 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3543 ASSERT_EQ(1u, primary_ssrcs.size());
3544 uint32_t flexfec_ssrc;
3545 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3546 EXPECT_NE(flexfec_ssrc, 0u);
3547}
3548
3549// Test that FlexFEC is disabled for simulcast.
3550// TODO(brandtr): Remove this test when we support simulcast, either through
3551// multiple FlexfecSenders, or through multistream protection.
3552TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003553 webrtc::test::ScopedFieldTrials override_field_trials(
3554 "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003555 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003556 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3557 RtpTransceiverDirection::kSendRecv, kActive,
3558 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003559 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003560 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3561 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003562
3563 // Use a single real codec, and then add FlexFEC for it.
3564 std::vector<VideoCodec> f1_codecs;
3565 f1_codecs.push_back(VideoCodec(97, "H264"));
3566 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003567 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003568
3569 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3570 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003571 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003572 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003573 MediaContentDescription* media_desc =
3574 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3575 ASSERT_TRUE(media_desc);
3576 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003577 const StreamParamsVec& streams = desc->streams();
3578 // Single stream.
3579 ASSERT_EQ(1u, streams.size());
3580 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3581 EXPECT_EQ(3u, streams[0].ssrcs.size());
3582 // And should have a SIM group for the simulcast.
3583 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3584 // And not a FEC-FR group for FlexFEC.
3585 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3586 std::vector<uint32_t> primary_ssrcs;
3587 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3588 EXPECT_EQ(3u, primary_ssrcs.size());
3589 for (uint32_t primary_ssrc : primary_ssrcs) {
3590 uint32_t flexfec_ssrc;
3591 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3592 }
3593}
3594
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003595// Create an updated offer after creating an answer to the original offer and
3596// verify that the RTP header extensions that were part of the original answer
3597// are not changed in the updated offer.
3598TEST_F(MediaSessionDescriptionFactoryTest,
3599 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3600 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003601 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003602
Markus Handell755c65d2020-06-24 01:06:10 +02003603 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3604 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003605 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02003606 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3607 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003608 std::unique_ptr<SessionDescription> answer =
3609 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003610
Yves Gerey665174f2018-06-19 15:03:05 +02003611 EXPECT_EQ(
3612 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3613 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3614 EXPECT_EQ(
3615 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3616 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003617
kwiberg31022942016-03-11 14:18:21 -08003618 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003619 f2_.CreateOffer(opts, answer.get()));
3620
3621 // The expected RTP header extensions in the new offer are the resulting
3622 // extensions from the first offer/answer exchange plus the extensions only
3623 // |f2_| offer.
3624 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003625 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003626 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003627 kAudioRtpExtensionAnswer[0],
3628 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003629 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003630 };
3631
3632 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003633 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003634 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003635 kVideoRtpExtensionAnswer[0],
3636 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003637 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003638 };
3639
3640 const AudioContentDescription* updated_acd =
3641 GetFirstAudioContentDescription(updated_offer.get());
3642 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3643 updated_acd->rtp_header_extensions());
3644
3645 const VideoContentDescription* updated_vcd =
3646 GetFirstVideoContentDescription(updated_offer.get());
3647 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3648 updated_vcd->rtp_header_extensions());
3649}
3650
deadbeefa5b273a2015-08-20 17:30:13 -07003651// Verify that if the same RTP extension URI is used for audio and video, the
3652// same ID is used. Also verify that the ID isn't changed when creating an
3653// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003654TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003655 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003656 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003657
Markus Handell755c65d2020-06-24 01:06:10 +02003658 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3659 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003660 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003661
3662 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3663 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003664 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003665 kVideoRtpExtension3[0],
3666 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003667 };
3668
Yves Gerey665174f2018-06-19 15:03:05 +02003669 EXPECT_EQ(
3670 MAKE_VECTOR(kAudioRtpExtension3),
3671 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3672 EXPECT_EQ(
3673 MAKE_VECTOR(kExpectedVideoRtpExtension),
3674 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003675
3676 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003677 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003678 f1_.CreateOffer(opts, offer.get()));
3679
3680 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003681 GetFirstAudioContentDescription(updated_offer.get())
3682 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003683 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003684 GetFirstVideoContentDescription(updated_offer.get())
3685 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003686}
3687
jbauch5869f502017-06-29 12:31:36 -07003688// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3689TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3690 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003691 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003692
3693 f1_.set_enable_encrypted_rtp_header_extensions(true);
3694 f2_.set_enable_encrypted_rtp_header_extensions(true);
3695
Markus Handell755c65d2020-06-24 01:06:10 +02003696 SetAudioVideoRtpHeaderExtensions(
3697 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3698 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003699 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003700
3701 // The extensions that are shared between audio and video should use the same
3702 // id.
3703 const RtpExtension kExpectedVideoRtpExtension[] = {
3704 kVideoRtpExtension3ForEncryption[0],
3705 kAudioRtpExtension3ForEncryptionOffer[1],
3706 kAudioRtpExtension3ForEncryptionOffer[2],
3707 };
3708
Yves Gerey665174f2018-06-19 15:03:05 +02003709 EXPECT_EQ(
3710 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3711 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3712 EXPECT_EQ(
3713 MAKE_VECTOR(kExpectedVideoRtpExtension),
3714 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003715
3716 // Nothing should change when creating a new offer
3717 std::unique_ptr<SessionDescription> updated_offer(
3718 f1_.CreateOffer(opts, offer.get()));
3719
3720 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003721 GetFirstAudioContentDescription(updated_offer.get())
3722 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003723 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003724 GetFirstVideoContentDescription(updated_offer.get())
3725 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003726}
3727
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003728TEST(MediaSessionDescription, CopySessionDescription) {
3729 SessionDescription source;
3730 cricket::ContentGroup group(cricket::CN_AUDIO);
3731 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003732 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003733 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003734 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3735 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003736 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003737 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003738 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003739 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3740 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003741 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003742
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003743 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003744 ASSERT_TRUE(copy.get() != NULL);
3745 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3746 const ContentInfo* ac = copy->GetContentByName("audio");
3747 const ContentInfo* vc = copy->GetContentByName("video");
3748 ASSERT_TRUE(ac != NULL);
3749 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003750 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003751 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003752 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3753 EXPECT_EQ(1u, acd->first_ssrc());
3754
Steve Anton5adfafd2017-12-20 16:34:00 -08003755 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003756 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003757 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3758 EXPECT_EQ(2u, vcd->first_ssrc());
3759}
3760
3761// The below TestTransportInfoXXX tests create different offers/answers, and
3762// ensure the TransportInfo in the SessionDescription matches what we expect.
3763TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3764 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003765 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3766 RtpTransceiverDirection::kRecvOnly, kActive,
3767 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003768 TestTransportInfo(true, options, false);
3769}
3770
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003771TEST_F(MediaSessionDescriptionFactoryTest,
3772 TestTransportInfoOfferIceRenomination) {
3773 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003774 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3775 RtpTransceiverDirection::kRecvOnly, kActive,
3776 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003777 options.media_description_options[0]
3778 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003779 TestTransportInfo(true, options, false);
3780}
3781
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003782TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3783 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003784 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3785 RtpTransceiverDirection::kRecvOnly, kActive,
3786 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003787 TestTransportInfo(true, options, true);
3788}
3789
3790TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3791 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003792 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3793 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3794 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003795 TestTransportInfo(true, options, false);
3796}
3797
3798TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003799 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003800 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003801 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3802 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3803 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003804 TestTransportInfo(true, options, true);
3805}
3806
3807TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3808 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003809 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3810 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3811 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003812 options.bundle_enabled = true;
3813 TestTransportInfo(true, options, false);
3814}
3815
3816TEST_F(MediaSessionDescriptionFactoryTest,
3817 TestTransportInfoOfferBundleCurrent) {
3818 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003819 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3820 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3821 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003822 options.bundle_enabled = true;
3823 TestTransportInfo(true, options, true);
3824}
3825
3826TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3827 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003828 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3829 RtpTransceiverDirection::kRecvOnly, kActive,
3830 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003831 TestTransportInfo(false, options, false);
3832}
3833
3834TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003835 TestTransportInfoAnswerIceRenomination) {
3836 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003837 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3838 RtpTransceiverDirection::kRecvOnly, kActive,
3839 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003840 options.media_description_options[0]
3841 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003842 TestTransportInfo(false, options, false);
3843}
3844
3845TEST_F(MediaSessionDescriptionFactoryTest,
3846 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003847 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003848 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3849 RtpTransceiverDirection::kRecvOnly, kActive,
3850 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003851 TestTransportInfo(false, options, true);
3852}
3853
3854TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3855 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003856 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3857 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3858 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003859 TestTransportInfo(false, options, false);
3860}
3861
3862TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003863 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003864 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003865 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3866 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3867 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003868 TestTransportInfo(false, options, true);
3869}
3870
3871TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3872 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003873 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3874 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3875 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003876 options.bundle_enabled = true;
3877 TestTransportInfo(false, options, false);
3878}
3879
3880TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003881 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003882 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003883 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3884 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3885 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003886 options.bundle_enabled = true;
3887 TestTransportInfo(false, options, true);
3888}
3889
3890// Create an offer with bundle enabled and verify the crypto parameters are
3891// the common set of the available cryptos.
3892TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3893 TestCryptoWithBundle(true);
3894}
3895
3896// Create an answer with bundle enabled and verify the crypto parameters are
3897// the common set of the available cryptos.
3898TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3899 TestCryptoWithBundle(false);
3900}
3901
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003902// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3903// DTLS is not enabled locally.
3904TEST_F(MediaSessionDescriptionFactoryTest,
3905 TestOfferDtlsSavpfWithoutDtlsFailed) {
3906 f1_.set_secure(SEC_ENABLED);
3907 f2_.set_secure(SEC_ENABLED);
3908 tdf1_.set_secure(SEC_DISABLED);
3909 tdf2_.set_secure(SEC_DISABLED);
3910
Steve Anton6fe1fba2018-12-11 10:15:23 -08003911 std::unique_ptr<SessionDescription> offer =
3912 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003913 ASSERT_TRUE(offer.get() != NULL);
3914 ContentInfo* offer_content = offer->GetContentByName("audio");
3915 ASSERT_TRUE(offer_content != NULL);
3916 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003917 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003918 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3919
Steve Anton6fe1fba2018-12-11 10:15:23 -08003920 std::unique_ptr<SessionDescription> answer =
3921 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003922 ASSERT_TRUE(answer != NULL);
3923 ContentInfo* answer_content = answer->GetContentByName("audio");
3924 ASSERT_TRUE(answer_content != NULL);
3925
3926 ASSERT_TRUE(answer_content->rejected);
3927}
3928
3929// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3930// UDP/TLS/RTP/SAVPF.
3931TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3932 f1_.set_secure(SEC_ENABLED);
3933 f2_.set_secure(SEC_ENABLED);
3934 tdf1_.set_secure(SEC_ENABLED);
3935 tdf2_.set_secure(SEC_ENABLED);
3936
Steve Anton6fe1fba2018-12-11 10:15:23 -08003937 std::unique_ptr<SessionDescription> offer =
3938 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003939 ASSERT_TRUE(offer.get() != NULL);
3940 ContentInfo* offer_content = offer->GetContentByName("audio");
3941 ASSERT_TRUE(offer_content != NULL);
3942 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003943 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003944 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3945
Steve Anton6fe1fba2018-12-11 10:15:23 -08003946 std::unique_ptr<SessionDescription> answer =
3947 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003948 ASSERT_TRUE(answer != NULL);
3949
3950 const ContentInfo* answer_content = answer->GetContentByName("audio");
3951 ASSERT_TRUE(answer_content != NULL);
3952 ASSERT_FALSE(answer_content->rejected);
3953
3954 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003955 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003956 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003957}
3958
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003959// Test that we include both SDES and DTLS in the offer, but only include SDES
3960// in the answer if DTLS isn't negotiated.
3961TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3962 f1_.set_secure(SEC_ENABLED);
3963 f2_.set_secure(SEC_ENABLED);
3964 tdf1_.set_secure(SEC_ENABLED);
3965 tdf2_.set_secure(SEC_DISABLED);
3966 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003967 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003968 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003969 const cricket::MediaContentDescription* audio_media_desc;
3970 const cricket::MediaContentDescription* video_media_desc;
3971 const cricket::TransportDescription* audio_trans_desc;
3972 const cricket::TransportDescription* video_trans_desc;
3973
3974 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003975 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003976 ASSERT_TRUE(offer.get() != NULL);
3977
Steve Antonb1c1de12017-12-21 15:14:30 -08003978 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003979 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003980 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003981 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003982 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003983 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3984
3985 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3986 ASSERT_TRUE(audio_trans_desc != NULL);
3987 video_trans_desc = offer->GetTransportDescriptionByName("video");
3988 ASSERT_TRUE(video_trans_desc != NULL);
3989 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3990 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3991
3992 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003993 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003994 ASSERT_TRUE(answer.get() != NULL);
3995
Steve Antonb1c1de12017-12-21 15:14:30 -08003996 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003997 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003998 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003999 ASSERT_TRUE(video_media_desc != NULL);
4000 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
4001 EXPECT_EQ(1u, video_media_desc->cryptos().size());
4002
4003 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
4004 ASSERT_TRUE(audio_trans_desc != NULL);
4005 video_trans_desc = answer->GetTransportDescriptionByName("video");
4006 ASSERT_TRUE(video_trans_desc != NULL);
4007 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
4008 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
4009
4010 // Enable DTLS; the answer should now only have DTLS support.
4011 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004012 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004013 ASSERT_TRUE(answer.get() != NULL);
4014
Steve Antonb1c1de12017-12-21 15:14:30 -08004015 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004016 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004017 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004018 ASSERT_TRUE(video_media_desc != NULL);
4019 EXPECT_TRUE(audio_media_desc->cryptos().empty());
4020 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08004021 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
4022 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004023
4024 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
4025 ASSERT_TRUE(audio_trans_desc != NULL);
4026 video_trans_desc = answer->GetTransportDescriptionByName("video");
4027 ASSERT_TRUE(video_trans_desc != NULL);
4028 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
4029 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00004030
4031 // Try creating offer again. DTLS enabled now, crypto's should be empty
4032 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004033 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00004034 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004035 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00004036 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004037 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00004038 ASSERT_TRUE(video_media_desc != NULL);
4039 EXPECT_TRUE(audio_media_desc->cryptos().empty());
4040 EXPECT_TRUE(video_media_desc->cryptos().empty());
4041
4042 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
4043 ASSERT_TRUE(audio_trans_desc != NULL);
4044 video_trans_desc = offer->GetTransportDescriptionByName("video");
4045 ASSERT_TRUE(video_trans_desc != NULL);
4046 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
4047 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004048}
4049
4050// Test that an answer can't be created if cryptos are required but the offer is
4051// unsecure.
4052TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004053 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004054 f1_.set_secure(SEC_DISABLED);
4055 tdf1_.set_secure(SEC_DISABLED);
4056 f2_.set_secure(SEC_REQUIRED);
4057 tdf1_.set_secure(SEC_ENABLED);
4058
Steve Anton6fe1fba2018-12-11 10:15:23 -08004059 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004060 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004061 std::unique_ptr<SessionDescription> answer =
4062 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004063 EXPECT_TRUE(answer.get() == NULL);
4064}
4065
4066// Test that we accept a DTLS offer without SDES and create an appropriate
4067// answer.
4068TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
4069 f1_.set_secure(SEC_DISABLED);
4070 f2_.set_secure(SEC_ENABLED);
4071 tdf1_.set_secure(SEC_ENABLED);
4072 tdf2_.set_secure(SEC_ENABLED);
4073 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004074 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
4075 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
4076 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004077
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004078 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004079 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004080 ASSERT_TRUE(offer.get() != NULL);
4081
4082 const AudioContentDescription* audio_offer =
4083 GetFirstAudioContentDescription(offer.get());
4084 ASSERT_TRUE(audio_offer->cryptos().empty());
4085 const VideoContentDescription* video_offer =
4086 GetFirstVideoContentDescription(offer.get());
4087 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004088 const RtpDataContentDescription* data_offer =
4089 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004090 ASSERT_TRUE(data_offer->cryptos().empty());
4091
4092 const cricket::TransportDescription* audio_offer_trans_desc =
4093 offer->GetTransportDescriptionByName("audio");
4094 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
4095 const cricket::TransportDescription* video_offer_trans_desc =
4096 offer->GetTransportDescriptionByName("video");
4097 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
4098 const cricket::TransportDescription* data_offer_trans_desc =
4099 offer->GetTransportDescriptionByName("data");
4100 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
4101
4102 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004103 std::unique_ptr<SessionDescription> answer =
4104 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004105 ASSERT_TRUE(answer.get() != NULL);
4106
4107 const cricket::TransportDescription* audio_answer_trans_desc =
4108 answer->GetTransportDescriptionByName("audio");
4109 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
4110 const cricket::TransportDescription* video_answer_trans_desc =
4111 answer->GetTransportDescriptionByName("video");
4112 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
4113 const cricket::TransportDescription* data_answer_trans_desc =
4114 answer->GetTransportDescriptionByName("data");
4115 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
4116}
4117
4118// Verifies if vad_enabled option is set to false, CN codecs are not present in
4119// offer or answer.
4120TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
4121 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004122 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004123 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004124 ASSERT_TRUE(offer.get() != NULL);
4125 const ContentInfo* audio_content = offer->GetContentByName("audio");
4126 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
4127
4128 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08004129 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004130 ASSERT_TRUE(offer.get() != NULL);
4131 audio_content = offer->GetContentByName("audio");
4132 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08004133 std::unique_ptr<SessionDescription> answer =
4134 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004135 ASSERT_TRUE(answer.get() != NULL);
4136 audio_content = answer->GetContentByName("audio");
4137 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
4138}
deadbeef44f08192015-12-15 16:20:09 -08004139
zhihuang1c378ed2017-08-17 14:10:50 -07004140// Test that the generated MIDs match the existing offer.
4141TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08004142 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004143 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
4144 RtpTransceiverDirection::kRecvOnly, kActive,
4145 &opts);
4146 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
4147 RtpTransceiverDirection::kRecvOnly, kActive,
4148 &opts);
deadbeef44f08192015-12-15 16:20:09 -08004149 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004150 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
4151 RtpTransceiverDirection::kSendRecv, kActive,
4152 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004153 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004154 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08004155 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08004156 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07004157
deadbeef44f08192015-12-15 16:20:09 -08004158 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
4159 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
4160 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
4161 ASSERT_TRUE(audio_content != nullptr);
4162 ASSERT_TRUE(video_content != nullptr);
4163 ASSERT_TRUE(data_content != nullptr);
4164 EXPECT_EQ("audio_modified", audio_content->name);
4165 EXPECT_EQ("video_modified", video_content->name);
4166 EXPECT_EQ("data_modified", data_content->name);
4167}
zhihuangcf5b37c2016-05-05 11:44:35 -07004168
zhihuang1c378ed2017-08-17 14:10:50 -07004169// The following tests verify that the unified plan SDP is supported.
4170// Test that we can create an offer with multiple media sections of same media
4171// type.
4172TEST_F(MediaSessionDescriptionFactoryTest,
4173 CreateOfferWithMultipleAVMediaSections) {
4174 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004175 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4176 RtpTransceiverDirection::kSendRecv, kActive,
4177 &opts);
4178 AttachSenderToMediaDescriptionOptions(
4179 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004180
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004181 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4182 RtpTransceiverDirection::kSendRecv, kActive,
4183 &opts);
4184 AttachSenderToMediaDescriptionOptions(
4185 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004186
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004187 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4188 RtpTransceiverDirection::kSendRecv, kActive,
4189 &opts);
4190 AttachSenderToMediaDescriptionOptions(
4191 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004192
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004193 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4194 RtpTransceiverDirection::kSendRecv, kActive,
4195 &opts);
4196 AttachSenderToMediaDescriptionOptions(
4197 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004198 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004199 ASSERT_TRUE(offer);
4200
4201 ASSERT_EQ(4u, offer->contents().size());
4202 EXPECT_FALSE(offer->contents()[0].rejected);
4203 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004204 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004205 ASSERT_EQ(1u, acd->streams().size());
4206 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004207 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004208
4209 EXPECT_FALSE(offer->contents()[1].rejected);
4210 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004211 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004212 ASSERT_EQ(1u, vcd->streams().size());
4213 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004214 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004215
4216 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004217 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004218 ASSERT_EQ(1u, acd->streams().size());
4219 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004220 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004221
4222 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004223 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004224 ASSERT_EQ(1u, vcd->streams().size());
4225 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004226 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004227}
4228
4229// Test that we can create an answer with multiple media sections of same media
4230// type.
4231TEST_F(MediaSessionDescriptionFactoryTest,
4232 CreateAnswerWithMultipleAVMediaSections) {
4233 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004234 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4235 RtpTransceiverDirection::kSendRecv, kActive,
4236 &opts);
4237 AttachSenderToMediaDescriptionOptions(
4238 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004239
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004240 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4241 RtpTransceiverDirection::kSendRecv, kActive,
4242 &opts);
4243 AttachSenderToMediaDescriptionOptions(
4244 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004245
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004246 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4247 RtpTransceiverDirection::kSendRecv, kActive,
4248 &opts);
4249 AttachSenderToMediaDescriptionOptions(
4250 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004251
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004252 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4253 RtpTransceiverDirection::kSendRecv, kActive,
4254 &opts);
4255 AttachSenderToMediaDescriptionOptions(
4256 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004257
Steve Anton6fe1fba2018-12-11 10:15:23 -08004258 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004259 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004260 std::unique_ptr<SessionDescription> answer =
4261 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004262
4263 ASSERT_EQ(4u, answer->contents().size());
4264 EXPECT_FALSE(answer->contents()[0].rejected);
4265 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004266 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004267 ASSERT_EQ(1u, acd->streams().size());
4268 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004269 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004270
4271 EXPECT_FALSE(answer->contents()[1].rejected);
4272 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004273 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004274 ASSERT_EQ(1u, vcd->streams().size());
4275 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004276 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004277
4278 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004279 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004280 ASSERT_EQ(1u, acd->streams().size());
4281 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004282 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004283
4284 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004285 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004286 ASSERT_EQ(1u, vcd->streams().size());
4287 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004288 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004289}
4290
4291// Test that the media section will be rejected in offer if the corresponding
4292// MediaDescriptionOptions is stopped by the offerer.
4293TEST_F(MediaSessionDescriptionFactoryTest,
4294 CreateOfferWithMediaSectionStoppedByOfferer) {
4295 // Create an offer with two audio sections and one of them is stopped.
4296 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004297 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4298 RtpTransceiverDirection::kSendRecv, kActive,
4299 &offer_opts);
4300 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4301 RtpTransceiverDirection::kInactive, kStopped,
4302 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004303 std::unique_ptr<SessionDescription> offer =
4304 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004305 ASSERT_TRUE(offer);
4306 ASSERT_EQ(2u, offer->contents().size());
4307 EXPECT_FALSE(offer->contents()[0].rejected);
4308 EXPECT_TRUE(offer->contents()[1].rejected);
4309}
4310
4311// Test that the media section will be rejected in answer if the corresponding
4312// MediaDescriptionOptions is stopped by the offerer.
4313TEST_F(MediaSessionDescriptionFactoryTest,
4314 CreateAnswerWithMediaSectionStoppedByOfferer) {
4315 // Create an offer with two audio sections and one of them is stopped.
4316 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004317 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4318 RtpTransceiverDirection::kSendRecv, kActive,
4319 &offer_opts);
4320 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4321 RtpTransceiverDirection::kInactive, kStopped,
4322 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004323 std::unique_ptr<SessionDescription> offer =
4324 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004325 ASSERT_TRUE(offer);
4326 ASSERT_EQ(2u, offer->contents().size());
4327 EXPECT_FALSE(offer->contents()[0].rejected);
4328 EXPECT_TRUE(offer->contents()[1].rejected);
4329
4330 // Create an answer based on the offer.
4331 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004332 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4333 RtpTransceiverDirection::kSendRecv, kActive,
4334 &answer_opts);
4335 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4336 RtpTransceiverDirection::kSendRecv, kActive,
4337 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004338 std::unique_ptr<SessionDescription> answer =
4339 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004340 ASSERT_EQ(2u, answer->contents().size());
4341 EXPECT_FALSE(answer->contents()[0].rejected);
4342 EXPECT_TRUE(answer->contents()[1].rejected);
4343}
4344
4345// Test that the media section will be rejected in answer if the corresponding
4346// MediaDescriptionOptions is stopped by the answerer.
4347TEST_F(MediaSessionDescriptionFactoryTest,
4348 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4349 // Create an offer with two audio sections.
4350 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004351 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4352 RtpTransceiverDirection::kSendRecv, kActive,
4353 &offer_opts);
4354 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4355 RtpTransceiverDirection::kSendRecv, kActive,
4356 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004357 std::unique_ptr<SessionDescription> offer =
4358 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004359 ASSERT_TRUE(offer);
4360 ASSERT_EQ(2u, offer->contents().size());
4361 ASSERT_FALSE(offer->contents()[0].rejected);
4362 ASSERT_FALSE(offer->contents()[1].rejected);
4363
4364 // The answerer rejects one of the audio sections.
4365 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004366 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4367 RtpTransceiverDirection::kSendRecv, kActive,
4368 &answer_opts);
4369 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4370 RtpTransceiverDirection::kInactive, kStopped,
4371 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004372 std::unique_ptr<SessionDescription> answer =
4373 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004374 ASSERT_EQ(2u, answer->contents().size());
4375 EXPECT_FALSE(answer->contents()[0].rejected);
4376 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004377
4378 // The TransportInfo of the rejected m= section is expected to be added in the
4379 // answer.
4380 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004381}
4382
4383// Test the generated media sections has the same order of the
4384// corresponding MediaDescriptionOptions.
4385TEST_F(MediaSessionDescriptionFactoryTest,
4386 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4387 MediaSessionOptions opts;
4388 // This tests put video section first because normally audio comes first by
4389 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004390 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4391 RtpTransceiverDirection::kSendRecv, kActive,
4392 &opts);
4393 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4394 RtpTransceiverDirection::kSendRecv, kActive,
4395 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004396 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004397
4398 ASSERT_TRUE(offer);
4399 ASSERT_EQ(2u, offer->contents().size());
4400 EXPECT_EQ("video", offer->contents()[0].name);
4401 EXPECT_EQ("audio", offer->contents()[1].name);
4402}
4403
4404// Test that different media sections using the same codec have same payload
4405// type.
4406TEST_F(MediaSessionDescriptionFactoryTest,
4407 PayloadTypesSharedByMediaSectionsOfSameType) {
4408 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004409 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4410 RtpTransceiverDirection::kSendRecv, kActive,
4411 &opts);
4412 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4413 RtpTransceiverDirection::kSendRecv, kActive,
4414 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004415 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004416 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004417 ASSERT_TRUE(offer);
4418 ASSERT_EQ(2u, offer->contents().size());
4419 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004420 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004421 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004422 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004423 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4424 ASSERT_EQ(2u, vcd1->codecs().size());
4425 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4426 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4427 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4428 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4429
4430 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004431 std::unique_ptr<SessionDescription> answer =
4432 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004433 ASSERT_TRUE(answer);
4434 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004435 vcd1 = answer->contents()[0].media_description()->as_video();
4436 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004437 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4438 ASSERT_EQ(1u, vcd1->codecs().size());
4439 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4440 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4441}
4442
4443// Test that the codec preference order per media section is respected in
4444// subsequent offer.
4445TEST_F(MediaSessionDescriptionFactoryTest,
4446 CreateOfferRespectsCodecPreferenceOrder) {
4447 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004448 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4449 RtpTransceiverDirection::kSendRecv, kActive,
4450 &opts);
4451 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4452 RtpTransceiverDirection::kSendRecv, kActive,
4453 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004454 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004455 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004456 ASSERT_TRUE(offer);
4457 ASSERT_EQ(2u, offer->contents().size());
4458 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004459 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004460 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004461 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004462 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4463 EXPECT_EQ(video_codecs, vcd1->codecs());
4464 EXPECT_EQ(video_codecs, vcd2->codecs());
4465
4466 // Change the codec preference of the first video section and create a
4467 // follow-up offer.
4468 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4469 vcd1->set_codecs(video_codecs_reverse);
4470 std::unique_ptr<SessionDescription> updated_offer(
4471 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004472 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4473 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004474 // The video codec preference order should be respected.
4475 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4476 EXPECT_EQ(video_codecs, vcd2->codecs());
4477}
4478
4479// Test that the codec preference order per media section is respected in
4480// the answer.
4481TEST_F(MediaSessionDescriptionFactoryTest,
4482 CreateAnswerRespectsCodecPreferenceOrder) {
4483 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004484 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4485 RtpTransceiverDirection::kSendRecv, kActive,
4486 &opts);
4487 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4488 RtpTransceiverDirection::kSendRecv, kActive,
4489 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004490 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004491 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004492 ASSERT_TRUE(offer);
4493 ASSERT_EQ(2u, offer->contents().size());
4494 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004495 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004496 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004497 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004498 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4499 EXPECT_EQ(video_codecs, vcd1->codecs());
4500 EXPECT_EQ(video_codecs, vcd2->codecs());
4501
4502 // Change the codec preference of the first video section and create an
4503 // answer.
4504 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4505 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004506 std::unique_ptr<SessionDescription> answer =
4507 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004508 vcd1 = answer->contents()[0].media_description()->as_video();
4509 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004510 // The video codec preference order should be respected.
4511 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4512 EXPECT_EQ(video_codecs, vcd2->codecs());
4513}
4514
Zhi Huang6f367472017-11-22 13:20:02 -08004515// Test that when creating an answer, the codecs use local parameters instead of
4516// the remote ones.
4517TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4518 const std::string audio_param_name = "audio_param";
4519 const std::string audio_value1 = "audio_v1";
4520 const std::string audio_value2 = "audio_v2";
4521 const std::string video_param_name = "video_param";
4522 const std::string video_value1 = "video_v1";
4523 const std::string video_value2 = "video_v2";
4524
4525 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4526 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4527 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4528 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4529
4530 // Set the parameters for codecs.
4531 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4532 video_codecs1[0].SetParam(video_param_name, video_value1);
4533 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4534 video_codecs2[0].SetParam(video_param_name, video_value2);
4535
4536 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004537 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004538 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004539 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004540
4541 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004542 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4543 RtpTransceiverDirection::kSendRecv, kActive,
4544 &opts);
4545 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4546 RtpTransceiverDirection::kSendRecv, kActive,
4547 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004548
Steve Anton6fe1fba2018-12-11 10:15:23 -08004549 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004550 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004551 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4552 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004553 std::string value;
4554 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4555 EXPECT_EQ(audio_value1, value);
4556 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4557 EXPECT_EQ(video_value1, value);
4558
Steve Anton6fe1fba2018-12-11 10:15:23 -08004559 std::unique_ptr<SessionDescription> answer =
4560 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004561 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004562 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4563 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004564 // Use the parameters from the local codecs.
4565 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4566 EXPECT_EQ(audio_value2, value);
4567 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4568 EXPECT_EQ(video_value2, value);
4569}
4570
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004571// Test that matching packetization-mode is part of the criteria for matching
4572// H264 codecs (in addition to profile-level-id). Previously, this was not the
4573// case, so the first H264 codec with the same profile-level-id would match and
4574// the payload type in the answer would be incorrect.
4575// This is a regression test for bugs.webrtc.org/8808
4576TEST_F(MediaSessionDescriptionFactoryTest,
4577 H264MatchCriteriaIncludesPacketizationMode) {
4578 // Create two H264 codecs with the same profile level ID and different
4579 // packetization modes.
4580 VideoCodec h264_pm0(96, "H264");
4581 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4582 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4583 VideoCodec h264_pm1(97, "H264");
4584 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4585 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4586
4587 // Offerer will send both codecs, answerer should choose the one with matching
4588 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004589 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4590 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004591
4592 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004593 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4594 RtpTransceiverDirection::kSendRecv, kActive,
4595 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004596
Steve Anton6fe1fba2018-12-11 10:15:23 -08004597 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004598 ASSERT_TRUE(offer);
4599
Steve Anton6fe1fba2018-12-11 10:15:23 -08004600 std::unique_ptr<SessionDescription> answer =
4601 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004602 ASSERT_TRUE(answer);
4603
4604 // Answer should have one negotiated codec with packetization-mode=1 using the
4605 // offered payload type.
4606 ASSERT_EQ(1u, answer->contents().size());
4607 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4608 ASSERT_EQ(1u, answer_vcd->codecs().size());
4609 auto answer_codec = answer_vcd->codecs()[0];
4610 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4611}
4612
zhihuangcf5b37c2016-05-05 11:44:35 -07004613class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4614 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004615 MediaProtocolTest()
4616 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004617 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4618 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004619 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4620 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004621 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004622 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4623 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004624 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4625 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004626 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004627 f1_.set_secure(SEC_ENABLED);
4628 f2_.set_secure(SEC_ENABLED);
4629 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004630 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004631 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004632 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004633 tdf1_.set_secure(SEC_ENABLED);
4634 tdf2_.set_secure(SEC_ENABLED);
4635 }
4636
4637 protected:
4638 MediaSessionDescriptionFactory f1_;
4639 MediaSessionDescriptionFactory f2_;
4640 TransportDescriptionFactory tdf1_;
4641 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004642 UniqueRandomIdGenerator ssrc_generator1;
4643 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004644};
4645
4646TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4647 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004648 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004649 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004650 ASSERT_TRUE(offer.get() != nullptr);
4651 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004652 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004653 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004654 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004655 std::unique_ptr<SessionDescription> answer =
4656 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004657 const ContentInfo* ac = answer->GetContentByName("audio");
4658 const ContentInfo* vc = answer->GetContentByName("video");
4659 ASSERT_TRUE(ac != nullptr);
4660 ASSERT_TRUE(vc != nullptr);
4661 EXPECT_FALSE(ac->rejected); // the offer is accepted
4662 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004663 const AudioContentDescription* acd = ac->media_description()->as_audio();
4664 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004665 EXPECT_EQ(GetParam(), acd->protocol());
4666 EXPECT_EQ(GetParam(), vcd->protocol());
4667}
4668
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004669INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4670 MediaProtocolTest,
4671 ::testing::ValuesIn(kMediaProtocols));
4672INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4673 MediaProtocolTest,
4674 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004675
4676TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4677 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004678 UniqueRandomIdGenerator ssrc_generator;
4679 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004680 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4681 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4682
4683 // The merged list of codecs should contain any send codecs that are also
4684 // nominally in the recieve codecs list. Payload types should be picked from
4685 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4686 // (set to 1). This equals what happens when the send codecs are used in an
4687 // offer and the receive codecs are used in the following answer.
4688 const std::vector<AudioCodec> sendrecv_codecs =
4689 MAKE_VECTOR(kAudioCodecsAnswer);
4690 const std::vector<AudioCodec> no_codecs;
4691
4692 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4693 << "Please don't change shared test data!";
4694 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4695 << "Please don't change shared test data!";
4696 // Alter iLBC send codec to have zero channels, to test that that is handled
4697 // properly.
4698 send_codecs[1].channels = 0;
4699
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004700 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004701 // are handled properly.
4702 recv_codecs[2].name = "ilbc";
4703
4704 // Test proper merge
4705 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004706 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4707 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4708 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004709
4710 // Test empty send codecs list
4711 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004712 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4713 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4714 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004715
4716 // Test empty recv codecs list
4717 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004718 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4719 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4720 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004721
4722 // Test all empty codec lists
4723 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004724 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4725 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4726 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004727}
4728
4729namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004730// Compare the two vectors of codecs ignoring the payload type.
4731template <class Codec>
4732bool CodecsMatch(const std::vector<Codec>& codecs1,
4733 const std::vector<Codec>& codecs2) {
4734 if (codecs1.size() != codecs2.size()) {
4735 return false;
4736 }
4737
4738 for (size_t i = 0; i < codecs1.size(); ++i) {
4739 if (!codecs1[i].Matches(codecs2[i])) {
4740 return false;
4741 }
4742 }
4743 return true;
4744}
4745
Steve Anton4e70a722017-11-28 14:57:10 -08004746void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004747 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004748 UniqueRandomIdGenerator ssrc_generator;
4749 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004750 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4751 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4752 const std::vector<AudioCodec> sendrecv_codecs =
4753 MAKE_VECTOR(kAudioCodecsAnswer);
4754 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004755
4756 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004757 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4758 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004759
Steve Anton4e70a722017-11-28 14:57:10 -08004760 if (direction == RtpTransceiverDirection::kSendRecv ||
4761 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004762 AttachSenderToMediaDescriptionOptions(
4763 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004764 }
ossu075af922016-06-14 03:29:38 -07004765
Steve Anton6fe1fba2018-12-11 10:15:23 -08004766 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004767 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004768 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004769
4770 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004771 // that the codecs put in are right. This happens when we neither want to
4772 // send nor receive audio. The checks are still in place if at some point
4773 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004774 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004775 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004776 // sendrecv and inactive should both present lists as if the channel was
4777 // to be used for sending and receiving. Inactive essentially means it
4778 // might eventually be used anything, but we don't know more at this
4779 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004780 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004781 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004782 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004783 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004784 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004785 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004786 }
4787 }
4788}
4789
4790static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004791 AudioCodec(0, "codec0", 16000, -1, 1),
4792 AudioCodec(1, "codec1", 8000, 13300, 1),
4793 AudioCodec(2, "codec2", 8000, 64000, 1),
4794 AudioCodec(3, "codec3", 8000, 64000, 1),
4795 AudioCodec(4, "codec4", 8000, 0, 2),
4796 AudioCodec(5, "codec5", 32000, 0, 1),
4797 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004798
zhihuang1c378ed2017-08-17 14:10:50 -07004799/* The codecs groups below are chosen as per the matrix below. The objective
4800 * is to have different sets of codecs in the inputs, to get unique sets of
4801 * codecs after negotiation, depending on offer and answer communication
4802 * directions. One-way directions in the offer should either result in the
4803 * opposite direction in the answer, or an inactive answer. Regardless, the
4804 * choice of codecs should be as if the answer contained the opposite
4805 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004806 *
4807 * | Offer | Answer | Result
4808 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4809 * 0 | x - - | - x - | x - - - -
4810 * 1 | x x x | - x - | x - - x -
4811 * 2 | - x - | x - - | - x - - -
4812 * 3 | x x x | x - - | - x x - -
4813 * 4 | - x - | x x x | - x - - -
4814 * 5 | x - - | x x x | x - - - -
4815 * 6 | x x x | x x x | x x x x x
4816 */
4817// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004818static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4819static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004820// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4821// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004822static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4823static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004824// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004825static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4826static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4827static const int kResultSendrecv_SendCodecs[] = {3, 6};
4828static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4829static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004830
4831template <typename T, int IDXS>
4832std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4833 std::vector<T> out;
4834 out.reserve(IDXS);
4835 for (int idx : indices)
4836 out.push_back(array[idx]);
4837
4838 return out;
4839}
4840
Steve Anton4e70a722017-11-28 14:57:10 -08004841void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4842 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004843 bool add_legacy_stream) {
4844 TransportDescriptionFactory offer_tdf;
4845 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004846 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4847 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4848 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004849 offer_factory.set_audio_codecs(
4850 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4851 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4852 answer_factory.set_audio_codecs(
4853 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4854 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4855
ossu075af922016-06-14 03:29:38 -07004856 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004857 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4858 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004859
Steve Anton4e70a722017-11-28 14:57:10 -08004860 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004861 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4862 kAudioTrack1, {kMediaStream1}, 1,
4863 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004864 }
4865
Steve Anton6fe1fba2018-12-11 10:15:23 -08004866 std::unique_ptr<SessionDescription> offer =
4867 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004868 ASSERT_TRUE(offer.get() != NULL);
4869
4870 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004871 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4872 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004873
Steve Anton4e70a722017-11-28 14:57:10 -08004874 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004875 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4876 kAudioTrack1, {kMediaStream1}, 1,
4877 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004878 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004879 std::unique_ptr<SessionDescription> answer =
4880 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004881 const ContentInfo* ac = answer->GetContentByName("audio");
4882
zhihuang1c378ed2017-08-17 14:10:50 -07004883 // If the factory didn't add any audio content to the answer, we cannot
4884 // check that the codecs put in are right. This happens when we neither want
4885 // to send nor receive audio. The checks are still in place if at some point
4886 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004887 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004888 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4889 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004890
ossu075af922016-06-14 03:29:38 -07004891 std::vector<AudioCodec> target_codecs;
4892 // For offers with sendrecv or inactive, we should never reply with more
4893 // codecs than offered, with these codec sets.
4894 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004895 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004896 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4897 kResultSendrecv_SendrecvCodecs);
4898 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004899 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004900 target_codecs =
4901 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004902 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004903 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004904 target_codecs =
4905 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004906 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004907 case RtpTransceiverDirection::kSendRecv:
4908 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004909 target_codecs =
4910 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004911 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004912 target_codecs =
4913 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004914 } else {
4915 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4916 kResultSendrecv_SendrecvCodecs);
4917 }
4918 break;
Harald Alvestrand6060df52020-08-11 09:54:02 +02004919 case RtpTransceiverDirection::kStopped:
4920 // This does not happen in any current test.
Markus Handell45c104b2020-03-11 10:51:13 +01004921 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004922 }
4923
zhihuang1c378ed2017-08-17 14:10:50 -07004924 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004925 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004926 bool first = true;
4927 os << "{";
4928 for (const auto& c : codecs) {
4929 os << (first ? " " : ", ") << c.id;
4930 first = false;
4931 }
4932 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004933 return os.Release();
ossu075af922016-06-14 03:29:38 -07004934 };
4935
4936 EXPECT_TRUE(acd->codecs() == target_codecs)
4937 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004938 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4939 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004940 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004941 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4942 << "; got: "
4943 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004944 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004945 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004946 << "Only inactive offers are allowed to not generate any audio "
4947 "content";
ossu075af922016-06-14 03:29:38 -07004948 }
4949}
brandtr03d5fb12016-11-22 03:37:59 -08004950
4951} // namespace
ossu075af922016-06-14 03:29:38 -07004952
4953class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004954 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004955
4956TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004957 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004958}
4959
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004960INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4961 AudioCodecsOfferTest,
4962 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4963 RtpTransceiverDirection::kRecvOnly,
4964 RtpTransceiverDirection::kSendRecv,
4965 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004966
4967class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004968 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4969 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004970 bool>> {};
ossu075af922016-06-14 03:29:38 -07004971
4972TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004973 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4974 ::testing::get<1>(GetParam()),
4975 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004976}
4977
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004978INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004979 MediaSessionDescriptionFactoryTest,
4980 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004981 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4982 RtpTransceiverDirection::kRecvOnly,
4983 RtpTransceiverDirection::kSendRecv,
4984 RtpTransceiverDirection::kInactive),
4985 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4986 RtpTransceiverDirection::kRecvOnly,
4987 RtpTransceiverDirection::kSendRecv,
4988 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004989 ::testing::Bool()));