blob: 389b6a0a48ea6e564db0392f8b6387dc12e70cff [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/media_session.h"
12
Amit Hilbuch77938e62018-12-21 09:23:38 -080013#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080014#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <string>
Harald Alvestrand1716d392019-06-03 20:35:45 +020016#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <vector>
18
Steve Anton64b626b2019-01-28 17:25:26 -080019#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080020#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020023#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "p2p/base/p2p_constants.h"
25#include "p2p/base/transport_description.h"
26#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "pc/rtp_media_utils.h"
28#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "rtc_base/message_digest.h"
33#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020034#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080035#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080036#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
Yves Gerey665174f2018-06-19 15:03:05 +020038#define ASSERT_CRYPTO(cd, s, cs) \
39 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080040 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041
42typedef std::vector<cricket::Candidate> Candidates;
43
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080044using cricket::AudioCodec;
45using cricket::AudioContentDescription;
46using cricket::ContentInfo;
47using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080048using cricket::GetFirstAudioContent;
49using cricket::GetFirstAudioContentDescription;
50using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020051using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080052using cricket::GetFirstVideoContent;
53using cricket::GetFirstVideoContentDescription;
54using cricket::kAutoBandwidth;
55using cricket::MEDIA_TYPE_AUDIO;
56using cricket::MEDIA_TYPE_DATA;
57using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070059using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080060using cricket::MediaProtocolType;
61using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062using cricket::MediaSessionOptions;
63using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080064using cricket::RidDescription;
65using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020066using cricket::RtpDataCodec;
67using cricket::RtpDataContentDescription;
68using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080069using cricket::SEC_DISABLED;
70using cricket::SEC_ENABLED;
71using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080073using cricket::SimulcastDescription;
74using cricket::SimulcastLayer;
75using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076using cricket::SsrcGroup;
77using cricket::StreamParams;
78using cricket::StreamParamsVec;
79using cricket::TransportDescription;
80using cricket::TransportDescriptionFactory;
81using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080083using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070084using rtc::CS_AEAD_AES_128_GCM;
85using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080086using rtc::CS_AES_CM_128_HMAC_SHA1_32;
87using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080088using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020089using ::testing::Contains;
90using ::testing::Each;
91using ::testing::ElementsAreArray;
92using ::testing::Eq;
93using ::testing::Field;
94using ::testing::IsEmpty;
95using ::testing::IsFalse;
96using ::testing::Ne;
97using ::testing::Not;
98using ::testing::Pointwise;
99using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700100using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800101using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102
103static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700104 AudioCodec(103, "ISAC", 16000, -1, 1),
105 AudioCodec(102, "iLBC", 8000, 13300, 1),
106 AudioCodec(0, "PCMU", 8000, 64000, 1),
107 AudioCodec(8, "PCMA", 8000, 64000, 1),
108 AudioCodec(117, "red", 8000, 0, 1),
109 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110
111static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200112 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700113 AudioCodec(0, "PCMU", 8000, 64000, 1),
114 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115};
116
117static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700118 AudioCodec(102, "iLBC", 8000, 13300, 1),
119 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120};
121
perkj26752742016-10-24 01:21:16 -0700122static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
123 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000124
zhihuang1c378ed2017-08-17 14:10:50 -0700125static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
126 VideoCodec(96, "H264-SVC")};
127
perkj26752742016-10-24 01:21:16 -0700128static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
129 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130
perkj26752742016-10-24 01:21:16 -0700131static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200133static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
134 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200136static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
137 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200139static const RtpDataCodec kDataCodecsAnswer[] = {
140 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000141
isheriff6f8d6862016-05-26 11:24:55 -0700142static const RtpExtension kAudioRtpExtension1[] = {
143 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
144 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145};
146
jbauch5869f502017-06-29 12:31:36 -0700147static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
148 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
149 RtpExtension("http://google.com/testing/audio_something", 10),
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
151};
152
isheriff6f8d6862016-05-26 11:24:55 -0700153static const RtpExtension kAudioRtpExtension2[] = {
154 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
155 RtpExtension("http://google.com/testing/audio_something_else", 8),
156 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157};
158
isheriff6f8d6862016-05-26 11:24:55 -0700159static const RtpExtension kAudioRtpExtension3[] = {
160 RtpExtension("http://google.com/testing/audio_something", 2),
161 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700162};
163
jbauch5869f502017-06-29 12:31:36 -0700164static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
165 RtpExtension("http://google.com/testing/audio_something", 2),
166 // Use RTP extension that supports encryption.
167 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
168};
169
170static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
171 RtpExtension("http://google.com/testing/audio_something", 2),
172 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
173 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
174};
175
isheriff6f8d6862016-05-26 11:24:55 -0700176static const RtpExtension kAudioRtpExtensionAnswer[] = {
177 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000178};
179
jbauch5869f502017-06-29 12:31:36 -0700180static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
181 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
182};
183
isheriff6f8d6862016-05-26 11:24:55 -0700184static const RtpExtension kVideoRtpExtension1[] = {
185 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
186 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187};
188
jbauch5869f502017-06-29 12:31:36 -0700189static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
191 RtpExtension("http://google.com/testing/video_something", 13),
192 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
193};
194
isheriff6f8d6862016-05-26 11:24:55 -0700195static const RtpExtension kVideoRtpExtension2[] = {
196 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
197 RtpExtension("http://google.com/testing/video_something_else", 14),
198 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199};
200
isheriff6f8d6862016-05-26 11:24:55 -0700201static const RtpExtension kVideoRtpExtension3[] = {
202 RtpExtension("http://google.com/testing/video_something", 4),
203 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700204};
205
jbauch5869f502017-06-29 12:31:36 -0700206static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
207 RtpExtension("http://google.com/testing/video_something", 4),
208 // Use RTP extension that supports encryption.
209 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
210};
211
isheriff6f8d6862016-05-26 11:24:55 -0700212static const RtpExtension kVideoRtpExtensionAnswer[] = {
213 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000214};
215
jbauch5869f502017-06-29 12:31:36 -0700216static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
217 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
218};
219
Johannes Kronce8e8672019-02-22 13:06:44 +0100220static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
221 RtpExtension("http://www.ietf.org/id/"
222 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
223 1),
224};
225
226static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
227 RtpExtension("http://www.ietf.org/id/"
228 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
229 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100230 RtpExtension(
231 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
232 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100233};
234
235static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100236 RtpExtension(
237 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
238 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100239};
240
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100241static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
242 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
243 "generic-frame-descriptor-00",
244 3),
245};
246
Peter Boström0c4e06b2015-10-07 12:23:21 +0200247static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
248static const uint32_t kSimSsrc[] = {10, 20, 30};
249static const uint32_t kFec1Ssrc[] = {10, 11};
250static const uint32_t kFec2Ssrc[] = {20, 21};
251static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000252
253static const char kMediaStream1[] = "stream_1";
254static const char kMediaStream2[] = "stream_2";
255static const char kVideoTrack1[] = "video_1";
256static const char kVideoTrack2[] = "video_2";
257static const char kAudioTrack1[] = "audio_1";
258static const char kAudioTrack2[] = "audio_2";
259static const char kAudioTrack3[] = "audio_3";
260static const char kDataTrack1[] = "data_1";
261static const char kDataTrack2[] = "data_2";
262static const char kDataTrack3[] = "data_3";
263
zhihuangcf5b37c2016-05-05 11:44:35 -0700264static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
265 "RTP/SAVPF"};
266static const char* kMediaProtocolsDtls[] = {
267 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
268 "UDP/TLS/RTP/SAVP"};
269
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700270// SRTP cipher name negotiated by the tests. This must be updated if the
271// default changes.
272static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
273static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
274
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800275// These constants are used to make the code using "AddMediaDescriptionOptions"
276// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700277static constexpr bool kStopped = true;
278static constexpr bool kActive = false;
279
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000280static bool IsMediaContentOfType(const ContentInfo* content,
281 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800282 RTC_DCHECK(content);
283 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000284}
285
Steve Anton4e70a722017-11-28 14:57:10 -0800286static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800287 RTC_DCHECK(content);
288 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000289}
290
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000291static void AddRtxCodec(const VideoCodec& rtx_codec,
292 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800293 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000294 codecs->push_back(rtx_codec);
295}
296
297template <class T>
298static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
299 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100300 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000301 for (const auto& codec : codecs) {
302 codec_names.push_back(codec.name);
303 }
304 return codec_names;
305}
306
zhihuang1c378ed2017-08-17 14:10:50 -0700307// This is used for test only. MIDs are not the identification of the
308// MediaDescriptionOptions since some end points may not support MID and the SDP
309// may not contain 'mid'.
310std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
311 const std::string& mid,
312 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800313 return absl::c_find_if(
314 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700315 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
316}
317
318std::vector<MediaDescriptionOptions>::const_iterator
319FindFirstMediaDescriptionByMid(const std::string& mid,
320 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800321 return absl::c_find_if(
322 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700323 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700324}
325
326// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800327static void AddMediaDescriptionOptions(MediaType type,
328 const std::string& mid,
329 RtpTransceiverDirection direction,
330 bool stopped,
331 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800332 opts->media_description_options.push_back(
333 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700334}
335
Steve Anton4e70a722017-11-28 14:57:10 -0800336static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700337 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800338 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
339 opts);
340 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
341 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700342}
343
344static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800345 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700346 MediaSessionOptions* opts) {
347 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800348 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700349}
350
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800351static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700352 const std::string& mid,
353 MediaType type,
354 const std::string& track_id,
355 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800356 const std::vector<RidDescription>& rids,
357 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700358 int num_sim_layer,
359 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700360 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
361 switch (type) {
362 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700363 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700364 break;
365 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800366 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
367 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700368 break;
369 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700370 RTC_CHECK(stream_ids.size() == 1U);
371 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700372 break;
373 default:
374 RTC_NOTREACHED();
375 }
376}
377
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800378static void AttachSenderToMediaDescriptionOptions(
379 const std::string& mid,
380 MediaType type,
381 const std::string& track_id,
382 const std::vector<std::string>& stream_ids,
383 int num_sim_layer,
384 MediaSessionOptions* session_options) {
385 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
386 SimulcastLayerList(), num_sim_layer,
387 session_options);
388}
389
zhihuang1c378ed2017-08-17 14:10:50 -0700390static void DetachSenderFromMediaSection(const std::string& mid,
391 const std::string& track_id,
392 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700393 std::vector<cricket::SenderOptions>& sender_options_list =
394 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
395 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800396 absl::c_find_if(sender_options_list,
397 [track_id](const cricket::SenderOptions& sender_options) {
398 return sender_options.track_id == track_id;
399 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700400 RTC_DCHECK(sender_it != sender_options_list.end());
401 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700402}
403
404// Helper function used to create a default MediaSessionOptions for Plan B SDP.
405// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
406static MediaSessionOptions CreatePlanBMediaSessionOptions() {
407 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800408 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
409 RtpTransceiverDirection::kRecvOnly, kActive,
410 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700411 return session_options;
412}
413
414// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
415// was designed for Plan B SDP, where only one audio "m=" section and one video
416// "m=" section could be generated, and ordering couldn't be controlled. Many of
417// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200418class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800420 MediaSessionDescriptionFactoryTest()
421 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700422 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
423 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000424 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200425 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700426 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
427 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000428 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200429 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200430 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700431 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200432 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700433 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 }
435
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000436 // Create a video StreamParamsVec object with:
437 // - one video stream with 3 simulcast streams and FEC,
438 StreamParamsVec CreateComplexVideoStreamParamsVec() {
439 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
440 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
441 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
442 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
443
444 std::vector<SsrcGroup> ssrc_groups;
445 ssrc_groups.push_back(sim_group);
446 ssrc_groups.push_back(fec_group1);
447 ssrc_groups.push_back(fec_group2);
448 ssrc_groups.push_back(fec_group3);
449
450 StreamParams simulcast_params;
451 simulcast_params.id = kVideoTrack1;
452 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
453 simulcast_params.ssrc_groups = ssrc_groups;
454 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800455 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000456
457 StreamParamsVec video_streams;
458 video_streams.push_back(simulcast_params);
459
460 return video_streams;
461 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462
463 bool CompareCryptoParams(const CryptoParamsVec& c1,
464 const CryptoParamsVec& c2) {
465 if (c1.size() != c2.size())
466 return false;
467 for (size_t i = 0; i < c1.size(); ++i)
468 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
469 c1[i].key_params != c2[i].key_params ||
470 c1[i].session_params != c2[i].session_params)
471 return false;
472 return true;
473 }
474
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700475 // Returns true if the transport info contains "renomination" as an
476 // ICE option.
477 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800478 return absl::c_linear_search(transport_info->description.transport_options,
479 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700480 }
481
zhihuang1c378ed2017-08-17 14:10:50 -0700482 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700483 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 bool has_current_desc) {
485 const std::string current_audio_ufrag = "current_audio_ufrag";
486 const std::string current_audio_pwd = "current_audio_pwd";
487 const std::string current_video_ufrag = "current_video_ufrag";
488 const std::string current_video_pwd = "current_video_pwd";
489 const std::string current_data_ufrag = "current_data_ufrag";
490 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800491 std::unique_ptr<SessionDescription> current_desc;
492 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200494 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800495 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200496 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800497 TransportDescription(current_audio_ufrag, current_audio_pwd)));
498 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200499 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800500 TransportDescription(current_video_ufrag, current_video_pwd)));
501 current_desc->AddTransportInfo(TransportInfo(
502 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000503 }
504 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800505 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 } else {
kwiberg31022942016-03-11 14:18:21 -0800507 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800508 offer = f1_.CreateOffer(options, NULL);
509 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 }
511 ASSERT_TRUE(desc.get() != NULL);
512 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000513 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 EXPECT_TRUE(ti_audio != NULL);
515 if (has_current_desc) {
516 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
517 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
518 } else {
519 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
520 ti_audio->description.ice_ufrag.size());
521 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
522 ti_audio->description.ice_pwd.size());
523 }
zhihuang1c378ed2017-08-17 14:10:50 -0700524 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700525 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700526 EXPECT_EQ(
527 media_desc_options_it->transport_options.enable_ice_renomination,
528 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700529 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
530 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531
532 } else {
533 EXPECT_TRUE(ti_audio == NULL);
534 }
535 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000536 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700538 auto media_desc_options_it =
539 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 if (options.bundle_enabled) {
541 EXPECT_EQ(ti_audio->description.ice_ufrag,
542 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200543 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700544 EXPECT_EQ(ti_audio->description.opaque_parameters,
545 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546 } else {
547 if (has_current_desc) {
548 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
549 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
550 } else {
551 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
552 ti_video->description.ice_ufrag.size());
553 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
554 ti_video->description.ice_pwd.size());
555 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700556 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
557 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558 }
zhihuang1c378ed2017-08-17 14:10:50 -0700559 EXPECT_EQ(
560 media_desc_options_it->transport_options.enable_ice_renomination,
561 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 } else {
563 EXPECT_TRUE(ti_video == NULL);
564 }
565 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
566 if (options.has_data()) {
567 EXPECT_TRUE(ti_data != NULL);
568 if (options.bundle_enabled) {
569 EXPECT_EQ(ti_audio->description.ice_ufrag,
570 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200571 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 } else {
573 if (has_current_desc) {
574 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
575 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
576 } else {
577 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
578 ti_data->description.ice_ufrag.size());
579 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
580 ti_data->description.ice_pwd.size());
581 }
582 }
zhihuang1c378ed2017-08-17 14:10:50 -0700583 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700584 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700585 EXPECT_EQ(
586 media_desc_options_it->transport_options.enable_ice_renomination,
587 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700588
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700590 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 }
592 }
593
594 void TestCryptoWithBundle(bool offer) {
595 f1_.set_secure(SEC_ENABLED);
596 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800597 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
598 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
599 &options);
kwiberg31022942016-03-11 14:18:21 -0800600 std::unique_ptr<SessionDescription> ref_desc;
601 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000602 if (offer) {
603 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800604 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800606 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 } else {
608 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800609 ref_desc = f1_.CreateOffer(options, NULL);
610 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000611 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800612 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800614 desc->GetContentDescriptionByName("audio");
615 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800617 desc->GetContentDescriptionByName("video");
618 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
620 video_media_desc->cryptos()));
621 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800622 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 audio_media_desc->cryptos()[0].cipher_suite);
624
625 // Verify the selected crypto is one from the reference audio
626 // media content.
627 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800628 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 bool found = false;
630 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
631 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200632 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000633 found = true;
634 break;
635 }
636 }
637 EXPECT_TRUE(found);
638 }
639
640 // This test that the audio and video media direction is set to
641 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700642 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800644 RtpTransceiverDirection direction_in_offer,
645 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700646 MediaSessionOptions offer_opts;
647 AddAudioVideoSections(direction_in_offer, &offer_opts);
648
Steve Anton6fe1fba2018-12-11 10:15:23 -0800649 std::unique_ptr<SessionDescription> offer =
650 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700652 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700654 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656
zhihuang1c378ed2017-08-17 14:10:50 -0700657 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800658 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800659 std::unique_ptr<SessionDescription> answer =
660 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 const AudioContentDescription* acd_answer =
662 GetFirstAudioContentDescription(answer.get());
663 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
664 const VideoContentDescription* vcd_answer =
665 GetFirstVideoContentDescription(answer.get());
666 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
667 }
668
669 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800670 RTC_DCHECK(content);
671 RTC_CHECK(content->media_description());
672 const cricket::AudioContentDescription* audio_desc =
673 content->media_description()->as_audio();
674 RTC_CHECK(audio_desc);
675 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
676 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800678 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679 }
680 return true;
681 }
682
jbauchcb560652016-08-04 05:20:32 -0700683 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
684 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800685 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700686 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700687
jbauchcb560652016-08-04 05:20:32 -0700688 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800689 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700690 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700691
jbauchcb560652016-08-04 05:20:32 -0700692 f1_.set_secure(SEC_ENABLED);
693 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800694 std::unique_ptr<SessionDescription> offer =
695 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700696 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800697 std::unique_ptr<SessionDescription> answer =
698 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700699 const ContentInfo* ac = answer->GetContentByName("audio");
700 const ContentInfo* vc = answer->GetContentByName("video");
701 ASSERT_TRUE(ac != NULL);
702 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800703 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
704 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800705 const AudioContentDescription* acd = ac->media_description()->as_audio();
706 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700707 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800708 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700709 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700710 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700711 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
712 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700713 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700714 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700715 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700716 }
717 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800718 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200719 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
720 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700721 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700722 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700723 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700724 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700725 }
Steve Antone38a5a12018-11-21 16:05:15 -0800726 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700727 }
728
Johannes Kronce8e8672019-02-22 13:06:44 +0100729 void TestTransportSequenceNumberNegotiation(
730 const cricket::RtpHeaderExtensions& local,
731 const cricket::RtpHeaderExtensions& offered,
732 const cricket::RtpHeaderExtensions& expectedAnswer) {
733 MediaSessionOptions opts;
734 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
735 f1_.set_audio_rtp_header_extensions(offered);
736 f1_.set_video_rtp_header_extensions(offered);
737 f2_.set_audio_rtp_header_extensions(local);
738 f2_.set_video_rtp_header_extensions(local);
739
740 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
741 ASSERT_TRUE(offer.get() != NULL);
742 std::unique_ptr<SessionDescription> answer =
743 f2_.CreateAnswer(offer.get(), opts, NULL);
744
745 EXPECT_EQ(
746 expectedAnswer,
747 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
748 EXPECT_EQ(
749 expectedAnswer,
750 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
751 }
752
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800754 UniqueRandomIdGenerator ssrc_generator1;
755 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000756 MediaSessionDescriptionFactory f1_;
757 MediaSessionDescriptionFactory f2_;
758 TransportDescriptionFactory tdf1_;
759 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760};
761
762// Create a typical audio offer, and ensure it matches what we expect.
763TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
764 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800765 std::unique_ptr<SessionDescription> offer =
766 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 ASSERT_TRUE(offer.get() != NULL);
768 const ContentInfo* ac = offer->GetContentByName("audio");
769 const ContentInfo* vc = offer->GetContentByName("video");
770 ASSERT_TRUE(ac != NULL);
771 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800772 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800773 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700775 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700776 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
778 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700779 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800780 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781}
782
783// Create a typical video offer, and ensure it matches what we expect.
784TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
785 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800786 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800788 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 ASSERT_TRUE(offer.get() != NULL);
790 const ContentInfo* ac = offer->GetContentByName("audio");
791 const ContentInfo* vc = offer->GetContentByName("video");
792 ASSERT_TRUE(ac != NULL);
793 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800794 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
795 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800796 const AudioContentDescription* acd = ac->media_description()->as_audio();
797 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700799 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700800 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
802 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700803 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800804 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000806 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700807 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
809 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700810 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800811 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812}
813
814// Test creating an offer with bundle where the Codecs have the same dynamic
815// RTP playlod type. The test verifies that the offer don't contain the
816// duplicate RTP payload types.
817TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000818 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700819 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200820 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
822 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
823
824 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800825 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
826 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800828 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829 const VideoContentDescription* vcd =
830 GetFirstVideoContentDescription(offer.get());
831 const AudioContentDescription* acd =
832 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200833 const RtpDataContentDescription* dcd =
834 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835 ASSERT_TRUE(NULL != vcd);
836 ASSERT_TRUE(NULL != acd);
837 ASSERT_TRUE(NULL != dcd);
838 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
839 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
840 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
841 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
842 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
843 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
844}
845
zhihuang1c378ed2017-08-17 14:10:50 -0700846// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847// after an audio only session has been negotiated.
848TEST_F(MediaSessionDescriptionFactoryTest,
849 TestCreateUpdatedVideoOfferWithBundle) {
850 f1_.set_secure(SEC_ENABLED);
851 f2_.set_secure(SEC_ENABLED);
852 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800853 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
854 RtpTransceiverDirection::kRecvOnly, kActive,
855 &opts);
856 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
857 RtpTransceiverDirection::kInactive, kStopped,
858 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 opts.data_channel_type = cricket::DCT_NONE;
860 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800861 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
862 std::unique_ptr<SessionDescription> answer =
863 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864
865 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800866 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
867 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
868 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800870 std::unique_ptr<SessionDescription> updated_offer(
871 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872
873 const AudioContentDescription* acd =
874 GetFirstAudioContentDescription(updated_offer.get());
875 const VideoContentDescription* vcd =
876 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200877 const RtpDataContentDescription* dcd =
878 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879 EXPECT_TRUE(NULL != vcd);
880 EXPECT_TRUE(NULL != acd);
881 EXPECT_TRUE(NULL != dcd);
882
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700883 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800884 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700885 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800886 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700887 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800888 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000889}
deadbeef44f08192015-12-15 16:20:09 -0800890
wu@webrtc.org78187522013-10-07 23:32:02 +0000891// Create a RTP data offer, and ensure it matches what we expect.
892TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800894 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
895 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800897 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000898 ASSERT_TRUE(offer.get() != NULL);
899 const ContentInfo* ac = offer->GetContentByName("audio");
900 const ContentInfo* dc = offer->GetContentByName("data");
901 ASSERT_TRUE(ac != NULL);
902 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800903 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
904 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800905 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200906 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700908 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700909 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000910 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
911 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700912 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800913 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200915 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700916 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000917 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200918 dcd->bandwidth()); // default bandwidth (auto)
919 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700920 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800921 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000922}
923
wu@webrtc.org78187522013-10-07 23:32:02 +0000924// Create an SCTP data offer with bundle without error.
925TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
926 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000927 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800928 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000929 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800930 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000931 EXPECT_TRUE(offer.get() != NULL);
932 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000933 auto dcd = GetFirstSctpDataContentDescription(offer.get());
934 ASSERT_TRUE(dcd);
935 // Since this transport is insecure, the protocol should be "SCTP".
936 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
937}
938
939// Create an SCTP data offer with bundle without error.
940TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
941 MediaSessionOptions opts;
942 opts.bundle_enabled = true;
943 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
944 f1_.set_secure(SEC_ENABLED);
945 tdf1_.set_secure(SEC_ENABLED);
946 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
947 EXPECT_TRUE(offer.get() != NULL);
948 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
949 auto dcd = GetFirstSctpDataContentDescription(offer.get());
950 ASSERT_TRUE(dcd);
951 // The protocol should now be "UDP/DTLS/SCTP"
952 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000953}
954
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000955// Test creating an sctp data channel from an already generated offer.
956TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
957 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000958 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800959 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000960 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800961 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000962 ASSERT_TRUE(offer1.get() != NULL);
963 const ContentInfo* data = offer1->GetContentByName("data");
964 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800965 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000966
967 // Now set data_channel_type to 'none' (default) and make sure that the
968 // datachannel type that gets generated from the previous offer, is of the
969 // same type.
970 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800971 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000972 f1_.CreateOffer(opts, offer1.get()));
973 data = offer2->GetContentByName("data");
974 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800975 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000976}
977
Steve Anton2bed3972019-01-04 17:04:30 -0800978// Test that if BUNDLE is enabled and all media sections are rejected then the
979// BUNDLE group is not present in the re-offer.
980TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
981 MediaSessionOptions opts;
982 opts.bundle_enabled = true;
983 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
984 RtpTransceiverDirection::kSendRecv, kActive,
985 &opts);
986 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
987
988 opts.media_description_options[0].stopped = true;
989 std::unique_ptr<SessionDescription> reoffer =
990 f1_.CreateOffer(opts, offer.get());
991
992 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
993}
994
995// Test that if BUNDLE is enabled and the remote re-offer does not include a
996// BUNDLE group since all media sections are rejected, then the re-answer also
997// does not include a BUNDLE group.
998TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
999 MediaSessionOptions opts;
1000 opts.bundle_enabled = true;
1001 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1002 RtpTransceiverDirection::kSendRecv, kActive,
1003 &opts);
1004 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1005 std::unique_ptr<SessionDescription> answer =
1006 f2_.CreateAnswer(offer.get(), opts, nullptr);
1007
1008 opts.media_description_options[0].stopped = true;
1009 std::unique_ptr<SessionDescription> reoffer =
1010 f1_.CreateOffer(opts, offer.get());
1011 std::unique_ptr<SessionDescription> reanswer =
1012 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1013
1014 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1015}
1016
1017// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1018// was rejected then the new offerer-tagged media section is the non-rejected
1019// media section.
1020TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1021 MediaSessionOptions opts;
1022 opts.bundle_enabled = true;
1023 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1024 RtpTransceiverDirection::kSendRecv, kActive,
1025 &opts);
1026 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1027
1028 // Reject the audio m= section and add a video m= section.
1029 opts.media_description_options[0].stopped = true;
1030 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1031 RtpTransceiverDirection::kSendRecv, kActive,
1032 &opts);
1033 std::unique_ptr<SessionDescription> reoffer =
1034 f1_.CreateOffer(opts, offer.get());
1035
1036 const cricket::ContentGroup* bundle_group =
1037 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1038 ASSERT_TRUE(bundle_group);
1039 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1040 EXPECT_TRUE(bundle_group->HasContentName("video"));
1041}
1042
1043// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1044// was rejected and a new media section is added, then the re-answer BUNDLE
1045// group will contain only the non-rejected media section.
1046TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1047 MediaSessionOptions opts;
1048 opts.bundle_enabled = true;
1049 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1050 RtpTransceiverDirection::kSendRecv, kActive,
1051 &opts);
1052 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1053 std::unique_ptr<SessionDescription> answer =
1054 f2_.CreateAnswer(offer.get(), opts, nullptr);
1055
1056 // Reject the audio m= section and add a video m= section.
1057 opts.media_description_options[0].stopped = true;
1058 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1059 RtpTransceiverDirection::kSendRecv, kActive,
1060 &opts);
1061 std::unique_ptr<SessionDescription> reoffer =
1062 f1_.CreateOffer(opts, offer.get());
1063 std::unique_ptr<SessionDescription> reanswer =
1064 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1065
1066 const cricket::ContentGroup* bundle_group =
1067 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1068 ASSERT_TRUE(bundle_group);
1069 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1070 EXPECT_TRUE(bundle_group->HasContentName("video"));
1071}
1072
1073// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1074// and there is still a non-rejected media section that was in the initial
1075// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1076// media section.
1077TEST_F(MediaSessionDescriptionFactoryTest,
1078 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1079 MediaSessionOptions opts;
1080 opts.bundle_enabled = true;
1081 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1082 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1083 std::unique_ptr<SessionDescription> answer =
1084 f2_.CreateAnswer(offer.get(), opts, nullptr);
1085
1086 // Reject the audio m= section.
1087 opts.media_description_options[0].stopped = true;
1088 std::unique_ptr<SessionDescription> reoffer =
1089 f1_.CreateOffer(opts, offer.get());
1090
1091 const TransportDescription* offer_tagged =
1092 offer->GetTransportDescriptionByName("audio");
1093 ASSERT_TRUE(offer_tagged);
1094 const TransportDescription* reoffer_tagged =
1095 reoffer->GetTransportDescriptionByName("video");
1096 ASSERT_TRUE(reoffer_tagged);
1097 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1098 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1099}
1100
1101// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1102// and there is still a non-rejected media section that was in the initial
1103// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1104// media section.
1105TEST_F(MediaSessionDescriptionFactoryTest,
1106 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1107 MediaSessionOptions opts;
1108 opts.bundle_enabled = true;
1109 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1110 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1111 std::unique_ptr<SessionDescription> answer =
1112 f2_.CreateAnswer(offer.get(), opts, nullptr);
1113
1114 // Reject the audio m= section.
1115 opts.media_description_options[0].stopped = true;
1116 std::unique_ptr<SessionDescription> reoffer =
1117 f1_.CreateOffer(opts, offer.get());
1118 std::unique_ptr<SessionDescription> reanswer =
1119 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1120
1121 const TransportDescription* answer_tagged =
1122 answer->GetTransportDescriptionByName("audio");
1123 ASSERT_TRUE(answer_tagged);
1124 const TransportDescription* reanswer_tagged =
1125 reanswer->GetTransportDescriptionByName("video");
1126 ASSERT_TRUE(reanswer_tagged);
1127 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1128 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1129}
1130
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131// Create an audio, video offer without legacy StreamParams.
1132TEST_F(MediaSessionDescriptionFactoryTest,
1133 TestCreateOfferWithoutLegacyStreams) {
1134 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001135 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001136 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137 ASSERT_TRUE(offer.get() != NULL);
1138 const ContentInfo* ac = offer->GetContentByName("audio");
1139 const ContentInfo* vc = offer->GetContentByName("video");
1140 ASSERT_TRUE(ac != NULL);
1141 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001142 const AudioContentDescription* acd = ac->media_description()->as_audio();
1143 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144
Yves Gerey665174f2018-06-19 15:03:05 +02001145 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1146 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001147}
1148
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001149// Creates an audio+video sendonly offer.
1150TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001151 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001152 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001153 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1154 {kMediaStream1}, 1, &opts);
1155 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1156 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001157
Steve Anton6fe1fba2018-12-11 10:15:23 -08001158 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001159 ASSERT_TRUE(offer.get() != NULL);
1160 EXPECT_EQ(2u, offer->contents().size());
1161 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1162 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1163
Steve Anton4e70a722017-11-28 14:57:10 -08001164 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1165 GetMediaDirection(&offer->contents()[0]));
1166 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1167 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001168}
1169
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001170// Verifies that the order of the media contents in the current
1171// SessionDescription is preserved in the new SessionDescription.
1172TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1173 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001174 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001175
kwiberg31022942016-03-11 14:18:21 -08001176 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001177 ASSERT_TRUE(offer1.get() != NULL);
1178 EXPECT_EQ(1u, offer1->contents().size());
1179 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1180
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001181 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1182 RtpTransceiverDirection::kRecvOnly, kActive,
1183 &opts);
kwiberg31022942016-03-11 14:18:21 -08001184 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001185 f1_.CreateOffer(opts, offer1.get()));
1186 ASSERT_TRUE(offer2.get() != NULL);
1187 EXPECT_EQ(2u, offer2->contents().size());
1188 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1189 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1190
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001191 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1192 RtpTransceiverDirection::kRecvOnly, kActive,
1193 &opts);
kwiberg31022942016-03-11 14:18:21 -08001194 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001195 f1_.CreateOffer(opts, offer2.get()));
1196 ASSERT_TRUE(offer3.get() != NULL);
1197 EXPECT_EQ(3u, offer3->contents().size());
1198 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1199 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1200 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001201}
1202
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203// Create a typical audio answer, and ensure it matches what we expect.
1204TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1205 f1_.set_secure(SEC_ENABLED);
1206 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001207 std::unique_ptr<SessionDescription> offer =
1208 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001209 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001210 std::unique_ptr<SessionDescription> answer =
1211 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212 const ContentInfo* ac = answer->GetContentByName("audio");
1213 const ContentInfo* vc = answer->GetContentByName("video");
1214 ASSERT_TRUE(ac != NULL);
1215 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001216 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001217 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001219 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001220 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1222 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001223 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001224 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225}
1226
jbauchcb560652016-08-04 05:20:32 -07001227// Create a typical audio answer with GCM ciphers enabled, and ensure it
1228// matches what we expect.
1229TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1230 f1_.set_secure(SEC_ENABLED);
1231 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001232 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001233 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001234 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001235 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001236 std::unique_ptr<SessionDescription> answer =
1237 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001238 const ContentInfo* ac = answer->GetContentByName("audio");
1239 const ContentInfo* vc = answer->GetContentByName("video");
1240 ASSERT_TRUE(ac != NULL);
1241 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001242 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001243 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001244 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001245 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001246 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001247 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1248 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001249 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001250 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001251}
1252
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253// Create a typical video answer, and ensure it matches what we expect.
1254TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1255 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001256 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257 f1_.set_secure(SEC_ENABLED);
1258 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001259 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001261 std::unique_ptr<SessionDescription> answer =
1262 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263 const ContentInfo* ac = answer->GetContentByName("audio");
1264 const ContentInfo* vc = answer->GetContentByName("video");
1265 ASSERT_TRUE(ac != NULL);
1266 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001267 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1268 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001269 const AudioContentDescription* acd = ac->media_description()->as_audio();
1270 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001272 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001273 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001274 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001276 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001277 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001278 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001279 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1280 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001281 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001282 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001283}
1284
jbauchcb560652016-08-04 05:20:32 -07001285// Create a typical video answer with GCM ciphers enabled, and ensure it
1286// matches what we expect.
1287TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1288 TestVideoGcmCipher(true, true);
1289}
1290
1291// Create a typical video answer with GCM ciphers enabled for the offer only,
1292// and ensure it matches what we expect.
1293TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1294 TestVideoGcmCipher(true, false);
1295}
1296
1297// Create a typical video answer with GCM ciphers enabled for the answer only,
1298// and ensure it matches what we expect.
1299TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1300 TestVideoGcmCipher(false, true);
1301}
1302
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001304 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001305 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001306 f1_.set_secure(SEC_ENABLED);
1307 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001308 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001310 std::unique_ptr<SessionDescription> answer =
1311 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001313 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001314 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001315 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001316 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1317 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001318 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001319 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001320 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001321 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001322 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001323 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001324 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001325 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001326 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001327 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001328 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001329 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001330 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001331 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332}
1333
jbauchcb560652016-08-04 05:20:32 -07001334TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001335 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001336 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001337 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001338 f1_.set_secure(SEC_ENABLED);
1339 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001340 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001341 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001342 std::unique_ptr<SessionDescription> answer =
1343 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001344 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001345 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001346 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001347 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001348 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1349 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001350 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001351 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001352 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001353 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001354 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001355 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001356 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001357 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001358 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001359 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001360 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001361 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001362 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001363 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001364}
1365
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001366// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1367// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001368TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1369 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001370 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001371 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001372 ASSERT_TRUE(offer.get() != NULL);
1373 ContentInfo* dc_offer = offer->GetContentByName("data");
1374 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001375 SctpDataContentDescription* dcd_offer =
1376 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001377 EXPECT_TRUE(dcd_offer->use_sctpmap());
1378
Steve Anton6fe1fba2018-12-11 10:15:23 -08001379 std::unique_ptr<SessionDescription> answer =
1380 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001381 const ContentInfo* dc_answer = answer->GetContentByName("data");
1382 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001383 const SctpDataContentDescription* dcd_answer =
1384 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001385 EXPECT_TRUE(dcd_answer->use_sctpmap());
1386}
1387
1388// The answer's use_sctpmap flag should match the offer's.
1389TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1390 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001391 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001392 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001393 ASSERT_TRUE(offer.get() != NULL);
1394 ContentInfo* dc_offer = offer->GetContentByName("data");
1395 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001396 SctpDataContentDescription* dcd_offer =
1397 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001398 dcd_offer->set_use_sctpmap(false);
1399
Steve Anton6fe1fba2018-12-11 10:15:23 -08001400 std::unique_ptr<SessionDescription> answer =
1401 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001402 const ContentInfo* dc_answer = answer->GetContentByName("data");
1403 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001404 const SctpDataContentDescription* dcd_answer =
1405 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001406 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001407}
1408
deadbeef8b7e9ad2017-05-25 09:38:55 -07001409// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1410// and "TCP/DTLS/SCTP" offers.
1411TEST_F(MediaSessionDescriptionFactoryTest,
1412 TestCreateDataAnswerToDifferentOfferedProtos) {
1413 // Need to enable DTLS offer/answer generation (disabled by default in this
1414 // test).
1415 f1_.set_secure(SEC_ENABLED);
1416 f2_.set_secure(SEC_ENABLED);
1417 tdf1_.set_secure(SEC_ENABLED);
1418 tdf2_.set_secure(SEC_ENABLED);
1419
1420 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001421 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001422 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001423 ASSERT_TRUE(offer.get() != nullptr);
1424 ContentInfo* dc_offer = offer->GetContentByName("data");
1425 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001426 SctpDataContentDescription* dcd_offer =
1427 dc_offer->media_description()->as_sctp();
1428 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001429
1430 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1431 "TCP/DTLS/SCTP"};
1432 for (const std::string& proto : protos) {
1433 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001434 std::unique_ptr<SessionDescription> answer =
1435 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001436 const ContentInfo* dc_answer = answer->GetContentByName("data");
1437 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001438 const SctpDataContentDescription* dcd_answer =
1439 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001440 EXPECT_FALSE(dc_answer->rejected);
1441 EXPECT_EQ(proto, dcd_answer->protocol());
1442 }
1443}
1444
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001445TEST_F(MediaSessionDescriptionFactoryTest,
1446 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1447 // Need to enable DTLS offer/answer generation (disabled by default in this
1448 // test).
1449 f1_.set_secure(SEC_ENABLED);
1450 f2_.set_secure(SEC_ENABLED);
1451 tdf1_.set_secure(SEC_ENABLED);
1452 tdf2_.set_secure(SEC_ENABLED);
1453
1454 MediaSessionOptions opts;
1455 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1456 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1457 ASSERT_TRUE(offer.get() != nullptr);
1458 ContentInfo* dc_offer = offer->GetContentByName("data");
1459 ASSERT_TRUE(dc_offer != nullptr);
1460 SctpDataContentDescription* dcd_offer =
1461 dc_offer->media_description()->as_sctp();
1462 ASSERT_TRUE(dcd_offer);
1463 dcd_offer->set_max_message_size(1234);
1464 std::unique_ptr<SessionDescription> answer =
1465 f2_.CreateAnswer(offer.get(), opts, nullptr);
1466 const ContentInfo* dc_answer = answer->GetContentByName("data");
1467 ASSERT_TRUE(dc_answer != nullptr);
1468 const SctpDataContentDescription* dcd_answer =
1469 dc_answer->media_description()->as_sctp();
1470 EXPECT_FALSE(dc_answer->rejected);
1471 EXPECT_EQ(1234, dcd_answer->max_message_size());
1472}
1473
1474TEST_F(MediaSessionDescriptionFactoryTest,
1475 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1476 // Need to enable DTLS offer/answer generation (disabled by default in this
1477 // test).
1478 f1_.set_secure(SEC_ENABLED);
1479 f2_.set_secure(SEC_ENABLED);
1480 tdf1_.set_secure(SEC_ENABLED);
1481 tdf2_.set_secure(SEC_ENABLED);
1482
1483 MediaSessionOptions opts;
1484 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1485 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1486 ASSERT_TRUE(offer.get() != nullptr);
1487 ContentInfo* dc_offer = offer->GetContentByName("data");
1488 ASSERT_TRUE(dc_offer != nullptr);
1489 SctpDataContentDescription* dcd_offer =
1490 dc_offer->media_description()->as_sctp();
1491 ASSERT_TRUE(dcd_offer);
1492 dcd_offer->set_max_message_size(0);
1493 std::unique_ptr<SessionDescription> answer =
1494 f2_.CreateAnswer(offer.get(), opts, nullptr);
1495 const ContentInfo* dc_answer = answer->GetContentByName("data");
1496 ASSERT_TRUE(dc_answer != nullptr);
1497 const SctpDataContentDescription* dcd_answer =
1498 dc_answer->media_description()->as_sctp();
1499 EXPECT_FALSE(dc_answer->rejected);
1500 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1501}
1502
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001503// Verifies that the order of the media contents in the offer is preserved in
1504// the answer.
1505TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1506 MediaSessionOptions opts;
1507
1508 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001509 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001510 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001511 ASSERT_TRUE(offer1.get() != NULL);
1512
1513 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001514 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1515 RtpTransceiverDirection::kRecvOnly, kActive,
1516 &opts);
kwiberg31022942016-03-11 14:18:21 -08001517 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001518 f1_.CreateOffer(opts, offer1.get()));
1519 ASSERT_TRUE(offer2.get() != NULL);
1520
1521 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001522 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1523 RtpTransceiverDirection::kRecvOnly, kActive,
1524 &opts);
kwiberg31022942016-03-11 14:18:21 -08001525 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001526 f1_.CreateOffer(opts, offer2.get()));
1527 ASSERT_TRUE(offer3.get() != NULL);
1528
Steve Anton6fe1fba2018-12-11 10:15:23 -08001529 std::unique_ptr<SessionDescription> answer =
1530 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001531 ASSERT_TRUE(answer.get() != NULL);
1532 EXPECT_EQ(3u, answer->contents().size());
1533 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1534 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1535 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1536}
1537
ossu075af922016-06-14 03:29:38 -07001538// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1539// answerer settings.
1540
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001541// This test that the media direction is set to send/receive in an answer if
1542// the offer is send receive.
1543TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001544 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1545 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001546}
1547
1548// This test that the media direction is set to receive only in an answer if
1549// the offer is send only.
1550TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001551 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1552 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001553}
1554
1555// This test that the media direction is set to send only in an answer if
1556// the offer is recv only.
1557TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001558 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1559 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560}
1561
1562// This test that the media direction is set to inactive in an answer if
1563// the offer is inactive.
1564TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001565 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1566 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001567}
1568
1569// Test that a data content with an unknown protocol is rejected in an answer.
1570TEST_F(MediaSessionDescriptionFactoryTest,
1571 CreateDataAnswerToOfferWithUnknownProtocol) {
1572 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001573 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574 f1_.set_secure(SEC_ENABLED);
1575 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001576 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001577 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001579 RtpDataContentDescription* dcd_offer =
1580 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001581 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001582 // Offer must be acceptable as an RTP protocol in order to be set.
1583 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001584 dcd_offer->set_protocol(protocol);
1585
Steve Anton6fe1fba2018-12-11 10:15:23 -08001586 std::unique_ptr<SessionDescription> answer =
1587 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001588
1589 const ContentInfo* dc_answer = answer->GetContentByName("data");
1590 ASSERT_TRUE(dc_answer != NULL);
1591 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001592 const RtpDataContentDescription* dcd_answer =
1593 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001594 ASSERT_TRUE(dcd_answer != NULL);
1595 EXPECT_EQ(protocol, dcd_answer->protocol());
1596}
1597
1598// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1599TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001600 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001601 f1_.set_secure(SEC_DISABLED);
1602 f2_.set_secure(SEC_DISABLED);
1603 tdf1_.set_secure(SEC_DISABLED);
1604 tdf2_.set_secure(SEC_DISABLED);
1605
Steve Anton6fe1fba2018-12-11 10:15:23 -08001606 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001607 const AudioContentDescription* offer_acd =
1608 GetFirstAudioContentDescription(offer.get());
1609 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001610 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611
Steve Anton6fe1fba2018-12-11 10:15:23 -08001612 std::unique_ptr<SessionDescription> answer =
1613 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001614
1615 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1616 ASSERT_TRUE(ac_answer != NULL);
1617 EXPECT_FALSE(ac_answer->rejected);
1618
1619 const AudioContentDescription* answer_acd =
1620 GetFirstAudioContentDescription(answer.get());
1621 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001622 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001623}
1624
1625// Create a video offer and answer and ensure the RTP header extensions
1626// matches what we expect.
1627TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1628 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001629 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001630 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1631 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1632 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1633 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1634
Steve Anton6fe1fba2018-12-11 10:15:23 -08001635 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001636 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001637 std::unique_ptr<SessionDescription> answer =
1638 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639
Yves Gerey665174f2018-06-19 15:03:05 +02001640 EXPECT_EQ(
1641 MAKE_VECTOR(kAudioRtpExtension1),
1642 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1643 EXPECT_EQ(
1644 MAKE_VECTOR(kVideoRtpExtension1),
1645 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1646 EXPECT_EQ(
1647 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1648 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1649 EXPECT_EQ(
1650 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1651 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001652}
1653
Johannes Kronce8e8672019-02-22 13:06:44 +01001654// Create a audio/video offer and answer and ensure that the
1655// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1656// supported and should take precedence even though not listed among locally
1657// supported extensions.
1658TEST_F(MediaSessionDescriptionFactoryTest,
1659 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1660 TestTransportSequenceNumberNegotiation(
1661 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1662 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1663 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1664}
1665TEST_F(MediaSessionDescriptionFactoryTest,
1666 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1667 TestTransportSequenceNumberNegotiation(
1668 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1669 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1670 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1671}
1672TEST_F(MediaSessionDescriptionFactoryTest,
1673 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1674 TestTransportSequenceNumberNegotiation(
1675 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1676 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1677 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1678}
1679
jbauch5869f502017-06-29 12:31:36 -07001680TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001681 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1682 MediaSessionOptions opts;
1683 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1684
1685 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1686 f1_.set_audio_rtp_header_extensions(offered);
1687 f1_.set_video_rtp_header_extensions(offered);
1688 const auto local = MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01);
1689 f2_.set_audio_rtp_header_extensions(local);
1690 f2_.set_video_rtp_header_extensions(local);
1691 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1692 std::unique_ptr<SessionDescription> answer =
1693 f2_.CreateAnswer(offer.get(), opts, nullptr);
1694 EXPECT_THAT(
1695 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1696 ElementsAreArray(offered));
1697 EXPECT_THAT(
1698 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1699 ElementsAreArray(offered));
1700}
1701
1702TEST_F(MediaSessionDescriptionFactoryTest,
1703 TestNegotiateFrameDescriptorWhenExposedLocally) {
1704 MediaSessionOptions opts;
1705 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1706
1707 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1708 f1_.set_audio_rtp_header_extensions(offered);
1709 f1_.set_video_rtp_header_extensions(offered);
1710 const auto local = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1711 f2_.set_audio_rtp_header_extensions(local);
1712 f2_.set_video_rtp_header_extensions(local);
1713 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1714 std::unique_ptr<SessionDescription> answer =
1715 f2_.CreateAnswer(offer.get(), opts, nullptr);
1716 EXPECT_THAT(
1717 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1718 ElementsAreArray(offered));
1719 EXPECT_THAT(
1720 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1721 ElementsAreArray(offered));
1722}
1723
1724TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001725 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001726 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001727 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001728
1729 f1_.set_enable_encrypted_rtp_header_extensions(true);
1730 f2_.set_enable_encrypted_rtp_header_extensions(true);
1731
Yves Gerey665174f2018-06-19 15:03:05 +02001732 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1733 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1734 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1735 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001736
Steve Anton6fe1fba2018-12-11 10:15:23 -08001737 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001738 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001739 std::unique_ptr<SessionDescription> answer =
1740 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001741
Yves Gerey665174f2018-06-19 15:03:05 +02001742 EXPECT_EQ(
1743 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1744 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1745 EXPECT_EQ(
1746 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1747 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1748 EXPECT_EQ(
1749 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1750 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1751 EXPECT_EQ(
1752 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1753 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001754}
1755
1756TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001757 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001758 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001759 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001760
1761 f1_.set_enable_encrypted_rtp_header_extensions(true);
1762
Yves Gerey665174f2018-06-19 15:03:05 +02001763 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1764 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1765 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1766 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001767
Steve Anton6fe1fba2018-12-11 10:15:23 -08001768 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001769 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001770 std::unique_ptr<SessionDescription> answer =
1771 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001772
Yves Gerey665174f2018-06-19 15:03:05 +02001773 EXPECT_EQ(
1774 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1775 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1776 EXPECT_EQ(
1777 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1778 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1779 EXPECT_EQ(
1780 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1781 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1782 EXPECT_EQ(
1783 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1784 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001785}
1786
1787TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001788 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001789 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001790 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001791
1792 f2_.set_enable_encrypted_rtp_header_extensions(true);
1793
Yves Gerey665174f2018-06-19 15:03:05 +02001794 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1795 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1796 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1797 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001798
Steve Anton6fe1fba2018-12-11 10:15:23 -08001799 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001800 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001801 std::unique_ptr<SessionDescription> answer =
1802 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001803
Yves Gerey665174f2018-06-19 15:03:05 +02001804 EXPECT_EQ(
1805 MAKE_VECTOR(kAudioRtpExtension1),
1806 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1807 EXPECT_EQ(
1808 MAKE_VECTOR(kVideoRtpExtension1),
1809 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1810 EXPECT_EQ(
1811 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1812 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1813 EXPECT_EQ(
1814 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1815 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001816}
1817
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001818// Create an audio, video, data answer without legacy StreamParams.
1819TEST_F(MediaSessionDescriptionFactoryTest,
1820 TestCreateAnswerWithoutLegacyStreams) {
1821 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001822 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1823 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001824 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001826 std::unique_ptr<SessionDescription> answer =
1827 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001828 const ContentInfo* ac = answer->GetContentByName("audio");
1829 const ContentInfo* vc = answer->GetContentByName("video");
1830 const ContentInfo* dc = answer->GetContentByName("data");
1831 ASSERT_TRUE(ac != NULL);
1832 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001833 const AudioContentDescription* acd = ac->media_description()->as_audio();
1834 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001835 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001836
1837 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1838 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1839 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1840}
1841
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001842// Create a typical video answer, and ensure it matches what we expect.
1843TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1844 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001845 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1846 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1847 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001848
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001849 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001850 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1851 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1852 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001853
kwiberg31022942016-03-11 14:18:21 -08001854 std::unique_ptr<SessionDescription> offer;
1855 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001856
1857 offer_opts.rtcp_mux_enabled = true;
1858 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001859 offer = f1_.CreateOffer(offer_opts, NULL);
1860 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001861 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1862 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001863 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001864 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1865 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001866 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001867 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1868 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001869 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001870 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1871 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001872 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001873
1874 offer_opts.rtcp_mux_enabled = true;
1875 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001876 offer = f1_.CreateOffer(offer_opts, NULL);
1877 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001878 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1879 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001880 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001881 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1882 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001883 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1885 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001886 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001887 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1888 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001889 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001890
1891 offer_opts.rtcp_mux_enabled = false;
1892 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001893 offer = f1_.CreateOffer(offer_opts, NULL);
1894 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001895 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1896 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001897 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001898 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1899 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001900 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001901 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1902 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001903 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001904 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1905 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001906 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001907
1908 offer_opts.rtcp_mux_enabled = false;
1909 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001910 offer = f1_.CreateOffer(offer_opts, NULL);
1911 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001912 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1913 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001914 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001915 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1916 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001917 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001918 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1919 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001920 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001921 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1922 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001923 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001924}
1925
1926// Create an audio-only answer to a video offer.
1927TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1928 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001929 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1930 RtpTransceiverDirection::kRecvOnly, kActive,
1931 &opts);
1932 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1933 RtpTransceiverDirection::kRecvOnly, kActive,
1934 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001935 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001936 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001937
1938 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001939 std::unique_ptr<SessionDescription> answer =
1940 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941 const ContentInfo* ac = answer->GetContentByName("audio");
1942 const ContentInfo* vc = answer->GetContentByName("video");
1943 ASSERT_TRUE(ac != NULL);
1944 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001945 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001946 EXPECT_TRUE(vc->rejected);
1947}
1948
1949// Create an audio-only answer to an offer with data.
1950TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001951 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001952 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001953 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1954 RtpTransceiverDirection::kRecvOnly, kActive,
1955 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001956 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001957 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001958
1959 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001960 std::unique_ptr<SessionDescription> answer =
1961 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001962 const ContentInfo* ac = answer->GetContentByName("audio");
1963 const ContentInfo* dc = answer->GetContentByName("data");
1964 ASSERT_TRUE(ac != NULL);
1965 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001966 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001967 EXPECT_TRUE(dc->rejected);
1968}
1969
1970// Create an answer that rejects the contents which are rejected in the offer.
1971TEST_F(MediaSessionDescriptionFactoryTest,
1972 CreateAnswerToOfferWithRejectedMedia) {
1973 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001974 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1975 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001976 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977 ASSERT_TRUE(offer.get() != NULL);
1978 ContentInfo* ac = offer->GetContentByName("audio");
1979 ContentInfo* vc = offer->GetContentByName("video");
1980 ContentInfo* dc = offer->GetContentByName("data");
1981 ASSERT_TRUE(ac != NULL);
1982 ASSERT_TRUE(vc != NULL);
1983 ASSERT_TRUE(dc != NULL);
1984 ac->rejected = true;
1985 vc->rejected = true;
1986 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001987 std::unique_ptr<SessionDescription> answer =
1988 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001989 ac = answer->GetContentByName("audio");
1990 vc = answer->GetContentByName("video");
1991 dc = answer->GetContentByName("data");
1992 ASSERT_TRUE(ac != NULL);
1993 ASSERT_TRUE(vc != NULL);
1994 ASSERT_TRUE(dc != NULL);
1995 EXPECT_TRUE(ac->rejected);
1996 EXPECT_TRUE(vc->rejected);
1997 EXPECT_TRUE(dc->rejected);
1998}
1999
Johannes Kron0854eb62018-10-10 22:33:20 +02002000TEST_F(MediaSessionDescriptionFactoryTest,
2001 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2002 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002003 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002004 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002005 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002006 ASSERT_TRUE(offer.get() != NULL);
2007 std::unique_ptr<SessionDescription> answer_no_support(
2008 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002009 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002010
2011 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002012 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002013 ASSERT_TRUE(offer.get() != NULL);
2014 std::unique_ptr<SessionDescription> answer_support(
2015 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002016 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002017}
2018
2019TEST_F(MediaSessionDescriptionFactoryTest,
2020 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2021 MediaSessionOptions opts;
2022 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002023 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002024 MediaContentDescription* video_offer =
2025 offer->GetContentDescriptionByName("video");
2026 ASSERT_TRUE(video_offer);
2027 MediaContentDescription* audio_offer =
2028 offer->GetContentDescriptionByName("audio");
2029 ASSERT_TRUE(audio_offer);
2030
2031 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002032 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2033 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002034
2035 ASSERT_TRUE(offer.get() != NULL);
2036 std::unique_ptr<SessionDescription> answer_no_support(
2037 f2_.CreateAnswer(offer.get(), opts, NULL));
2038 MediaContentDescription* video_answer =
2039 answer_no_support->GetContentDescriptionByName("video");
2040 MediaContentDescription* audio_answer =
2041 answer_no_support->GetContentDescriptionByName("audio");
2042 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002043 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002044 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002045 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002046
2047 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002048 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2049 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002050 ASSERT_TRUE(offer.get() != NULL);
2051 std::unique_ptr<SessionDescription> answer_support(
2052 f2_.CreateAnswer(offer.get(), opts, NULL));
2053 video_answer = answer_support->GetContentDescriptionByName("video");
2054 audio_answer = answer_support->GetContentDescriptionByName("audio");
2055 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002056 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002057 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002058 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002059}
2060
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002061// Create an audio and video offer with:
2062// - one video track
2063// - two audio tracks
2064// - two data tracks
2065// and ensure it matches what we expect. Also updates the initial offer by
2066// adding a new video track and replaces one of the audio tracks.
2067TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2068 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002069 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002070 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2071 {kMediaStream1}, 1, &opts);
2072 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2073 {kMediaStream1}, 1, &opts);
2074 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2075 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002076
Steve Anton4e70a722017-11-28 14:57:10 -08002077 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002078 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2079 {kMediaStream1}, 1, &opts);
2080 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2081 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002082
2083 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002084 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002085
2086 ASSERT_TRUE(offer.get() != NULL);
2087 const ContentInfo* ac = offer->GetContentByName("audio");
2088 const ContentInfo* vc = offer->GetContentByName("video");
2089 const ContentInfo* dc = offer->GetContentByName("data");
2090 ASSERT_TRUE(ac != NULL);
2091 ASSERT_TRUE(vc != NULL);
2092 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002093 const AudioContentDescription* acd = ac->media_description()->as_audio();
2094 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002095 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002096 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002097 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002098
2099 const StreamParamsVec& audio_streams = acd->streams();
2100 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002101 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002102 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2103 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2104 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2105 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2106 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2107 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2108
2109 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2110 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002111 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002112
2113 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002114 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002115 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002116
2117 const StreamParamsVec& video_streams = vcd->streams();
2118 ASSERT_EQ(1U, video_streams.size());
2119 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2120 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2121 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2122 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2123
2124 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002125 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002126 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002127
2128 const StreamParamsVec& data_streams = dcd->streams();
2129 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002130 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2132 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2133 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2134 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2135 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2136 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2137
2138 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002139 dcd->bandwidth()); // default bandwidth (auto)
2140 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002141 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002142
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002143 // Update the offer. Add a new video track that is not synched to the
2144 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002145 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2146 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002147 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002148 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2149 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002150 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002151 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2152 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002153 std::unique_ptr<SessionDescription> updated_offer(
2154 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155
2156 ASSERT_TRUE(updated_offer.get() != NULL);
2157 ac = updated_offer->GetContentByName("audio");
2158 vc = updated_offer->GetContentByName("video");
2159 dc = updated_offer->GetContentByName("data");
2160 ASSERT_TRUE(ac != NULL);
2161 ASSERT_TRUE(vc != NULL);
2162 ASSERT_TRUE(dc != NULL);
2163 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002164 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002165 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002166 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002167 const RtpDataContentDescription* updated_dcd =
2168 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002169
2170 EXPECT_EQ(acd->type(), updated_acd->type());
2171 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2172 EXPECT_EQ(vcd->type(), updated_vcd->type());
2173 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2174 EXPECT_EQ(dcd->type(), updated_dcd->type());
2175 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002176 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002177 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002178 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002180 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002181 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2182
2183 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2184 ASSERT_EQ(2U, updated_audio_streams.size());
2185 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2186 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2187 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2188 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2189 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2190
2191 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2192 ASSERT_EQ(2U, updated_video_streams.size());
2193 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2194 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002195 // All the media streams in one PeerConnection share one RTCP CNAME.
2196 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197
2198 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2199 ASSERT_EQ(2U, updated_data_streams.size());
2200 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2201 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2202 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2203 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2204 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002205 // The stream correctly got the CNAME from the MediaSessionOptions.
2206 // The Expected RTCP CNAME is the default one as we are using the default
2207 // MediaSessionOptions.
2208 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209}
2210
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002211// Create an offer with simulcast video stream.
2212TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2213 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002214 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2215 RtpTransceiverDirection::kRecvOnly, kActive,
2216 &opts);
2217 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2218 RtpTransceiverDirection::kSendRecv, kActive,
2219 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002220 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002221 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2222 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002223 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002224
2225 ASSERT_TRUE(offer.get() != NULL);
2226 const ContentInfo* vc = offer->GetContentByName("video");
2227 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002228 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002229
2230 const StreamParamsVec& video_streams = vcd->streams();
2231 ASSERT_EQ(1U, video_streams.size());
2232 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2233 const SsrcGroup* sim_ssrc_group =
2234 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2235 ASSERT_TRUE(sim_ssrc_group != NULL);
2236 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2237}
2238
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002239MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2240 const RidDescription& rid1 = ::testing::get<0>(arg);
2241 const RidDescription& rid2 = ::testing::get<1>(arg);
2242 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2243}
2244
2245static void CheckSimulcastInSessionDescription(
2246 const SessionDescription* description,
2247 const std::string& content_name,
2248 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002249 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002250 ASSERT_NE(description, nullptr);
2251 const ContentInfo* content = description->GetContentByName(content_name);
2252 ASSERT_NE(content, nullptr);
2253 const MediaContentDescription* cd = content->media_description();
2254 ASSERT_NE(cd, nullptr);
2255 const StreamParamsVec& streams = cd->streams();
2256 ASSERT_THAT(streams, SizeIs(1));
2257 const StreamParams& stream = streams[0];
2258 ASSERT_THAT(stream.ssrcs, IsEmpty());
2259 EXPECT_TRUE(stream.has_rids());
2260 const std::vector<RidDescription> rids = stream.rids();
2261
2262 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2263
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002264 EXPECT_TRUE(cd->HasSimulcast());
2265 const SimulcastDescription& simulcast = cd->simulcast_description();
2266 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2267 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2268
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002269 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002270}
2271
2272// Create an offer with spec-compliant simulcast video stream.
2273TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2274 MediaSessionOptions opts;
2275 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2276 RtpTransceiverDirection::kSendRecv, kActive,
2277 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002278 std::vector<RidDescription> send_rids;
2279 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2280 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2281 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2282 SimulcastLayerList simulcast_layers;
2283 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2284 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2285 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2286 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2287 {kMediaStream1}, send_rids,
2288 simulcast_layers, 0, &opts);
2289 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2290
2291 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002292 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002293}
2294
2295// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2296// In this scenario, RIDs do not need to be negotiated (there is only one).
2297TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2298 MediaSessionOptions opts;
2299 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2300 RtpTransceiverDirection::kSendRecv, kActive,
2301 &opts);
2302 RidDescription rid("f", RidDirection::kSend);
2303 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2304 {kMediaStream1}, {rid},
2305 SimulcastLayerList(), 0, &opts);
2306 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2307
2308 ASSERT_NE(offer.get(), nullptr);
2309 const ContentInfo* content = offer->GetContentByName("video");
2310 ASSERT_NE(content, nullptr);
2311 const MediaContentDescription* cd = content->media_description();
2312 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002313 const StreamParamsVec& streams = cd->streams();
2314 ASSERT_THAT(streams, SizeIs(1));
2315 const StreamParams& stream = streams[0];
2316 ASSERT_THAT(stream.ssrcs, IsEmpty());
2317 EXPECT_FALSE(stream.has_rids());
2318 EXPECT_FALSE(cd->HasSimulcast());
2319}
2320
2321// Create an answer with spec-compliant simulcast video stream.
2322// In this scenario, the SFU is the caller requesting that we send Simulcast.
2323TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2324 MediaSessionOptions offer_opts;
2325 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2326 RtpTransceiverDirection::kSendRecv, kActive,
2327 &offer_opts);
2328 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2329 {kMediaStream1}, 1, &offer_opts);
2330 std::unique_ptr<SessionDescription> offer =
2331 f1_.CreateOffer(offer_opts, nullptr);
2332
2333 MediaSessionOptions answer_opts;
2334 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2335 RtpTransceiverDirection::kSendRecv, kActive,
2336 &answer_opts);
2337
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002338 std::vector<RidDescription> rid_descriptions{
2339 RidDescription("f", RidDirection::kSend),
2340 RidDescription("h", RidDirection::kSend),
2341 RidDescription("q", RidDirection::kSend),
2342 };
2343 SimulcastLayerList simulcast_layers;
2344 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2345 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2346 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2347 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2348 {kMediaStream1}, rid_descriptions,
2349 simulcast_layers, 0, &answer_opts);
2350 std::unique_ptr<SessionDescription> answer =
2351 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2352
2353 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002354 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002355}
2356
2357// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2358// In this scenario, RIDs do not need to be negotiated (there is only one).
2359// Note that RID Direction is not the same as the transceiver direction.
2360TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2361 MediaSessionOptions offer_opts;
2362 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2363 RtpTransceiverDirection::kSendRecv, kActive,
2364 &offer_opts);
2365 RidDescription rid_offer("f", RidDirection::kSend);
2366 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2367 {kMediaStream1}, {rid_offer},
2368 SimulcastLayerList(), 0, &offer_opts);
2369 std::unique_ptr<SessionDescription> offer =
2370 f1_.CreateOffer(offer_opts, nullptr);
2371
2372 MediaSessionOptions answer_opts;
2373 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2374 RtpTransceiverDirection::kSendRecv, kActive,
2375 &answer_opts);
2376
2377 RidDescription rid_answer("f", RidDirection::kReceive);
2378 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2379 {kMediaStream1}, {rid_answer},
2380 SimulcastLayerList(), 0, &answer_opts);
2381 std::unique_ptr<SessionDescription> answer =
2382 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2383
2384 ASSERT_NE(answer.get(), nullptr);
2385 const ContentInfo* content = offer->GetContentByName("video");
2386 ASSERT_NE(content, nullptr);
2387 const MediaContentDescription* cd = content->media_description();
2388 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002389 const StreamParamsVec& streams = cd->streams();
2390 ASSERT_THAT(streams, SizeIs(1));
2391 const StreamParams& stream = streams[0];
2392 ASSERT_THAT(stream.ssrcs, IsEmpty());
2393 EXPECT_FALSE(stream.has_rids());
2394 EXPECT_FALSE(cd->HasSimulcast());
2395}
2396
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002397// Create an audio and video answer to a standard video offer with:
2398// - one video track
2399// - two audio tracks
2400// - two data tracks
2401// and ensure it matches what we expect. Also updates the initial answer by
2402// adding a new video track and removes one of the audio tracks.
2403TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2404 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002405 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2406 RtpTransceiverDirection::kRecvOnly, kActive,
2407 &offer_opts);
2408 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2409 RtpTransceiverDirection::kRecvOnly, kActive,
2410 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002411 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002412 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2413 RtpTransceiverDirection::kRecvOnly, kActive,
2414 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002415 f1_.set_secure(SEC_ENABLED);
2416 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002417 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002418
zhihuang1c378ed2017-08-17 14:10:50 -07002419 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002420 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2421 RtpTransceiverDirection::kSendRecv, kActive,
2422 &answer_opts);
2423 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2424 RtpTransceiverDirection::kSendRecv, kActive,
2425 &answer_opts);
2426 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2427 {kMediaStream1}, 1, &answer_opts);
2428 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2429 {kMediaStream1}, 1, &answer_opts);
2430 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2431 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002432
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002433 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2434 RtpTransceiverDirection::kSendRecv, kActive,
2435 &answer_opts);
2436 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2437 {kMediaStream1}, 1, &answer_opts);
2438 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2439 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002440 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002441
Steve Anton6fe1fba2018-12-11 10:15:23 -08002442 std::unique_ptr<SessionDescription> answer =
2443 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002444
2445 ASSERT_TRUE(answer.get() != NULL);
2446 const ContentInfo* ac = answer->GetContentByName("audio");
2447 const ContentInfo* vc = answer->GetContentByName("video");
2448 const ContentInfo* dc = answer->GetContentByName("data");
2449 ASSERT_TRUE(ac != NULL);
2450 ASSERT_TRUE(vc != NULL);
2451 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002452 const AudioContentDescription* acd = ac->media_description()->as_audio();
2453 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002454 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002455 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2456 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2457 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002458
2459 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002460 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002461
2462 const StreamParamsVec& audio_streams = acd->streams();
2463 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002464 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002465 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2466 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2467 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2468 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2469 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2470 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2471
2472 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2473 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2474
2475 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002476 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002477
2478 const StreamParamsVec& video_streams = vcd->streams();
2479 ASSERT_EQ(1U, video_streams.size());
2480 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2481 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2482 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2483 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2484
2485 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002486 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002487
2488 const StreamParamsVec& data_streams = dcd->streams();
2489 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002490 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002491 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2492 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2493 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2494 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2495 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2496 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2497
2498 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002499 dcd->bandwidth()); // default bandwidth (auto)
2500 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002501
2502 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002503 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002504 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2505 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002506 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2507 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002508 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002509 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002510
2511 ASSERT_TRUE(updated_answer.get() != NULL);
2512 ac = updated_answer->GetContentByName("audio");
2513 vc = updated_answer->GetContentByName("video");
2514 dc = updated_answer->GetContentByName("data");
2515 ASSERT_TRUE(ac != NULL);
2516 ASSERT_TRUE(vc != NULL);
2517 ASSERT_TRUE(dc != NULL);
2518 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002519 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002520 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002521 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002522 const RtpDataContentDescription* updated_dcd =
2523 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002524
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002525 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002527 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002529 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2531
2532 EXPECT_EQ(acd->type(), updated_acd->type());
2533 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2534 EXPECT_EQ(vcd->type(), updated_vcd->type());
2535 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2536 EXPECT_EQ(dcd->type(), updated_dcd->type());
2537 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2538
2539 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2540 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002541 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002542
2543 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2544 ASSERT_EQ(2U, updated_video_streams.size());
2545 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2546 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002547 // All media streams in one PeerConnection share one CNAME.
2548 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002549
2550 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2551 ASSERT_EQ(1U, updated_data_streams.size());
2552 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2553}
2554
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002555// Create an updated offer after creating an answer to the original offer and
2556// verify that the codecs that were part of the original answer are not changed
2557// in the updated offer.
2558TEST_F(MediaSessionDescriptionFactoryTest,
2559 RespondentCreatesOfferAfterCreatingAnswer) {
2560 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002561 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002562
Steve Anton6fe1fba2018-12-11 10:15:23 -08002563 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2564 std::unique_ptr<SessionDescription> answer =
2565 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002566
2567 const AudioContentDescription* acd =
2568 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002569 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002570
2571 const VideoContentDescription* vcd =
2572 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002573 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002574
kwiberg31022942016-03-11 14:18:21 -08002575 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002576 f2_.CreateOffer(opts, answer.get()));
2577
2578 // The expected audio codecs are the common audio codecs from the first
2579 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2580 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002581 // TODO(wu): |updated_offer| should not include the codec
2582 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002583 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002584 kAudioCodecsAnswer[0],
2585 kAudioCodecsAnswer[1],
2586 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002587 };
2588
2589 // The expected video codecs are the common video codecs from the first
2590 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2591 // preference order.
2592 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002593 kVideoCodecsAnswer[0],
2594 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002595 };
2596
2597 const AudioContentDescription* updated_acd =
2598 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002599 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002600
2601 const VideoContentDescription* updated_vcd =
2602 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002603 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002604}
2605
Steve Anton5c72e712018-12-10 14:25:30 -08002606// Test that a reoffer does not reuse audio codecs from a previous media section
2607// that is being recycled.
2608TEST_F(MediaSessionDescriptionFactoryTest,
2609 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002610 f1_.set_video_codecs({});
2611 f2_.set_video_codecs({});
Steve Anton5c72e712018-12-10 14:25:30 -08002612
2613 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002614 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2615 RtpTransceiverDirection::kSendRecv, kActive,
2616 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002617 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2618 std::unique_ptr<SessionDescription> answer =
2619 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002620
2621 // Recycle the media section by changing its mid.
2622 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002623 std::unique_ptr<SessionDescription> reoffer =
2624 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002625
2626 // Expect that the results of the first negotiation are ignored. If the m=
2627 // section was not recycled the payload types would match the initial offerer.
2628 const AudioContentDescription* acd =
2629 GetFirstAudioContentDescription(reoffer.get());
2630 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2631}
2632
2633// Test that a reoffer does not reuse video codecs from a previous media section
2634// that is being recycled.
2635TEST_F(MediaSessionDescriptionFactoryTest,
2636 ReOfferDoesNotReUseRecycledVideoCodecs) {
2637 f1_.set_audio_codecs({}, {});
2638 f2_.set_audio_codecs({}, {});
2639
2640 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002641 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2642 RtpTransceiverDirection::kSendRecv, kActive,
2643 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002644 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2645 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002646
2647 // Recycle the media section by changing its mid.
2648 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002649 std::unique_ptr<SessionDescription> reoffer =
2650 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002651
2652 // Expect that the results of the first negotiation are ignored. If the m=
2653 // section was not recycled the payload types would match the initial offerer.
2654 const VideoContentDescription* vcd =
2655 GetFirstVideoContentDescription(reoffer.get());
2656 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2657}
2658
2659// Test that a reanswer does not reuse audio codecs from a previous media
2660// section that is being recycled.
2661TEST_F(MediaSessionDescriptionFactoryTest,
2662 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002663 f1_.set_video_codecs({});
2664 f2_.set_video_codecs({});
Steve Anton5c72e712018-12-10 14:25:30 -08002665
2666 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2667 // second offer/answer is forward (|f1_| as offerer).
2668 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002669 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2670 RtpTransceiverDirection::kSendRecv, kActive,
2671 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002672 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2673 std::unique_ptr<SessionDescription> answer =
2674 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002675
2676 // Recycle the media section by changing its mid.
2677 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002678 std::unique_ptr<SessionDescription> reoffer =
2679 f1_.CreateOffer(opts, answer.get());
2680 std::unique_ptr<SessionDescription> reanswer =
2681 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002682
2683 // Expect that the results of the first negotiation are ignored. If the m=
2684 // section was not recycled the payload types would match the initial offerer.
2685 const AudioContentDescription* acd =
2686 GetFirstAudioContentDescription(reanswer.get());
2687 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2688}
2689
2690// Test that a reanswer does not reuse video codecs from a previous media
2691// section that is being recycled.
2692TEST_F(MediaSessionDescriptionFactoryTest,
2693 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2694 f1_.set_audio_codecs({}, {});
2695 f2_.set_audio_codecs({}, {});
2696
2697 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2698 // second offer/answer is forward (|f1_| as offerer).
2699 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002700 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2701 RtpTransceiverDirection::kSendRecv, kActive,
2702 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002703 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2704 std::unique_ptr<SessionDescription> answer =
2705 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002706
2707 // Recycle the media section by changing its mid.
2708 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002709 std::unique_ptr<SessionDescription> reoffer =
2710 f1_.CreateOffer(opts, answer.get());
2711 std::unique_ptr<SessionDescription> reanswer =
2712 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002713
2714 // Expect that the results of the first negotiation are ignored. If the m=
2715 // section was not recycled the payload types would match the initial offerer.
2716 const VideoContentDescription* vcd =
2717 GetFirstVideoContentDescription(reanswer.get());
2718 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2719}
2720
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002721// Create an updated offer after creating an answer to the original offer and
2722// verify that the codecs that were part of the original answer are not changed
2723// in the updated offer. In this test Rtx is enabled.
2724TEST_F(MediaSessionDescriptionFactoryTest,
2725 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2726 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002727 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2728 RtpTransceiverDirection::kRecvOnly, kActive,
2729 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002731 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002732 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002733 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002734
2735 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002736 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002737 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002738 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002739
Steve Anton6fe1fba2018-12-11 10:15:23 -08002740 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002741 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002742 std::unique_ptr<SessionDescription> answer =
2743 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002744
2745 const VideoContentDescription* vcd =
2746 GetFirstVideoContentDescription(answer.get());
2747
2748 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002749 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2750 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002751
2752 EXPECT_EQ(expected_codecs, vcd->codecs());
2753
deadbeef67cf2c12016-04-13 10:07:16 -07002754 // Now, make sure we get same result (except for the order) if |f2_| creates
2755 // an updated offer even though the default payload types between |f1_| and
2756 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002757 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758 f2_.CreateOffer(opts, answer.get()));
2759 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002760 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002761 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2762
2763 const VideoContentDescription* updated_vcd =
2764 GetFirstVideoContentDescription(updated_answer.get());
2765
2766 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2767}
2768
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002769// Regression test for:
2770// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2771// Existing codecs should always appear before new codecs in re-offers. But
2772// under a specific set of circumstances, the existing RTX codec was ending up
2773// added to the end of the list.
2774TEST_F(MediaSessionDescriptionFactoryTest,
2775 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2776 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002777 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2778 RtpTransceiverDirection::kRecvOnly, kActive,
2779 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002780 // We specifically choose different preferred payload types for VP8 to
2781 // trigger the issue.
2782 cricket::VideoCodec vp8_offerer(100, "VP8");
2783 cricket::VideoCodec vp8_offerer_rtx =
2784 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2785 cricket::VideoCodec vp8_answerer(110, "VP8");
2786 cricket::VideoCodec vp8_answerer_rtx =
2787 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2788 cricket::VideoCodec vp9(120, "VP9");
2789 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2790
2791 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2792 // We also specifically cause the answerer to prefer VP9, such that if it
2793 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2794 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2795 vp8_answerer_rtx};
2796
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002797 f1_.set_video_codecs(f1_codecs);
2798 f2_.set_video_codecs(f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002799 std::vector<AudioCodec> audio_codecs;
2800 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2801 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2802
2803 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002804 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002805 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002806 std::unique_ptr<SessionDescription> answer =
2807 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002808
2809 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2810 // But if the bug is triggered, RTX for VP8 ends up last.
2811 std::unique_ptr<SessionDescription> updated_offer(
2812 f2_.CreateOffer(opts, answer.get()));
2813
2814 const VideoContentDescription* vcd =
2815 GetFirstVideoContentDescription(updated_offer.get());
2816 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2817 ASSERT_EQ(4u, codecs.size());
2818 EXPECT_EQ(vp8_offerer, codecs[0]);
2819 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2820 EXPECT_EQ(vp9, codecs[2]);
2821 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002822}
2823
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002824// Create an updated offer that adds video after creating an audio only answer
2825// to the original offer. This test verifies that if a video codec and the RTX
2826// codec have the same default payload type as an audio codec that is already in
2827// use, the added codecs payload types are changed.
2828TEST_F(MediaSessionDescriptionFactoryTest,
2829 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2830 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002831 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002832 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002833 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002834
2835 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002836 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2837 RtpTransceiverDirection::kRecvOnly, kActive,
2838 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002839
Steve Anton6fe1fba2018-12-11 10:15:23 -08002840 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2841 std::unique_ptr<SessionDescription> answer =
2842 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002843
2844 const AudioContentDescription* acd =
2845 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002846 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002847
2848 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2849 // reference be the same as an audio codec that was negotiated in the
2850 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002851 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002852 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002853
2854 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2855 int used_pl_type = acd->codecs()[0].id;
2856 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002857 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002858 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002859
kwiberg31022942016-03-11 14:18:21 -08002860 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861 f2_.CreateOffer(opts, answer.get()));
2862 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002863 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002864 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2865
2866 const AudioContentDescription* updated_acd =
2867 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002868 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002869
2870 const VideoContentDescription* updated_vcd =
2871 GetFirstVideoContentDescription(updated_answer.get());
2872
2873 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002874 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002875 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002876 EXPECT_NE(used_pl_type, new_h264_pl_type);
2877 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002878 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002879 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2880 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2881}
2882
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002883// Create an updated offer with RTX after creating an answer to an offer
2884// without RTX, and with different default payload types.
2885// Verify that the added RTX codec references the correct payload type.
2886TEST_F(MediaSessionDescriptionFactoryTest,
2887 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2888 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002889 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002890
2891 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2892 // This creates rtx for H264 with the payload type |f2_| uses.
2893 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002894 f2_.set_video_codecs(f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002895
Steve Anton6fe1fba2018-12-11 10:15:23 -08002896 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002897 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002898 std::unique_ptr<SessionDescription> answer =
2899 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002900
2901 const VideoContentDescription* vcd =
2902 GetFirstVideoContentDescription(answer.get());
2903
2904 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2905 EXPECT_EQ(expected_codecs, vcd->codecs());
2906
2907 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2908 // updated offer, even though the default payload types are different from
2909 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002910 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002911 f2_.CreateOffer(opts, answer.get()));
2912 ASSERT_TRUE(updated_offer);
2913
2914 const VideoContentDescription* updated_vcd =
2915 GetFirstVideoContentDescription(updated_offer.get());
2916
2917 // New offer should attempt to add H263, and RTX for H264.
2918 expected_codecs.push_back(kVideoCodecs2[1]);
2919 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2920 &expected_codecs);
2921 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2922}
2923
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002924// Test that RTX is ignored when there is no associated payload type parameter.
2925TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2926 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002927 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2928 RtpTransceiverDirection::kRecvOnly, kActive,
2929 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002930 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002931 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002932 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002933 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002934
2935 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002936 // This creates RTX for H264 with the payload type |f2_| uses.
2937 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002938 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002939
Steve Anton6fe1fba2018-12-11 10:15:23 -08002940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002941 ASSERT_TRUE(offer.get() != NULL);
2942 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2943 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2944 // is possible to test that that RTX is dropped when
2945 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002946 MediaContentDescription* media_desc =
2947 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2948 ASSERT_TRUE(media_desc);
2949 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002950 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002951 for (VideoCodec& codec : codecs) {
2952 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2953 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002954 }
2955 }
2956 desc->set_codecs(codecs);
2957
Steve Anton6fe1fba2018-12-11 10:15:23 -08002958 std::unique_ptr<SessionDescription> answer =
2959 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002960
Steve Anton64b626b2019-01-28 17:25:26 -08002961 EXPECT_THAT(
2962 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2963 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002964}
2965
2966// Test that RTX will be filtered out in the answer if its associated payload
2967// type doesn't match the local value.
2968TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2969 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002970 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2971 RtpTransceiverDirection::kRecvOnly, kActive,
2972 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002973 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2974 // This creates RTX for H264 in sender.
2975 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002976 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002977
2978 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2979 // This creates RTX for H263 in receiver.
2980 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002981 f2_.set_video_codecs(f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002982
Steve Anton6fe1fba2018-12-11 10:15:23 -08002983 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002984 ASSERT_TRUE(offer.get() != NULL);
2985 // Associated payload type doesn't match, therefore, RTX codec is removed in
2986 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002987 std::unique_ptr<SessionDescription> answer =
2988 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002989
Steve Anton64b626b2019-01-28 17:25:26 -08002990 EXPECT_THAT(
2991 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2992 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002993}
2994
2995// Test that when multiple RTX codecs are offered, only the matched RTX codec
2996// is added in the answer, and the unsupported RTX codec is filtered out.
2997TEST_F(MediaSessionDescriptionFactoryTest,
2998 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2999 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003000 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3001 RtpTransceiverDirection::kRecvOnly, kActive,
3002 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003003 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3004 // This creates RTX for H264-SVC in sender.
3005 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003006 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003007
3008 // This creates RTX for H264 in sender.
3009 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003010 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003011
3012 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3013 // This creates RTX for H264 in receiver.
3014 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003015 f2_.set_video_codecs(f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003016
3017 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3018 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003019 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003020 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003021 std::unique_ptr<SessionDescription> answer =
3022 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003023 const VideoContentDescription* vcd =
3024 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003025 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3026 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3027 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003028
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003029 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003030}
3031
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003032// Test that after one RTX codec has been negotiated, a new offer can attempt
3033// to add another.
3034TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3035 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003036 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3037 RtpTransceiverDirection::kRecvOnly, kActive,
3038 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003039 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3040 // This creates RTX for H264 for the offerer.
3041 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003042 f1_.set_video_codecs(f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003043
Steve Anton6fe1fba2018-12-11 10:15:23 -08003044 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003045 ASSERT_TRUE(offer);
3046 const VideoContentDescription* vcd =
3047 GetFirstVideoContentDescription(offer.get());
3048
3049 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3050 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3051 &expected_codecs);
3052 EXPECT_EQ(expected_codecs, vcd->codecs());
3053
3054 // Now, attempt to add RTX for H264-SVC.
3055 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003056 f1_.set_video_codecs(f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003057
kwiberg31022942016-03-11 14:18:21 -08003058 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003059 f1_.CreateOffer(opts, offer.get()));
3060 ASSERT_TRUE(updated_offer);
3061 vcd = GetFirstVideoContentDescription(updated_offer.get());
3062
3063 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3064 &expected_codecs);
3065 EXPECT_EQ(expected_codecs, vcd->codecs());
3066}
3067
Noah Richards2e7a0982015-05-18 14:02:54 -07003068// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3069// generated for each simulcast ssrc and correctly grouped.
3070TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3071 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003072 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3073 RtpTransceiverDirection::kSendRecv, kActive,
3074 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003075 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003076 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3077 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003078
3079 // Use a single real codec, and then add RTX for it.
3080 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003081 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003082 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003083 f1_.set_video_codecs(f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003084
3085 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3086 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003087 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003088 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003089 MediaContentDescription* media_desc =
3090 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3091 ASSERT_TRUE(media_desc);
3092 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003093 const StreamParamsVec& streams = desc->streams();
3094 // Single stream.
3095 ASSERT_EQ(1u, streams.size());
3096 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3097 EXPECT_EQ(6u, streams[0].ssrcs.size());
3098 // And should have a SIM group for the simulcast.
3099 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3100 // And a FID group for RTX.
3101 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003102 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003103 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3104 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003105 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003106 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3107 EXPECT_EQ(3u, fid_ssrcs.size());
3108}
3109
brandtr03d5fb12016-11-22 03:37:59 -08003110// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3111// together with a FEC-FR grouping.
3112TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3113 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003114 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3115 RtpTransceiverDirection::kSendRecv, kActive,
3116 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003117 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003118 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3119 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003120
3121 // Use a single real codec, and then add FlexFEC for it.
3122 std::vector<VideoCodec> f1_codecs;
3123 f1_codecs.push_back(VideoCodec(97, "H264"));
3124 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003125 f1_.set_video_codecs(f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003126
3127 // Ensure that the offer has a single FlexFEC ssrc and that
3128 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003129 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003130 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003131 MediaContentDescription* media_desc =
3132 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3133 ASSERT_TRUE(media_desc);
3134 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003135 const StreamParamsVec& streams = desc->streams();
3136 // Single stream.
3137 ASSERT_EQ(1u, streams.size());
3138 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3139 EXPECT_EQ(2u, streams[0].ssrcs.size());
3140 // And should have a FEC-FR group for FlexFEC.
3141 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3142 std::vector<uint32_t> primary_ssrcs;
3143 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3144 ASSERT_EQ(1u, primary_ssrcs.size());
3145 uint32_t flexfec_ssrc;
3146 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3147 EXPECT_NE(flexfec_ssrc, 0u);
3148}
3149
3150// Test that FlexFEC is disabled for simulcast.
3151// TODO(brandtr): Remove this test when we support simulcast, either through
3152// multiple FlexfecSenders, or through multistream protection.
3153TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3154 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003155 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3156 RtpTransceiverDirection::kSendRecv, kActive,
3157 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003158 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003159 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3160 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003161
3162 // Use a single real codec, and then add FlexFEC for it.
3163 std::vector<VideoCodec> f1_codecs;
3164 f1_codecs.push_back(VideoCodec(97, "H264"));
3165 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003166 f1_.set_video_codecs(f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003167
3168 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3169 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003170 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003171 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003172 MediaContentDescription* media_desc =
3173 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3174 ASSERT_TRUE(media_desc);
3175 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003176 const StreamParamsVec& streams = desc->streams();
3177 // Single stream.
3178 ASSERT_EQ(1u, streams.size());
3179 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3180 EXPECT_EQ(3u, streams[0].ssrcs.size());
3181 // And should have a SIM group for the simulcast.
3182 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3183 // And not a FEC-FR group for FlexFEC.
3184 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3185 std::vector<uint32_t> primary_ssrcs;
3186 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3187 EXPECT_EQ(3u, primary_ssrcs.size());
3188 for (uint32_t primary_ssrc : primary_ssrcs) {
3189 uint32_t flexfec_ssrc;
3190 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3191 }
3192}
3193
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003194// Create an updated offer after creating an answer to the original offer and
3195// verify that the RTP header extensions that were part of the original answer
3196// are not changed in the updated offer.
3197TEST_F(MediaSessionDescriptionFactoryTest,
3198 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3199 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003200 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003201
3202 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3203 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3204 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3205 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3206
Steve Anton6fe1fba2018-12-11 10:15:23 -08003207 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3208 std::unique_ptr<SessionDescription> answer =
3209 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003210
Yves Gerey665174f2018-06-19 15:03:05 +02003211 EXPECT_EQ(
3212 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3213 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3214 EXPECT_EQ(
3215 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3216 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003217
kwiberg31022942016-03-11 14:18:21 -08003218 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003219 f2_.CreateOffer(opts, answer.get()));
3220
3221 // The expected RTP header extensions in the new offer are the resulting
3222 // extensions from the first offer/answer exchange plus the extensions only
3223 // |f2_| offer.
3224 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003225 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003226 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003227 kAudioRtpExtensionAnswer[0],
3228 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003229 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003230 };
3231
3232 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003233 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003234 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003235 kVideoRtpExtensionAnswer[0],
3236 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003237 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003238 };
3239
3240 const AudioContentDescription* updated_acd =
3241 GetFirstAudioContentDescription(updated_offer.get());
3242 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3243 updated_acd->rtp_header_extensions());
3244
3245 const VideoContentDescription* updated_vcd =
3246 GetFirstVideoContentDescription(updated_offer.get());
3247 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3248 updated_vcd->rtp_header_extensions());
3249}
3250
deadbeefa5b273a2015-08-20 17:30:13 -07003251// Verify that if the same RTP extension URI is used for audio and video, the
3252// same ID is used. Also verify that the ID isn't changed when creating an
3253// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003254TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003255 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003256 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003257
3258 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3259 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3260
Steve Anton6fe1fba2018-12-11 10:15:23 -08003261 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003262
3263 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3264 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003265 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003266 kVideoRtpExtension3[0],
3267 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003268 };
3269
Yves Gerey665174f2018-06-19 15:03:05 +02003270 EXPECT_EQ(
3271 MAKE_VECTOR(kAudioRtpExtension3),
3272 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3273 EXPECT_EQ(
3274 MAKE_VECTOR(kExpectedVideoRtpExtension),
3275 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003276
3277 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003278 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003279 f1_.CreateOffer(opts, offer.get()));
3280
3281 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003282 GetFirstAudioContentDescription(updated_offer.get())
3283 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003284 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003285 GetFirstVideoContentDescription(updated_offer.get())
3286 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003287}
3288
jbauch5869f502017-06-29 12:31:36 -07003289// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3290TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3291 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003292 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003293
3294 f1_.set_enable_encrypted_rtp_header_extensions(true);
3295 f2_.set_enable_encrypted_rtp_header_extensions(true);
3296
3297 f1_.set_audio_rtp_header_extensions(
3298 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3299 f1_.set_video_rtp_header_extensions(
3300 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3301
Steve Anton6fe1fba2018-12-11 10:15:23 -08003302 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003303
3304 // The extensions that are shared between audio and video should use the same
3305 // id.
3306 const RtpExtension kExpectedVideoRtpExtension[] = {
3307 kVideoRtpExtension3ForEncryption[0],
3308 kAudioRtpExtension3ForEncryptionOffer[1],
3309 kAudioRtpExtension3ForEncryptionOffer[2],
3310 };
3311
Yves Gerey665174f2018-06-19 15:03:05 +02003312 EXPECT_EQ(
3313 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3314 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3315 EXPECT_EQ(
3316 MAKE_VECTOR(kExpectedVideoRtpExtension),
3317 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003318
3319 // Nothing should change when creating a new offer
3320 std::unique_ptr<SessionDescription> updated_offer(
3321 f1_.CreateOffer(opts, offer.get()));
3322
3323 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003324 GetFirstAudioContentDescription(updated_offer.get())
3325 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003326 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003327 GetFirstVideoContentDescription(updated_offer.get())
3328 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003329}
3330
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003331TEST(MediaSessionDescription, CopySessionDescription) {
3332 SessionDescription source;
3333 cricket::ContentGroup group(cricket::CN_AUDIO);
3334 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003335 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003336 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003337 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3338 acd->AddLegacyStream(1);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003339 std::unique_ptr<AudioContentDescription> acd_passed =
3340 absl::WrapUnique(acd->Copy());
3341 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp,
3342 std::move(acd_passed));
3343 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003344 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003345 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3346 vcd->AddLegacyStream(2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003347 std::unique_ptr<VideoContentDescription> vcd_passed =
3348 absl::WrapUnique(vcd->Copy());
3349 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp,
3350 std::move(vcd_passed));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003351
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003352 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003353 ASSERT_TRUE(copy.get() != NULL);
3354 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3355 const ContentInfo* ac = copy->GetContentByName("audio");
3356 const ContentInfo* vc = copy->GetContentByName("video");
3357 ASSERT_TRUE(ac != NULL);
3358 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003359 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003360 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003361 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3362 EXPECT_EQ(1u, acd->first_ssrc());
3363
Steve Anton5adfafd2017-12-20 16:34:00 -08003364 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003365 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003366 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3367 EXPECT_EQ(2u, vcd->first_ssrc());
3368}
3369
3370// The below TestTransportInfoXXX tests create different offers/answers, and
3371// ensure the TransportInfo in the SessionDescription matches what we expect.
3372TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3373 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003374 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3375 RtpTransceiverDirection::kRecvOnly, kActive,
3376 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003377 TestTransportInfo(true, options, false);
3378}
3379
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003380TEST_F(MediaSessionDescriptionFactoryTest,
3381 TestTransportInfoOfferIceRenomination) {
3382 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003383 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3384 RtpTransceiverDirection::kRecvOnly, kActive,
3385 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003386 options.media_description_options[0]
3387 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003388 TestTransportInfo(true, options, false);
3389}
3390
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003391TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3392 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003393 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3394 RtpTransceiverDirection::kRecvOnly, kActive,
3395 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003396 TestTransportInfo(true, options, true);
3397}
3398
3399TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3400 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003401 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3402 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3403 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003404 TestTransportInfo(true, options, false);
3405}
3406
3407TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003408 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003409 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003410 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3411 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3412 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003413 TestTransportInfo(true, options, true);
3414}
3415
3416TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3417 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003418 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3419 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3420 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003421 options.bundle_enabled = true;
3422 TestTransportInfo(true, options, false);
3423}
3424
3425TEST_F(MediaSessionDescriptionFactoryTest,
3426 TestTransportInfoOfferBundleCurrent) {
3427 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003428 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3429 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3430 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003431 options.bundle_enabled = true;
3432 TestTransportInfo(true, options, true);
3433}
3434
3435TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3436 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003437 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3438 RtpTransceiverDirection::kRecvOnly, kActive,
3439 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003440 TestTransportInfo(false, options, false);
3441}
3442
3443TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003444 TestTransportInfoAnswerIceRenomination) {
3445 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003446 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3447 RtpTransceiverDirection::kRecvOnly, kActive,
3448 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003449 options.media_description_options[0]
3450 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003451 TestTransportInfo(false, options, false);
3452}
3453
3454TEST_F(MediaSessionDescriptionFactoryTest,
3455 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003456 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003457 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3458 RtpTransceiverDirection::kRecvOnly, kActive,
3459 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003460 TestTransportInfo(false, options, true);
3461}
3462
3463TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3464 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003465 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3466 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3467 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003468 TestTransportInfo(false, options, false);
3469}
3470
3471TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003472 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003473 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003474 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3475 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3476 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003477 TestTransportInfo(false, options, true);
3478}
3479
3480TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3481 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003482 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3483 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3484 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003485 options.bundle_enabled = true;
3486 TestTransportInfo(false, options, false);
3487}
3488
3489TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003490 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003491 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003492 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3493 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3494 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003495 options.bundle_enabled = true;
3496 TestTransportInfo(false, options, true);
3497}
3498
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003499TEST_F(MediaSessionDescriptionFactoryTest,
3500 TestTransportInfoOfferBundlesTransportOptions) {
3501 MediaSessionOptions options;
3502 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3503
3504 cricket::OpaqueTransportParameters audio_params;
3505 audio_params.protocol = "audio-transport";
3506 audio_params.parameters = "audio-params";
3507 FindFirstMediaDescriptionByMid("audio", &options)
3508 ->transport_options.opaque_parameters = audio_params;
3509
3510 cricket::OpaqueTransportParameters video_params;
3511 video_params.protocol = "video-transport";
3512 video_params.parameters = "video-params";
3513 FindFirstMediaDescriptionByMid("video", &options)
3514 ->transport_options.opaque_parameters = video_params;
3515
3516 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3517}
3518
3519TEST_F(MediaSessionDescriptionFactoryTest,
3520 TestTransportInfoAnswerBundlesTransportOptions) {
3521 MediaSessionOptions options;
3522 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3523
3524 cricket::OpaqueTransportParameters audio_params;
3525 audio_params.protocol = "audio-transport";
3526 audio_params.parameters = "audio-params";
3527 FindFirstMediaDescriptionByMid("audio", &options)
3528 ->transport_options.opaque_parameters = audio_params;
3529
3530 cricket::OpaqueTransportParameters video_params;
3531 video_params.protocol = "video-transport";
3532 video_params.parameters = "video-params";
3533 FindFirstMediaDescriptionByMid("video", &options)
3534 ->transport_options.opaque_parameters = video_params;
3535
3536 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3537}
3538
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003539TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3540 MediaSessionOptions options;
3541 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3542 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3543 &options);
3544
3545 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3546 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3547 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3548
3549 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3550
3551 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3552 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3553 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3554}
3555
3556TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3557 MediaSessionOptions options;
3558 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3559 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3560 &options);
3561
3562 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3563 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3564 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3565
3566 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3567 std::unique_ptr<SessionDescription> answer =
3568 f1_.CreateAnswer(offer.get(), options, nullptr);
3569
3570 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3571 "foo");
3572 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3573 "bar");
3574 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3575}
3576
3577TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3578 MediaSessionOptions options;
3579 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3580 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3581 &options);
3582
3583 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3584
3585 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3586 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3587 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3588
3589 std::unique_ptr<SessionDescription> answer =
3590 f1_.CreateAnswer(offer.get(), options, nullptr);
3591
3592 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3593 absl::nullopt);
3594 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3595 absl::nullopt);
3596 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3597 absl::nullopt);
3598}
3599
3600TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3601 MediaSessionOptions options;
3602 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3603 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3604 &options);
3605
3606 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3607 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3608 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3609
3610 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3611
3612 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3613 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3614 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3615
3616 std::unique_ptr<SessionDescription> answer =
3617 f1_.CreateAnswer(offer.get(), options, nullptr);
3618
3619 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3620 absl::nullopt);
3621 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3622 absl::nullopt);
3623 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3624 absl::nullopt);
3625}
3626
3627TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3628 MediaSessionOptions options;
3629 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3630 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3631 &options);
3632
3633 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3634 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3635 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3636
3637 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3638
3639 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3640 absl::nullopt;
3641 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3642 absl::nullopt;
3643 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3644 absl::nullopt;
3645
3646 std::unique_ptr<SessionDescription> answer =
3647 f1_.CreateAnswer(offer.get(), options, nullptr);
3648
3649 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3650 absl::nullopt);
3651 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3652 absl::nullopt);
3653 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3654 absl::nullopt);
3655}
3656
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003657// Create an offer with bundle enabled and verify the crypto parameters are
3658// the common set of the available cryptos.
3659TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3660 TestCryptoWithBundle(true);
3661}
3662
3663// Create an answer with bundle enabled and verify the crypto parameters are
3664// the common set of the available cryptos.
3665TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3666 TestCryptoWithBundle(false);
3667}
3668
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003669// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3670// DTLS is not enabled locally.
3671TEST_F(MediaSessionDescriptionFactoryTest,
3672 TestOfferDtlsSavpfWithoutDtlsFailed) {
3673 f1_.set_secure(SEC_ENABLED);
3674 f2_.set_secure(SEC_ENABLED);
3675 tdf1_.set_secure(SEC_DISABLED);
3676 tdf2_.set_secure(SEC_DISABLED);
3677
Steve Anton6fe1fba2018-12-11 10:15:23 -08003678 std::unique_ptr<SessionDescription> offer =
3679 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003680 ASSERT_TRUE(offer.get() != NULL);
3681 ContentInfo* offer_content = offer->GetContentByName("audio");
3682 ASSERT_TRUE(offer_content != NULL);
3683 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003684 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003685 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3686
Steve Anton6fe1fba2018-12-11 10:15:23 -08003687 std::unique_ptr<SessionDescription> answer =
3688 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003689 ASSERT_TRUE(answer != NULL);
3690 ContentInfo* answer_content = answer->GetContentByName("audio");
3691 ASSERT_TRUE(answer_content != NULL);
3692
3693 ASSERT_TRUE(answer_content->rejected);
3694}
3695
3696// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3697// UDP/TLS/RTP/SAVPF.
3698TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3699 f1_.set_secure(SEC_ENABLED);
3700 f2_.set_secure(SEC_ENABLED);
3701 tdf1_.set_secure(SEC_ENABLED);
3702 tdf2_.set_secure(SEC_ENABLED);
3703
Steve Anton6fe1fba2018-12-11 10:15:23 -08003704 std::unique_ptr<SessionDescription> offer =
3705 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003706 ASSERT_TRUE(offer.get() != NULL);
3707 ContentInfo* offer_content = offer->GetContentByName("audio");
3708 ASSERT_TRUE(offer_content != NULL);
3709 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003710 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003711 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3712
Steve Anton6fe1fba2018-12-11 10:15:23 -08003713 std::unique_ptr<SessionDescription> answer =
3714 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003715 ASSERT_TRUE(answer != NULL);
3716
3717 const ContentInfo* answer_content = answer->GetContentByName("audio");
3718 ASSERT_TRUE(answer_content != NULL);
3719 ASSERT_FALSE(answer_content->rejected);
3720
3721 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003722 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003723 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003724}
3725
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003726// Test that we include both SDES and DTLS in the offer, but only include SDES
3727// in the answer if DTLS isn't negotiated.
3728TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3729 f1_.set_secure(SEC_ENABLED);
3730 f2_.set_secure(SEC_ENABLED);
3731 tdf1_.set_secure(SEC_ENABLED);
3732 tdf2_.set_secure(SEC_DISABLED);
3733 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003734 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003735 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003736 const cricket::MediaContentDescription* audio_media_desc;
3737 const cricket::MediaContentDescription* video_media_desc;
3738 const cricket::TransportDescription* audio_trans_desc;
3739 const cricket::TransportDescription* video_trans_desc;
3740
3741 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003742 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003743 ASSERT_TRUE(offer.get() != NULL);
3744
Steve Antonb1c1de12017-12-21 15:14:30 -08003745 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003746 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003747 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003748 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003749 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003750 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3751
3752 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3753 ASSERT_TRUE(audio_trans_desc != NULL);
3754 video_trans_desc = offer->GetTransportDescriptionByName("video");
3755 ASSERT_TRUE(video_trans_desc != NULL);
3756 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3757 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3758
3759 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003760 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003761 ASSERT_TRUE(answer.get() != NULL);
3762
Steve Antonb1c1de12017-12-21 15:14:30 -08003763 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003764 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003765 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003766 ASSERT_TRUE(video_media_desc != NULL);
3767 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3768 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3769
3770 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3771 ASSERT_TRUE(audio_trans_desc != NULL);
3772 video_trans_desc = answer->GetTransportDescriptionByName("video");
3773 ASSERT_TRUE(video_trans_desc != NULL);
3774 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3775 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3776
3777 // Enable DTLS; the answer should now only have DTLS support.
3778 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003779 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003780 ASSERT_TRUE(answer.get() != NULL);
3781
Steve Antonb1c1de12017-12-21 15:14:30 -08003782 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003783 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003784 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003785 ASSERT_TRUE(video_media_desc != NULL);
3786 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3787 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003788 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3789 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003790
3791 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3792 ASSERT_TRUE(audio_trans_desc != NULL);
3793 video_trans_desc = answer->GetTransportDescriptionByName("video");
3794 ASSERT_TRUE(video_trans_desc != NULL);
3795 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3796 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003797
3798 // Try creating offer again. DTLS enabled now, crypto's should be empty
3799 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003800 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003801 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003802 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003803 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003804 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003805 ASSERT_TRUE(video_media_desc != NULL);
3806 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3807 EXPECT_TRUE(video_media_desc->cryptos().empty());
3808
3809 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3810 ASSERT_TRUE(audio_trans_desc != NULL);
3811 video_trans_desc = offer->GetTransportDescriptionByName("video");
3812 ASSERT_TRUE(video_trans_desc != NULL);
3813 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3814 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003815}
3816
3817// Test that an answer can't be created if cryptos are required but the offer is
3818// unsecure.
3819TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003820 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003821 f1_.set_secure(SEC_DISABLED);
3822 tdf1_.set_secure(SEC_DISABLED);
3823 f2_.set_secure(SEC_REQUIRED);
3824 tdf1_.set_secure(SEC_ENABLED);
3825
Steve Anton6fe1fba2018-12-11 10:15:23 -08003826 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003827 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003828 std::unique_ptr<SessionDescription> answer =
3829 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003830 EXPECT_TRUE(answer.get() == NULL);
3831}
3832
3833// Test that we accept a DTLS offer without SDES and create an appropriate
3834// answer.
3835TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3836 f1_.set_secure(SEC_DISABLED);
3837 f2_.set_secure(SEC_ENABLED);
3838 tdf1_.set_secure(SEC_ENABLED);
3839 tdf2_.set_secure(SEC_ENABLED);
3840 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003841 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3842 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3843 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003844
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003845 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003846 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003847 ASSERT_TRUE(offer.get() != NULL);
3848
3849 const AudioContentDescription* audio_offer =
3850 GetFirstAudioContentDescription(offer.get());
3851 ASSERT_TRUE(audio_offer->cryptos().empty());
3852 const VideoContentDescription* video_offer =
3853 GetFirstVideoContentDescription(offer.get());
3854 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003855 const RtpDataContentDescription* data_offer =
3856 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003857 ASSERT_TRUE(data_offer->cryptos().empty());
3858
3859 const cricket::TransportDescription* audio_offer_trans_desc =
3860 offer->GetTransportDescriptionByName("audio");
3861 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3862 const cricket::TransportDescription* video_offer_trans_desc =
3863 offer->GetTransportDescriptionByName("video");
3864 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3865 const cricket::TransportDescription* data_offer_trans_desc =
3866 offer->GetTransportDescriptionByName("data");
3867 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3868
3869 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003870 std::unique_ptr<SessionDescription> answer =
3871 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003872 ASSERT_TRUE(answer.get() != NULL);
3873
3874 const cricket::TransportDescription* audio_answer_trans_desc =
3875 answer->GetTransportDescriptionByName("audio");
3876 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3877 const cricket::TransportDescription* video_answer_trans_desc =
3878 answer->GetTransportDescriptionByName("video");
3879 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3880 const cricket::TransportDescription* data_answer_trans_desc =
3881 answer->GetTransportDescriptionByName("data");
3882 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3883}
3884
3885// Verifies if vad_enabled option is set to false, CN codecs are not present in
3886// offer or answer.
3887TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3888 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003889 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003890 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003891 ASSERT_TRUE(offer.get() != NULL);
3892 const ContentInfo* audio_content = offer->GetContentByName("audio");
3893 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3894
3895 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003896 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003897 ASSERT_TRUE(offer.get() != NULL);
3898 audio_content = offer->GetContentByName("audio");
3899 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003900 std::unique_ptr<SessionDescription> answer =
3901 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003902 ASSERT_TRUE(answer.get() != NULL);
3903 audio_content = answer->GetContentByName("audio");
3904 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3905}
deadbeef44f08192015-12-15 16:20:09 -08003906
zhihuang1c378ed2017-08-17 14:10:50 -07003907// Test that the generated MIDs match the existing offer.
3908TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003909 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003910 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3911 RtpTransceiverDirection::kRecvOnly, kActive,
3912 &opts);
3913 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3914 RtpTransceiverDirection::kRecvOnly, kActive,
3915 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003916 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003917 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3918 RtpTransceiverDirection::kSendRecv, kActive,
3919 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003920 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003921 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003922 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003923 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003924
deadbeef44f08192015-12-15 16:20:09 -08003925 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3926 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3927 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3928 ASSERT_TRUE(audio_content != nullptr);
3929 ASSERT_TRUE(video_content != nullptr);
3930 ASSERT_TRUE(data_content != nullptr);
3931 EXPECT_EQ("audio_modified", audio_content->name);
3932 EXPECT_EQ("video_modified", video_content->name);
3933 EXPECT_EQ("data_modified", data_content->name);
3934}
zhihuangcf5b37c2016-05-05 11:44:35 -07003935
zhihuang1c378ed2017-08-17 14:10:50 -07003936// The following tests verify that the unified plan SDP is supported.
3937// Test that we can create an offer with multiple media sections of same media
3938// type.
3939TEST_F(MediaSessionDescriptionFactoryTest,
3940 CreateOfferWithMultipleAVMediaSections) {
3941 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003942 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3943 RtpTransceiverDirection::kSendRecv, kActive,
3944 &opts);
3945 AttachSenderToMediaDescriptionOptions(
3946 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003947
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003948 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3949 RtpTransceiverDirection::kSendRecv, kActive,
3950 &opts);
3951 AttachSenderToMediaDescriptionOptions(
3952 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003953
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003954 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3955 RtpTransceiverDirection::kSendRecv, kActive,
3956 &opts);
3957 AttachSenderToMediaDescriptionOptions(
3958 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003959
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003960 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3961 RtpTransceiverDirection::kSendRecv, kActive,
3962 &opts);
3963 AttachSenderToMediaDescriptionOptions(
3964 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003965 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003966 ASSERT_TRUE(offer);
3967
3968 ASSERT_EQ(4u, offer->contents().size());
3969 EXPECT_FALSE(offer->contents()[0].rejected);
3970 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003971 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003972 ASSERT_EQ(1u, acd->streams().size());
3973 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003974 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003975
3976 EXPECT_FALSE(offer->contents()[1].rejected);
3977 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003978 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003979 ASSERT_EQ(1u, vcd->streams().size());
3980 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003981 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003982
3983 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003984 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003985 ASSERT_EQ(1u, acd->streams().size());
3986 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003987 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003988
3989 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003990 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003991 ASSERT_EQ(1u, vcd->streams().size());
3992 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003993 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003994}
3995
3996// Test that we can create an answer with multiple media sections of same media
3997// type.
3998TEST_F(MediaSessionDescriptionFactoryTest,
3999 CreateAnswerWithMultipleAVMediaSections) {
4000 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004001 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4002 RtpTransceiverDirection::kSendRecv, kActive,
4003 &opts);
4004 AttachSenderToMediaDescriptionOptions(
4005 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004006
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004007 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4008 RtpTransceiverDirection::kSendRecv, kActive,
4009 &opts);
4010 AttachSenderToMediaDescriptionOptions(
4011 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004012
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004013 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4014 RtpTransceiverDirection::kSendRecv, kActive,
4015 &opts);
4016 AttachSenderToMediaDescriptionOptions(
4017 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004018
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004019 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4020 RtpTransceiverDirection::kSendRecv, kActive,
4021 &opts);
4022 AttachSenderToMediaDescriptionOptions(
4023 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004024
Steve Anton6fe1fba2018-12-11 10:15:23 -08004025 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004026 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004027 std::unique_ptr<SessionDescription> answer =
4028 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004029
4030 ASSERT_EQ(4u, answer->contents().size());
4031 EXPECT_FALSE(answer->contents()[0].rejected);
4032 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004033 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004034 ASSERT_EQ(1u, acd->streams().size());
4035 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004036 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004037
4038 EXPECT_FALSE(answer->contents()[1].rejected);
4039 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004040 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004041 ASSERT_EQ(1u, vcd->streams().size());
4042 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004043 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004044
4045 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004046 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004047 ASSERT_EQ(1u, acd->streams().size());
4048 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004049 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004050
4051 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004052 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004053 ASSERT_EQ(1u, vcd->streams().size());
4054 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004055 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004056}
4057
4058// Test that the media section will be rejected in offer if the corresponding
4059// MediaDescriptionOptions is stopped by the offerer.
4060TEST_F(MediaSessionDescriptionFactoryTest,
4061 CreateOfferWithMediaSectionStoppedByOfferer) {
4062 // Create an offer with two audio sections and one of them is stopped.
4063 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004064 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4065 RtpTransceiverDirection::kSendRecv, kActive,
4066 &offer_opts);
4067 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4068 RtpTransceiverDirection::kInactive, kStopped,
4069 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004070 std::unique_ptr<SessionDescription> offer =
4071 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004072 ASSERT_TRUE(offer);
4073 ASSERT_EQ(2u, offer->contents().size());
4074 EXPECT_FALSE(offer->contents()[0].rejected);
4075 EXPECT_TRUE(offer->contents()[1].rejected);
4076}
4077
4078// Test that the media section will be rejected in answer if the corresponding
4079// MediaDescriptionOptions is stopped by the offerer.
4080TEST_F(MediaSessionDescriptionFactoryTest,
4081 CreateAnswerWithMediaSectionStoppedByOfferer) {
4082 // Create an offer with two audio sections and one of them is stopped.
4083 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004084 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4085 RtpTransceiverDirection::kSendRecv, kActive,
4086 &offer_opts);
4087 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4088 RtpTransceiverDirection::kInactive, kStopped,
4089 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004090 std::unique_ptr<SessionDescription> offer =
4091 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004092 ASSERT_TRUE(offer);
4093 ASSERT_EQ(2u, offer->contents().size());
4094 EXPECT_FALSE(offer->contents()[0].rejected);
4095 EXPECT_TRUE(offer->contents()[1].rejected);
4096
4097 // Create an answer based on the offer.
4098 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004099 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4100 RtpTransceiverDirection::kSendRecv, kActive,
4101 &answer_opts);
4102 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4103 RtpTransceiverDirection::kSendRecv, kActive,
4104 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004105 std::unique_ptr<SessionDescription> answer =
4106 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004107 ASSERT_EQ(2u, answer->contents().size());
4108 EXPECT_FALSE(answer->contents()[0].rejected);
4109 EXPECT_TRUE(answer->contents()[1].rejected);
4110}
4111
4112// Test that the media section will be rejected in answer if the corresponding
4113// MediaDescriptionOptions is stopped by the answerer.
4114TEST_F(MediaSessionDescriptionFactoryTest,
4115 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4116 // Create an offer with two audio sections.
4117 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004118 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4119 RtpTransceiverDirection::kSendRecv, kActive,
4120 &offer_opts);
4121 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4122 RtpTransceiverDirection::kSendRecv, kActive,
4123 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004124 std::unique_ptr<SessionDescription> offer =
4125 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004126 ASSERT_TRUE(offer);
4127 ASSERT_EQ(2u, offer->contents().size());
4128 ASSERT_FALSE(offer->contents()[0].rejected);
4129 ASSERT_FALSE(offer->contents()[1].rejected);
4130
4131 // The answerer rejects one of the audio sections.
4132 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004133 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4134 RtpTransceiverDirection::kSendRecv, kActive,
4135 &answer_opts);
4136 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4137 RtpTransceiverDirection::kInactive, kStopped,
4138 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004139 std::unique_ptr<SessionDescription> answer =
4140 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004141 ASSERT_EQ(2u, answer->contents().size());
4142 EXPECT_FALSE(answer->contents()[0].rejected);
4143 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004144
4145 // The TransportInfo of the rejected m= section is expected to be added in the
4146 // answer.
4147 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004148}
4149
4150// Test the generated media sections has the same order of the
4151// corresponding MediaDescriptionOptions.
4152TEST_F(MediaSessionDescriptionFactoryTest,
4153 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4154 MediaSessionOptions opts;
4155 // This tests put video section first because normally audio comes first by
4156 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004157 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4158 RtpTransceiverDirection::kSendRecv, kActive,
4159 &opts);
4160 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4161 RtpTransceiverDirection::kSendRecv, kActive,
4162 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004163 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004164
4165 ASSERT_TRUE(offer);
4166 ASSERT_EQ(2u, offer->contents().size());
4167 EXPECT_EQ("video", offer->contents()[0].name);
4168 EXPECT_EQ("audio", offer->contents()[1].name);
4169}
4170
4171// Test that different media sections using the same codec have same payload
4172// type.
4173TEST_F(MediaSessionDescriptionFactoryTest,
4174 PayloadTypesSharedByMediaSectionsOfSameType) {
4175 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004176 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4177 RtpTransceiverDirection::kSendRecv, kActive,
4178 &opts);
4179 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4180 RtpTransceiverDirection::kSendRecv, kActive,
4181 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004182 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004183 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004184 ASSERT_TRUE(offer);
4185 ASSERT_EQ(2u, offer->contents().size());
4186 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004187 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004188 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004189 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004190 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4191 ASSERT_EQ(2u, vcd1->codecs().size());
4192 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4193 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4194 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4195 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4196
4197 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004198 std::unique_ptr<SessionDescription> answer =
4199 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004200 ASSERT_TRUE(answer);
4201 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004202 vcd1 = answer->contents()[0].media_description()->as_video();
4203 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004204 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4205 ASSERT_EQ(1u, vcd1->codecs().size());
4206 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4207 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4208}
4209
4210// Test that the codec preference order per media section is respected in
4211// subsequent offer.
4212TEST_F(MediaSessionDescriptionFactoryTest,
4213 CreateOfferRespectsCodecPreferenceOrder) {
4214 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004215 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4216 RtpTransceiverDirection::kSendRecv, kActive,
4217 &opts);
4218 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4219 RtpTransceiverDirection::kSendRecv, kActive,
4220 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004221 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004222 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004223 ASSERT_TRUE(offer);
4224 ASSERT_EQ(2u, offer->contents().size());
4225 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004226 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004227 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004228 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004229 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4230 EXPECT_EQ(video_codecs, vcd1->codecs());
4231 EXPECT_EQ(video_codecs, vcd2->codecs());
4232
4233 // Change the codec preference of the first video section and create a
4234 // follow-up offer.
4235 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4236 vcd1->set_codecs(video_codecs_reverse);
4237 std::unique_ptr<SessionDescription> updated_offer(
4238 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004239 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4240 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004241 // The video codec preference order should be respected.
4242 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4243 EXPECT_EQ(video_codecs, vcd2->codecs());
4244}
4245
4246// Test that the codec preference order per media section is respected in
4247// the answer.
4248TEST_F(MediaSessionDescriptionFactoryTest,
4249 CreateAnswerRespectsCodecPreferenceOrder) {
4250 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004251 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4252 RtpTransceiverDirection::kSendRecv, kActive,
4253 &opts);
4254 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4255 RtpTransceiverDirection::kSendRecv, kActive,
4256 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004257 // Create an offer with two video sections using same codecs.
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);
4260 ASSERT_EQ(2u, offer->contents().size());
4261 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004262 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004263 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004264 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004265 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4266 EXPECT_EQ(video_codecs, vcd1->codecs());
4267 EXPECT_EQ(video_codecs, vcd2->codecs());
4268
4269 // Change the codec preference of the first video section and create an
4270 // answer.
4271 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4272 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004273 std::unique_ptr<SessionDescription> answer =
4274 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004275 vcd1 = answer->contents()[0].media_description()->as_video();
4276 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004277 // The video codec preference order should be respected.
4278 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4279 EXPECT_EQ(video_codecs, vcd2->codecs());
4280}
4281
Zhi Huang6f367472017-11-22 13:20:02 -08004282// Test that when creating an answer, the codecs use local parameters instead of
4283// the remote ones.
4284TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4285 const std::string audio_param_name = "audio_param";
4286 const std::string audio_value1 = "audio_v1";
4287 const std::string audio_value2 = "audio_v2";
4288 const std::string video_param_name = "video_param";
4289 const std::string video_value1 = "video_v1";
4290 const std::string video_value2 = "video_v2";
4291
4292 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4293 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4294 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4295 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4296
4297 // Set the parameters for codecs.
4298 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4299 video_codecs1[0].SetParam(video_param_name, video_value1);
4300 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4301 video_codecs2[0].SetParam(video_param_name, video_value2);
4302
4303 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004304 f1_.set_video_codecs(video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004305 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004306 f2_.set_video_codecs(video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004307
4308 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004309 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4310 RtpTransceiverDirection::kSendRecv, kActive,
4311 &opts);
4312 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4313 RtpTransceiverDirection::kSendRecv, kActive,
4314 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004315
Steve Anton6fe1fba2018-12-11 10:15:23 -08004316 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004317 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004318 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4319 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004320 std::string value;
4321 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4322 EXPECT_EQ(audio_value1, value);
4323 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4324 EXPECT_EQ(video_value1, value);
4325
Steve Anton6fe1fba2018-12-11 10:15:23 -08004326 std::unique_ptr<SessionDescription> answer =
4327 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004328 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004329 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4330 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004331 // Use the parameters from the local codecs.
4332 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4333 EXPECT_EQ(audio_value2, value);
4334 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4335 EXPECT_EQ(video_value2, value);
4336}
4337
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004338// Test that matching packetization-mode is part of the criteria for matching
4339// H264 codecs (in addition to profile-level-id). Previously, this was not the
4340// case, so the first H264 codec with the same profile-level-id would match and
4341// the payload type in the answer would be incorrect.
4342// This is a regression test for bugs.webrtc.org/8808
4343TEST_F(MediaSessionDescriptionFactoryTest,
4344 H264MatchCriteriaIncludesPacketizationMode) {
4345 // Create two H264 codecs with the same profile level ID and different
4346 // packetization modes.
4347 VideoCodec h264_pm0(96, "H264");
4348 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4349 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4350 VideoCodec h264_pm1(97, "H264");
4351 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4352 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4353
4354 // Offerer will send both codecs, answerer should choose the one with matching
4355 // packetization mode (and not the first one it sees).
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004356 f1_.set_video_codecs({h264_pm0, h264_pm1});
4357 f2_.set_video_codecs({h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004358
4359 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004360 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4361 RtpTransceiverDirection::kSendRecv, kActive,
4362 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004363
Steve Anton6fe1fba2018-12-11 10:15:23 -08004364 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004365 ASSERT_TRUE(offer);
4366
Steve Anton6fe1fba2018-12-11 10:15:23 -08004367 std::unique_ptr<SessionDescription> answer =
4368 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004369 ASSERT_TRUE(answer);
4370
4371 // Answer should have one negotiated codec with packetization-mode=1 using the
4372 // offered payload type.
4373 ASSERT_EQ(1u, answer->contents().size());
4374 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4375 ASSERT_EQ(1u, answer_vcd->codecs().size());
4376 auto answer_codec = answer_vcd->codecs()[0];
4377 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4378}
4379
zhihuangcf5b37c2016-05-05 11:44:35 -07004380class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4381 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004382 MediaProtocolTest()
4383 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004384 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4385 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004386 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004387 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004388 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4389 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004390 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004391 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004392 f1_.set_secure(SEC_ENABLED);
4393 f2_.set_secure(SEC_ENABLED);
4394 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004395 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004396 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004397 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004398 tdf1_.set_secure(SEC_ENABLED);
4399 tdf2_.set_secure(SEC_ENABLED);
4400 }
4401
4402 protected:
4403 MediaSessionDescriptionFactory f1_;
4404 MediaSessionDescriptionFactory f2_;
4405 TransportDescriptionFactory tdf1_;
4406 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004407 UniqueRandomIdGenerator ssrc_generator1;
4408 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004409};
4410
4411TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4412 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004413 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004414 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004415 ASSERT_TRUE(offer.get() != nullptr);
4416 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004417 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004418 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004419 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004420 std::unique_ptr<SessionDescription> answer =
4421 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004422 const ContentInfo* ac = answer->GetContentByName("audio");
4423 const ContentInfo* vc = answer->GetContentByName("video");
4424 ASSERT_TRUE(ac != nullptr);
4425 ASSERT_TRUE(vc != nullptr);
4426 EXPECT_FALSE(ac->rejected); // the offer is accepted
4427 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004428 const AudioContentDescription* acd = ac->media_description()->as_audio();
4429 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004430 EXPECT_EQ(GetParam(), acd->protocol());
4431 EXPECT_EQ(GetParam(), vcd->protocol());
4432}
4433
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004434INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4435 MediaProtocolTest,
4436 ::testing::ValuesIn(kMediaProtocols));
4437INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4438 MediaProtocolTest,
4439 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004440
4441TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4442 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004443 UniqueRandomIdGenerator ssrc_generator;
4444 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004445 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4446 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4447
4448 // The merged list of codecs should contain any send codecs that are also
4449 // nominally in the recieve codecs list. Payload types should be picked from
4450 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4451 // (set to 1). This equals what happens when the send codecs are used in an
4452 // offer and the receive codecs are used in the following answer.
4453 const std::vector<AudioCodec> sendrecv_codecs =
4454 MAKE_VECTOR(kAudioCodecsAnswer);
4455 const std::vector<AudioCodec> no_codecs;
4456
4457 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4458 << "Please don't change shared test data!";
4459 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4460 << "Please don't change shared test data!";
4461 // Alter iLBC send codec to have zero channels, to test that that is handled
4462 // properly.
4463 send_codecs[1].channels = 0;
4464
4465 // Alther iLBC receive codec to be lowercase, to test that case conversions
4466 // are handled properly.
4467 recv_codecs[2].name = "ilbc";
4468
4469 // Test proper merge
4470 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004471 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4472 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4473 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004474
4475 // Test empty send codecs list
4476 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004477 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4478 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4479 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004480
4481 // Test empty recv codecs list
4482 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004483 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4484 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4485 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004486
4487 // Test all empty codec lists
4488 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004489 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4490 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4491 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004492}
4493
4494namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004495// Compare the two vectors of codecs ignoring the payload type.
4496template <class Codec>
4497bool CodecsMatch(const std::vector<Codec>& codecs1,
4498 const std::vector<Codec>& codecs2) {
4499 if (codecs1.size() != codecs2.size()) {
4500 return false;
4501 }
4502
4503 for (size_t i = 0; i < codecs1.size(); ++i) {
4504 if (!codecs1[i].Matches(codecs2[i])) {
4505 return false;
4506 }
4507 }
4508 return true;
4509}
4510
Steve Anton4e70a722017-11-28 14:57:10 -08004511void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004512 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004513 UniqueRandomIdGenerator ssrc_generator;
4514 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004515 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4516 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4517 const std::vector<AudioCodec> sendrecv_codecs =
4518 MAKE_VECTOR(kAudioCodecsAnswer);
4519 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004520
4521 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004522 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4523 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004524
Steve Anton4e70a722017-11-28 14:57:10 -08004525 if (direction == RtpTransceiverDirection::kSendRecv ||
4526 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004527 AttachSenderToMediaDescriptionOptions(
4528 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004529 }
ossu075af922016-06-14 03:29:38 -07004530
Steve Anton6fe1fba2018-12-11 10:15:23 -08004531 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004532 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004533 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004534
4535 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004536 // that the codecs put in are right. This happens when we neither want to
4537 // send nor receive audio. The checks are still in place if at some point
4538 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004539 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004540 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004541 // sendrecv and inactive should both present lists as if the channel was
4542 // to be used for sending and receiving. Inactive essentially means it
4543 // might eventually be used anything, but we don't know more at this
4544 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004545 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004546 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004547 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004548 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004549 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004550 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004551 }
4552 }
4553}
4554
4555static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004556 AudioCodec(0, "codec0", 16000, -1, 1),
4557 AudioCodec(1, "codec1", 8000, 13300, 1),
4558 AudioCodec(2, "codec2", 8000, 64000, 1),
4559 AudioCodec(3, "codec3", 8000, 64000, 1),
4560 AudioCodec(4, "codec4", 8000, 0, 2),
4561 AudioCodec(5, "codec5", 32000, 0, 1),
4562 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004563
zhihuang1c378ed2017-08-17 14:10:50 -07004564/* The codecs groups below are chosen as per the matrix below. The objective
4565 * is to have different sets of codecs in the inputs, to get unique sets of
4566 * codecs after negotiation, depending on offer and answer communication
4567 * directions. One-way directions in the offer should either result in the
4568 * opposite direction in the answer, or an inactive answer. Regardless, the
4569 * choice of codecs should be as if the answer contained the opposite
4570 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004571 *
4572 * | Offer | Answer | Result
4573 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4574 * 0 | x - - | - x - | x - - - -
4575 * 1 | x x x | - x - | x - - x -
4576 * 2 | - x - | x - - | - x - - -
4577 * 3 | x x x | x - - | - x x - -
4578 * 4 | - x - | x x x | - x - - -
4579 * 5 | x - - | x x x | x - - - -
4580 * 6 | x x x | x x x | x x x x x
4581 */
4582// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004583static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4584static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004585// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4586// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004587static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4588static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004589// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004590static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4591static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4592static const int kResultSendrecv_SendCodecs[] = {3, 6};
4593static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4594static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004595
4596template <typename T, int IDXS>
4597std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4598 std::vector<T> out;
4599 out.reserve(IDXS);
4600 for (int idx : indices)
4601 out.push_back(array[idx]);
4602
4603 return out;
4604}
4605
Steve Anton4e70a722017-11-28 14:57:10 -08004606void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4607 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004608 bool add_legacy_stream) {
4609 TransportDescriptionFactory offer_tdf;
4610 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004611 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4612 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4613 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004614 offer_factory.set_audio_codecs(
4615 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4616 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4617 answer_factory.set_audio_codecs(
4618 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4619 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4620
ossu075af922016-06-14 03:29:38 -07004621 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004622 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4623 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004624
Steve Anton4e70a722017-11-28 14:57:10 -08004625 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004626 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4627 kAudioTrack1, {kMediaStream1}, 1,
4628 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004629 }
4630
Steve Anton6fe1fba2018-12-11 10:15:23 -08004631 std::unique_ptr<SessionDescription> offer =
4632 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004633 ASSERT_TRUE(offer.get() != NULL);
4634
4635 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004636 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4637 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004638
Steve Anton4e70a722017-11-28 14:57:10 -08004639 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004640 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4641 kAudioTrack1, {kMediaStream1}, 1,
4642 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004643 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004644 std::unique_ptr<SessionDescription> answer =
4645 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004646 const ContentInfo* ac = answer->GetContentByName("audio");
4647
zhihuang1c378ed2017-08-17 14:10:50 -07004648 // If the factory didn't add any audio content to the answer, we cannot
4649 // check that the codecs put in are right. This happens when we neither want
4650 // to send nor receive audio. The checks are still in place if at some point
4651 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004652 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004653 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4654 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004655
ossu075af922016-06-14 03:29:38 -07004656 std::vector<AudioCodec> target_codecs;
4657 // For offers with sendrecv or inactive, we should never reply with more
4658 // codecs than offered, with these codec sets.
4659 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004660 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004661 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4662 kResultSendrecv_SendrecvCodecs);
4663 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004664 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004665 target_codecs =
4666 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004667 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004668 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004669 target_codecs =
4670 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004671 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004672 case RtpTransceiverDirection::kSendRecv:
4673 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004674 target_codecs =
4675 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004676 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004677 target_codecs =
4678 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004679 } else {
4680 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4681 kResultSendrecv_SendrecvCodecs);
4682 }
4683 break;
4684 }
4685
zhihuang1c378ed2017-08-17 14:10:50 -07004686 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004687 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004688 bool first = true;
4689 os << "{";
4690 for (const auto& c : codecs) {
4691 os << (first ? " " : ", ") << c.id;
4692 first = false;
4693 }
4694 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004695 return os.Release();
ossu075af922016-06-14 03:29:38 -07004696 };
4697
4698 EXPECT_TRUE(acd->codecs() == target_codecs)
4699 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004700 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4701 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004702 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004703 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4704 << "; got: "
4705 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004706 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004707 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004708 << "Only inactive offers are allowed to not generate any audio "
4709 "content";
ossu075af922016-06-14 03:29:38 -07004710 }
4711}
brandtr03d5fb12016-11-22 03:37:59 -08004712
4713} // namespace
ossu075af922016-06-14 03:29:38 -07004714
4715class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004716 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004717
4718TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004719 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004720}
4721
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004722INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4723 AudioCodecsOfferTest,
4724 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4725 RtpTransceiverDirection::kRecvOnly,
4726 RtpTransceiverDirection::kSendRecv,
4727 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004728
4729class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004730 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4731 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004732 bool>> {};
ossu075af922016-06-14 03:29:38 -07004733
4734TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004735 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4736 ::testing::get<1>(GetParam()),
4737 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004738}
4739
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004740INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004741 MediaSessionDescriptionFactoryTest,
4742 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004743 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4744 RtpTransceiverDirection::kRecvOnly,
4745 RtpTransceiverDirection::kSendRecv,
4746 RtpTransceiverDirection::kInactive),
4747 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4748 RtpTransceiverDirection::kRecvOnly,
4749 RtpTransceiverDirection::kSendRecv,
4750 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004751 ::testing::Bool()));