blob: 548b778681fbc08b23cf90f12923993bfe72bf21 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/media_session.h"
12
Amit Hilbuch77938e62018-12-21 09:23:38 -080013#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080014#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <string>
Harald Alvestrand1716d392019-06-03 20:35:45 +020016#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <vector>
18
Steve Anton64b626b2019-01-28 17:25:26 -080019#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080020#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020023#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "p2p/base/p2p_constants.h"
25#include "p2p/base/transport_description.h"
26#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "pc/rtp_media_utils.h"
28#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "rtc_base/message_digest.h"
33#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020034#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080035#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080036#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
Yves Gerey665174f2018-06-19 15:03:05 +020038#define ASSERT_CRYPTO(cd, s, cs) \
39 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080040 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041
42typedef std::vector<cricket::Candidate> Candidates;
43
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080044using cricket::AudioCodec;
45using cricket::AudioContentDescription;
46using cricket::ContentInfo;
47using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080048using cricket::GetFirstAudioContent;
49using cricket::GetFirstAudioContentDescription;
50using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020051using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080052using cricket::GetFirstVideoContent;
53using cricket::GetFirstVideoContentDescription;
54using cricket::kAutoBandwidth;
55using cricket::MEDIA_TYPE_AUDIO;
56using cricket::MEDIA_TYPE_DATA;
57using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070059using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080060using cricket::MediaProtocolType;
61using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062using cricket::MediaSessionOptions;
63using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080064using cricket::RidDescription;
65using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020066using cricket::RtpDataCodec;
67using cricket::RtpDataContentDescription;
68using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080069using cricket::SEC_DISABLED;
70using cricket::SEC_ENABLED;
71using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080073using cricket::SimulcastDescription;
74using cricket::SimulcastLayer;
75using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076using cricket::SsrcGroup;
77using cricket::StreamParams;
78using cricket::StreamParamsVec;
79using cricket::TransportDescription;
80using cricket::TransportDescriptionFactory;
81using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080083using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070084using rtc::CS_AEAD_AES_128_GCM;
85using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080086using rtc::CS_AES_CM_128_HMAC_SHA1_32;
87using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080088using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020089using ::testing::Contains;
90using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +010091using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020092using ::testing::ElementsAreArray;
93using ::testing::Eq;
94using ::testing::Field;
95using ::testing::IsEmpty;
96using ::testing::IsFalse;
97using ::testing::Ne;
98using ::testing::Not;
99using ::testing::Pointwise;
100using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700101using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800102using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
104static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700105 AudioCodec(103, "ISAC", 16000, -1, 1),
106 AudioCodec(102, "iLBC", 8000, 13300, 1),
107 AudioCodec(0, "PCMU", 8000, 64000, 1),
108 AudioCodec(8, "PCMA", 8000, 64000, 1),
109 AudioCodec(117, "red", 8000, 0, 1),
110 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
112static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200113 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700114 AudioCodec(0, "PCMU", 8000, 64000, 1),
115 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116};
117
118static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700119 AudioCodec(102, "iLBC", 8000, 13300, 1),
120 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121};
122
perkj26752742016-10-24 01:21:16 -0700123static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
124 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125
zhihuang1c378ed2017-08-17 14:10:50 -0700126static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
127 VideoCodec(96, "H264-SVC")};
128
perkj26752742016-10-24 01:21:16 -0700129static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
130 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
perkj26752742016-10-24 01:21:16 -0700132static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200134static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
135 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200137static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
138 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200140static const RtpDataCodec kDataCodecsAnswer[] = {
141 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142
isheriff6f8d6862016-05-26 11:24:55 -0700143static const RtpExtension kAudioRtpExtension1[] = {
144 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
145 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146};
147
jbauch5869f502017-06-29 12:31:36 -0700148static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
149 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
150 RtpExtension("http://google.com/testing/audio_something", 10),
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
152};
153
isheriff6f8d6862016-05-26 11:24:55 -0700154static const RtpExtension kAudioRtpExtension2[] = {
155 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
156 RtpExtension("http://google.com/testing/audio_something_else", 8),
157 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000158};
159
isheriff6f8d6862016-05-26 11:24:55 -0700160static const RtpExtension kAudioRtpExtension3[] = {
161 RtpExtension("http://google.com/testing/audio_something", 2),
162 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700163};
164
jbauch5869f502017-06-29 12:31:36 -0700165static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
166 RtpExtension("http://google.com/testing/audio_something", 2),
167 // Use RTP extension that supports encryption.
168 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
169};
170
171static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
172 RtpExtension("http://google.com/testing/audio_something", 2),
173 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
175};
176
isheriff6f8d6862016-05-26 11:24:55 -0700177static const RtpExtension kAudioRtpExtensionAnswer[] = {
178 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179};
180
jbauch5869f502017-06-29 12:31:36 -0700181static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
182 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
183};
184
isheriff6f8d6862016-05-26 11:24:55 -0700185static const RtpExtension kVideoRtpExtension1[] = {
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
187 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188};
189
jbauch5869f502017-06-29 12:31:36 -0700190static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
192 RtpExtension("http://google.com/testing/video_something", 13),
193 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
194};
195
isheriff6f8d6862016-05-26 11:24:55 -0700196static const RtpExtension kVideoRtpExtension2[] = {
197 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
198 RtpExtension("http://google.com/testing/video_something_else", 14),
199 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200};
201
isheriff6f8d6862016-05-26 11:24:55 -0700202static const RtpExtension kVideoRtpExtension3[] = {
203 RtpExtension("http://google.com/testing/video_something", 4),
204 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700205};
206
jbauch5869f502017-06-29 12:31:36 -0700207static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
208 RtpExtension("http://google.com/testing/video_something", 4),
209 // Use RTP extension that supports encryption.
210 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
211};
212
isheriff6f8d6862016-05-26 11:24:55 -0700213static const RtpExtension kVideoRtpExtensionAnswer[] = {
214 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215};
216
jbauch5869f502017-06-29 12:31:36 -0700217static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
218 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
219};
220
Johannes Kronce8e8672019-02-22 13:06:44 +0100221static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
222 RtpExtension("http://www.ietf.org/id/"
223 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
224 1),
225};
226
227static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
228 RtpExtension("http://www.ietf.org/id/"
229 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
230 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100231 RtpExtension(
232 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
233 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100234};
235
236static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100237 RtpExtension(
238 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
239 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100240};
241
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100242static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
243 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
244 "generic-frame-descriptor-00",
245 3),
246};
247
Peter Boström0c4e06b2015-10-07 12:23:21 +0200248static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
249static const uint32_t kSimSsrc[] = {10, 20, 30};
250static const uint32_t kFec1Ssrc[] = {10, 11};
251static const uint32_t kFec2Ssrc[] = {20, 21};
252static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253
254static const char kMediaStream1[] = "stream_1";
255static const char kMediaStream2[] = "stream_2";
256static const char kVideoTrack1[] = "video_1";
257static const char kVideoTrack2[] = "video_2";
258static const char kAudioTrack1[] = "audio_1";
259static const char kAudioTrack2[] = "audio_2";
260static const char kAudioTrack3[] = "audio_3";
261static const char kDataTrack1[] = "data_1";
262static const char kDataTrack2[] = "data_2";
263static const char kDataTrack3[] = "data_3";
264
zhihuangcf5b37c2016-05-05 11:44:35 -0700265static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
266 "RTP/SAVPF"};
267static const char* kMediaProtocolsDtls[] = {
268 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
269 "UDP/TLS/RTP/SAVP"};
270
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700271// SRTP cipher name negotiated by the tests. This must be updated if the
272// default changes.
273static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
274static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
275
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800276// These constants are used to make the code using "AddMediaDescriptionOptions"
277// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700278static constexpr bool kStopped = true;
279static constexpr bool kActive = false;
280
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000281static bool IsMediaContentOfType(const ContentInfo* content,
282 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800283 RTC_DCHECK(content);
284 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000285}
286
Steve Anton4e70a722017-11-28 14:57:10 -0800287static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800288 RTC_DCHECK(content);
289 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000290}
291
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000292static void AddRtxCodec(const VideoCodec& rtx_codec,
293 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800294 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000295 codecs->push_back(rtx_codec);
296}
297
298template <class T>
299static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
300 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100301 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000302 for (const auto& codec : codecs) {
303 codec_names.push_back(codec.name);
304 }
305 return codec_names;
306}
307
zhihuang1c378ed2017-08-17 14:10:50 -0700308// This is used for test only. MIDs are not the identification of the
309// MediaDescriptionOptions since some end points may not support MID and the SDP
310// may not contain 'mid'.
311std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
312 const std::string& mid,
313 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800314 return absl::c_find_if(
315 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700316 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
317}
318
319std::vector<MediaDescriptionOptions>::const_iterator
320FindFirstMediaDescriptionByMid(const std::string& mid,
321 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800322 return absl::c_find_if(
323 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700324 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700325}
326
327// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800328static void AddMediaDescriptionOptions(MediaType type,
329 const std::string& mid,
330 RtpTransceiverDirection direction,
331 bool stopped,
332 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800333 opts->media_description_options.push_back(
334 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700335}
336
Steve Anton4e70a722017-11-28 14:57:10 -0800337static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700338 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800339 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
340 opts);
341 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
342 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700343}
344
345static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800346 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700347 MediaSessionOptions* opts) {
348 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800349 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700350}
351
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800352static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700353 const std::string& mid,
354 MediaType type,
355 const std::string& track_id,
356 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800357 const std::vector<RidDescription>& rids,
358 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700359 int num_sim_layer,
360 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700361 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
362 switch (type) {
363 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700364 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700365 break;
366 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800367 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
368 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700369 break;
370 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700371 RTC_CHECK(stream_ids.size() == 1U);
372 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700373 break;
374 default:
375 RTC_NOTREACHED();
376 }
377}
378
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800379static void AttachSenderToMediaDescriptionOptions(
380 const std::string& mid,
381 MediaType type,
382 const std::string& track_id,
383 const std::vector<std::string>& stream_ids,
384 int num_sim_layer,
385 MediaSessionOptions* session_options) {
386 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
387 SimulcastLayerList(), num_sim_layer,
388 session_options);
389}
390
zhihuang1c378ed2017-08-17 14:10:50 -0700391static void DetachSenderFromMediaSection(const std::string& mid,
392 const std::string& track_id,
393 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700394 std::vector<cricket::SenderOptions>& sender_options_list =
395 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
396 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800397 absl::c_find_if(sender_options_list,
398 [track_id](const cricket::SenderOptions& sender_options) {
399 return sender_options.track_id == track_id;
400 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700401 RTC_DCHECK(sender_it != sender_options_list.end());
402 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700403}
404
405// Helper function used to create a default MediaSessionOptions for Plan B SDP.
406// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
407static MediaSessionOptions CreatePlanBMediaSessionOptions() {
408 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800409 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
410 RtpTransceiverDirection::kRecvOnly, kActive,
411 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700412 return session_options;
413}
414
415// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
416// was designed for Plan B SDP, where only one audio "m=" section and one video
417// "m=" section could be generated, and ordering couldn't be controlled. Many of
418// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200419class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800421 MediaSessionDescriptionFactoryTest()
422 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700423 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
424 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000425 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200426 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700427 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
428 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000429 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200430 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200431 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700432 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200433 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700434 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 }
436
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000437 // Create a video StreamParamsVec object with:
438 // - one video stream with 3 simulcast streams and FEC,
439 StreamParamsVec CreateComplexVideoStreamParamsVec() {
440 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
441 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
442 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
443 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
444
445 std::vector<SsrcGroup> ssrc_groups;
446 ssrc_groups.push_back(sim_group);
447 ssrc_groups.push_back(fec_group1);
448 ssrc_groups.push_back(fec_group2);
449 ssrc_groups.push_back(fec_group3);
450
451 StreamParams simulcast_params;
452 simulcast_params.id = kVideoTrack1;
453 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
454 simulcast_params.ssrc_groups = ssrc_groups;
455 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800456 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000457
458 StreamParamsVec video_streams;
459 video_streams.push_back(simulcast_params);
460
461 return video_streams;
462 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463
464 bool CompareCryptoParams(const CryptoParamsVec& c1,
465 const CryptoParamsVec& c2) {
466 if (c1.size() != c2.size())
467 return false;
468 for (size_t i = 0; i < c1.size(); ++i)
469 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
470 c1[i].key_params != c2[i].key_params ||
471 c1[i].session_params != c2[i].session_params)
472 return false;
473 return true;
474 }
475
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700476 // Returns true if the transport info contains "renomination" as an
477 // ICE option.
478 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800479 return absl::c_linear_search(transport_info->description.transport_options,
480 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700481 }
482
zhihuang1c378ed2017-08-17 14:10:50 -0700483 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700484 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485 bool has_current_desc) {
486 const std::string current_audio_ufrag = "current_audio_ufrag";
487 const std::string current_audio_pwd = "current_audio_pwd";
488 const std::string current_video_ufrag = "current_video_ufrag";
489 const std::string current_video_pwd = "current_video_pwd";
490 const std::string current_data_ufrag = "current_data_ufrag";
491 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800492 std::unique_ptr<SessionDescription> current_desc;
493 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000494 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200495 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800496 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200497 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800498 TransportDescription(current_audio_ufrag, current_audio_pwd)));
499 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200500 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800501 TransportDescription(current_video_ufrag, current_video_pwd)));
502 current_desc->AddTransportInfo(TransportInfo(
503 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 }
505 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800506 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 } else {
kwiberg31022942016-03-11 14:18:21 -0800508 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800509 offer = f1_.CreateOffer(options, NULL);
510 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511 }
512 ASSERT_TRUE(desc.get() != NULL);
513 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000514 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 EXPECT_TRUE(ti_audio != NULL);
516 if (has_current_desc) {
517 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
518 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
519 } else {
520 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
521 ti_audio->description.ice_ufrag.size());
522 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
523 ti_audio->description.ice_pwd.size());
524 }
zhihuang1c378ed2017-08-17 14:10:50 -0700525 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700526 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700527 EXPECT_EQ(
528 media_desc_options_it->transport_options.enable_ice_renomination,
529 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700530 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
531 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532
533 } else {
534 EXPECT_TRUE(ti_audio == NULL);
535 }
536 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000537 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700539 auto media_desc_options_it =
540 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 if (options.bundle_enabled) {
542 EXPECT_EQ(ti_audio->description.ice_ufrag,
543 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200544 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700545 EXPECT_EQ(ti_audio->description.opaque_parameters,
546 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 } else {
548 if (has_current_desc) {
549 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
550 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
551 } else {
552 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
553 ti_video->description.ice_ufrag.size());
554 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
555 ti_video->description.ice_pwd.size());
556 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700557 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
558 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 }
zhihuang1c378ed2017-08-17 14:10:50 -0700560 EXPECT_EQ(
561 media_desc_options_it->transport_options.enable_ice_renomination,
562 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 } else {
564 EXPECT_TRUE(ti_video == NULL);
565 }
566 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
567 if (options.has_data()) {
568 EXPECT_TRUE(ti_data != NULL);
569 if (options.bundle_enabled) {
570 EXPECT_EQ(ti_audio->description.ice_ufrag,
571 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200572 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 } else {
574 if (has_current_desc) {
575 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
576 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
577 } else {
578 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
579 ti_data->description.ice_ufrag.size());
580 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
581 ti_data->description.ice_pwd.size());
582 }
583 }
zhihuang1c378ed2017-08-17 14:10:50 -0700584 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700585 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700586 EXPECT_EQ(
587 media_desc_options_it->transport_options.enable_ice_renomination,
588 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700589
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700591 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 }
593 }
594
595 void TestCryptoWithBundle(bool offer) {
596 f1_.set_secure(SEC_ENABLED);
597 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800598 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
599 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
600 &options);
kwiberg31022942016-03-11 14:18:21 -0800601 std::unique_ptr<SessionDescription> ref_desc;
602 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 if (offer) {
604 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800605 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800607 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 } else {
609 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800610 ref_desc = f1_.CreateOffer(options, NULL);
611 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800613 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800615 desc->GetContentDescriptionByName("audio");
616 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800618 desc->GetContentDescriptionByName("video");
619 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
621 video_media_desc->cryptos()));
622 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800623 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 audio_media_desc->cryptos()[0].cipher_suite);
625
626 // Verify the selected crypto is one from the reference audio
627 // media content.
628 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800629 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 bool found = false;
631 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
632 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200633 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 found = true;
635 break;
636 }
637 }
638 EXPECT_TRUE(found);
639 }
640
641 // This test that the audio and video media direction is set to
642 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700643 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800645 RtpTransceiverDirection direction_in_offer,
646 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700647 MediaSessionOptions offer_opts;
648 AddAudioVideoSections(direction_in_offer, &offer_opts);
649
Steve Anton6fe1fba2018-12-11 10:15:23 -0800650 std::unique_ptr<SessionDescription> offer =
651 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700653 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700655 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657
zhihuang1c378ed2017-08-17 14:10:50 -0700658 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800659 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800660 std::unique_ptr<SessionDescription> answer =
661 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 const AudioContentDescription* acd_answer =
663 GetFirstAudioContentDescription(answer.get());
664 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
665 const VideoContentDescription* vcd_answer =
666 GetFirstVideoContentDescription(answer.get());
667 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
668 }
669
670 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800671 RTC_DCHECK(content);
672 RTC_CHECK(content->media_description());
673 const cricket::AudioContentDescription* audio_desc =
674 content->media_description()->as_audio();
675 RTC_CHECK(audio_desc);
676 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
677 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800679 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 }
681 return true;
682 }
683
jbauchcb560652016-08-04 05:20:32 -0700684 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
685 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800686 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700687 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700688
jbauchcb560652016-08-04 05:20:32 -0700689 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800690 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700691 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700692
jbauchcb560652016-08-04 05:20:32 -0700693 f1_.set_secure(SEC_ENABLED);
694 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800695 std::unique_ptr<SessionDescription> offer =
696 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700697 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800698 std::unique_ptr<SessionDescription> answer =
699 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700700 const ContentInfo* ac = answer->GetContentByName("audio");
701 const ContentInfo* vc = answer->GetContentByName("video");
702 ASSERT_TRUE(ac != NULL);
703 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800704 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
705 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800706 const AudioContentDescription* acd = ac->media_description()->as_audio();
707 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700708 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800709 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700710 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700711 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700712 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
713 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700714 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700715 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700716 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700717 }
718 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800719 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200720 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
721 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700722 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700723 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700724 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700725 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700726 }
Steve Antone38a5a12018-11-21 16:05:15 -0800727 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700728 }
729
Johannes Kronce8e8672019-02-22 13:06:44 +0100730 void TestTransportSequenceNumberNegotiation(
731 const cricket::RtpHeaderExtensions& local,
732 const cricket::RtpHeaderExtensions& offered,
733 const cricket::RtpHeaderExtensions& expectedAnswer) {
734 MediaSessionOptions opts;
735 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
736 f1_.set_audio_rtp_header_extensions(offered);
737 f1_.set_video_rtp_header_extensions(offered);
738 f2_.set_audio_rtp_header_extensions(local);
739 f2_.set_video_rtp_header_extensions(local);
740
741 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
742 ASSERT_TRUE(offer.get() != NULL);
743 std::unique_ptr<SessionDescription> answer =
744 f2_.CreateAnswer(offer.get(), opts, NULL);
745
746 EXPECT_EQ(
747 expectedAnswer,
748 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
749 EXPECT_EQ(
750 expectedAnswer,
751 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
752 }
753
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800755 UniqueRandomIdGenerator ssrc_generator1;
756 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757 MediaSessionDescriptionFactory f1_;
758 MediaSessionDescriptionFactory f2_;
759 TransportDescriptionFactory tdf1_;
760 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761};
762
763// Create a typical audio offer, and ensure it matches what we expect.
764TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
765 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800766 std::unique_ptr<SessionDescription> offer =
767 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 ASSERT_TRUE(offer.get() != NULL);
769 const ContentInfo* ac = offer->GetContentByName("audio");
770 const ContentInfo* vc = offer->GetContentByName("video");
771 ASSERT_TRUE(ac != NULL);
772 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800773 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800774 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700776 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700777 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
779 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700780 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800781 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782}
783
784// Create a typical video offer, and ensure it matches what we expect.
785TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
786 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800787 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000788 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800789 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790 ASSERT_TRUE(offer.get() != NULL);
791 const ContentInfo* ac = offer->GetContentByName("audio");
792 const ContentInfo* vc = offer->GetContentByName("video");
793 ASSERT_TRUE(ac != NULL);
794 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800795 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
796 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800797 const AudioContentDescription* acd = ac->media_description()->as_audio();
798 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700800 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700801 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
803 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700804 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800805 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000807 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700808 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
810 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700811 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800812 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813}
814
815// Test creating an offer with bundle where the Codecs have the same dynamic
816// RTP playlod type. The test verifies that the offer don't contain the
817// duplicate RTP payload types.
818TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +0000819 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700820 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200821 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
823 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
824
825 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800826 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
827 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800829 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830 const VideoContentDescription* vcd =
831 GetFirstVideoContentDescription(offer.get());
832 const AudioContentDescription* acd =
833 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200834 const RtpDataContentDescription* dcd =
835 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836 ASSERT_TRUE(NULL != vcd);
837 ASSERT_TRUE(NULL != acd);
838 ASSERT_TRUE(NULL != dcd);
839 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
840 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
841 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
842 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
843 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
844 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
845}
846
zhihuang1c378ed2017-08-17 14:10:50 -0700847// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848// after an audio only session has been negotiated.
849TEST_F(MediaSessionDescriptionFactoryTest,
850 TestCreateUpdatedVideoOfferWithBundle) {
851 f1_.set_secure(SEC_ENABLED);
852 f2_.set_secure(SEC_ENABLED);
853 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800854 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
855 RtpTransceiverDirection::kRecvOnly, kActive,
856 &opts);
857 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
858 RtpTransceiverDirection::kInactive, kStopped,
859 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 opts.data_channel_type = cricket::DCT_NONE;
861 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800862 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
863 std::unique_ptr<SessionDescription> answer =
864 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865
866 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800867 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
868 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
869 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800871 std::unique_ptr<SessionDescription> updated_offer(
872 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873
874 const AudioContentDescription* acd =
875 GetFirstAudioContentDescription(updated_offer.get());
876 const VideoContentDescription* vcd =
877 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200878 const RtpDataContentDescription* dcd =
879 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 EXPECT_TRUE(NULL != vcd);
881 EXPECT_TRUE(NULL != acd);
882 EXPECT_TRUE(NULL != dcd);
883
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700884 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800885 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700886 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800887 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700888 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800889 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000890}
deadbeef44f08192015-12-15 16:20:09 -0800891
wu@webrtc.org78187522013-10-07 23:32:02 +0000892// Create a RTP data offer, and ensure it matches what we expect.
893TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800895 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
896 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800898 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 ASSERT_TRUE(offer.get() != NULL);
900 const ContentInfo* ac = offer->GetContentByName("audio");
901 const ContentInfo* dc = offer->GetContentByName("data");
902 ASSERT_TRUE(ac != NULL);
903 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800904 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
905 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800906 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200907 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700909 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700910 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
912 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700913 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800914 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200916 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700917 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200919 dcd->bandwidth()); // default bandwidth (auto)
920 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700921 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800922 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923}
924
wu@webrtc.org78187522013-10-07 23:32:02 +0000925// Create an SCTP data offer with bundle without error.
926TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
927 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000928 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800929 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000930 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800931 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000932 EXPECT_TRUE(offer.get() != NULL);
933 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000934 auto dcd = GetFirstSctpDataContentDescription(offer.get());
935 ASSERT_TRUE(dcd);
936 // Since this transport is insecure, the protocol should be "SCTP".
937 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
938}
939
940// Create an SCTP data offer with bundle without error.
941TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
942 MediaSessionOptions opts;
943 opts.bundle_enabled = true;
944 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
945 f1_.set_secure(SEC_ENABLED);
946 tdf1_.set_secure(SEC_ENABLED);
947 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
948 EXPECT_TRUE(offer.get() != NULL);
949 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
950 auto dcd = GetFirstSctpDataContentDescription(offer.get());
951 ASSERT_TRUE(dcd);
952 // The protocol should now be "UDP/DTLS/SCTP"
953 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000954}
955
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000956// Test creating an sctp data channel from an already generated offer.
957TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
958 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000959 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800960 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000961 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800962 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000963 ASSERT_TRUE(offer1.get() != NULL);
964 const ContentInfo* data = offer1->GetContentByName("data");
965 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800966 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000967
968 // Now set data_channel_type to 'none' (default) and make sure that the
969 // datachannel type that gets generated from the previous offer, is of the
970 // same type.
971 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800972 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000973 f1_.CreateOffer(opts, offer1.get()));
974 data = offer2->GetContentByName("data");
975 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800976 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000977}
978
Steve Anton2bed3972019-01-04 17:04:30 -0800979// Test that if BUNDLE is enabled and all media sections are rejected then the
980// BUNDLE group is not present in the re-offer.
981TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
982 MediaSessionOptions opts;
983 opts.bundle_enabled = true;
984 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
985 RtpTransceiverDirection::kSendRecv, kActive,
986 &opts);
987 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
988
989 opts.media_description_options[0].stopped = true;
990 std::unique_ptr<SessionDescription> reoffer =
991 f1_.CreateOffer(opts, offer.get());
992
993 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
994}
995
996// Test that if BUNDLE is enabled and the remote re-offer does not include a
997// BUNDLE group since all media sections are rejected, then the re-answer also
998// does not include a BUNDLE group.
999TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
1000 MediaSessionOptions opts;
1001 opts.bundle_enabled = true;
1002 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1003 RtpTransceiverDirection::kSendRecv, kActive,
1004 &opts);
1005 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1006 std::unique_ptr<SessionDescription> answer =
1007 f2_.CreateAnswer(offer.get(), opts, nullptr);
1008
1009 opts.media_description_options[0].stopped = true;
1010 std::unique_ptr<SessionDescription> reoffer =
1011 f1_.CreateOffer(opts, offer.get());
1012 std::unique_ptr<SessionDescription> reanswer =
1013 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1014
1015 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1016}
1017
1018// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1019// was rejected then the new offerer-tagged media section is the non-rejected
1020// media section.
1021TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1022 MediaSessionOptions opts;
1023 opts.bundle_enabled = true;
1024 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1025 RtpTransceiverDirection::kSendRecv, kActive,
1026 &opts);
1027 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1028
1029 // Reject the audio m= section and add a video m= section.
1030 opts.media_description_options[0].stopped = true;
1031 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1032 RtpTransceiverDirection::kSendRecv, kActive,
1033 &opts);
1034 std::unique_ptr<SessionDescription> reoffer =
1035 f1_.CreateOffer(opts, offer.get());
1036
1037 const cricket::ContentGroup* bundle_group =
1038 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1039 ASSERT_TRUE(bundle_group);
1040 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1041 EXPECT_TRUE(bundle_group->HasContentName("video"));
1042}
1043
1044// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1045// was rejected and a new media section is added, then the re-answer BUNDLE
1046// group will contain only the non-rejected media section.
1047TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1048 MediaSessionOptions opts;
1049 opts.bundle_enabled = true;
1050 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1051 RtpTransceiverDirection::kSendRecv, kActive,
1052 &opts);
1053 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1054 std::unique_ptr<SessionDescription> answer =
1055 f2_.CreateAnswer(offer.get(), opts, nullptr);
1056
1057 // Reject the audio m= section and add a video m= section.
1058 opts.media_description_options[0].stopped = true;
1059 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1060 RtpTransceiverDirection::kSendRecv, kActive,
1061 &opts);
1062 std::unique_ptr<SessionDescription> reoffer =
1063 f1_.CreateOffer(opts, offer.get());
1064 std::unique_ptr<SessionDescription> reanswer =
1065 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1066
1067 const cricket::ContentGroup* bundle_group =
1068 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1069 ASSERT_TRUE(bundle_group);
1070 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1071 EXPECT_TRUE(bundle_group->HasContentName("video"));
1072}
1073
1074// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1075// and there is still a non-rejected media section that was in the initial
1076// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1077// media section.
1078TEST_F(MediaSessionDescriptionFactoryTest,
1079 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1080 MediaSessionOptions opts;
1081 opts.bundle_enabled = true;
1082 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1083 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1084 std::unique_ptr<SessionDescription> answer =
1085 f2_.CreateAnswer(offer.get(), opts, nullptr);
1086
1087 // Reject the audio m= section.
1088 opts.media_description_options[0].stopped = true;
1089 std::unique_ptr<SessionDescription> reoffer =
1090 f1_.CreateOffer(opts, offer.get());
1091
1092 const TransportDescription* offer_tagged =
1093 offer->GetTransportDescriptionByName("audio");
1094 ASSERT_TRUE(offer_tagged);
1095 const TransportDescription* reoffer_tagged =
1096 reoffer->GetTransportDescriptionByName("video");
1097 ASSERT_TRUE(reoffer_tagged);
1098 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1099 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1100}
1101
1102// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1103// and there is still a non-rejected media section that was in the initial
1104// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1105// media section.
1106TEST_F(MediaSessionDescriptionFactoryTest,
1107 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1108 MediaSessionOptions opts;
1109 opts.bundle_enabled = true;
1110 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1111 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1112 std::unique_ptr<SessionDescription> answer =
1113 f2_.CreateAnswer(offer.get(), opts, nullptr);
1114
1115 // Reject the audio m= section.
1116 opts.media_description_options[0].stopped = true;
1117 std::unique_ptr<SessionDescription> reoffer =
1118 f1_.CreateOffer(opts, offer.get());
1119 std::unique_ptr<SessionDescription> reanswer =
1120 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1121
1122 const TransportDescription* answer_tagged =
1123 answer->GetTransportDescriptionByName("audio");
1124 ASSERT_TRUE(answer_tagged);
1125 const TransportDescription* reanswer_tagged =
1126 reanswer->GetTransportDescriptionByName("video");
1127 ASSERT_TRUE(reanswer_tagged);
1128 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1129 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1130}
1131
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132// Create an audio, video offer without legacy StreamParams.
1133TEST_F(MediaSessionDescriptionFactoryTest,
1134 TestCreateOfferWithoutLegacyStreams) {
1135 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001136 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001137 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138 ASSERT_TRUE(offer.get() != NULL);
1139 const ContentInfo* ac = offer->GetContentByName("audio");
1140 const ContentInfo* vc = offer->GetContentByName("video");
1141 ASSERT_TRUE(ac != NULL);
1142 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001143 const AudioContentDescription* acd = ac->media_description()->as_audio();
1144 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001145
Yves Gerey665174f2018-06-19 15:03:05 +02001146 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1147 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148}
1149
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001150// Creates an audio+video sendonly offer.
1151TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001152 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001153 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001154 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1155 {kMediaStream1}, 1, &opts);
1156 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1157 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001158
Steve Anton6fe1fba2018-12-11 10:15:23 -08001159 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001160 ASSERT_TRUE(offer.get() != NULL);
1161 EXPECT_EQ(2u, offer->contents().size());
1162 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1163 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1164
Steve Anton4e70a722017-11-28 14:57:10 -08001165 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1166 GetMediaDirection(&offer->contents()[0]));
1167 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1168 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001169}
1170
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001171// Verifies that the order of the media contents in the current
1172// SessionDescription is preserved in the new SessionDescription.
1173TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1174 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001175 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001176
kwiberg31022942016-03-11 14:18:21 -08001177 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001178 ASSERT_TRUE(offer1.get() != NULL);
1179 EXPECT_EQ(1u, offer1->contents().size());
1180 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1181
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001182 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1183 RtpTransceiverDirection::kRecvOnly, kActive,
1184 &opts);
kwiberg31022942016-03-11 14:18:21 -08001185 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001186 f1_.CreateOffer(opts, offer1.get()));
1187 ASSERT_TRUE(offer2.get() != NULL);
1188 EXPECT_EQ(2u, offer2->contents().size());
1189 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1190 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1191
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001192 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1193 RtpTransceiverDirection::kRecvOnly, kActive,
1194 &opts);
kwiberg31022942016-03-11 14:18:21 -08001195 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001196 f1_.CreateOffer(opts, offer2.get()));
1197 ASSERT_TRUE(offer3.get() != NULL);
1198 EXPECT_EQ(3u, offer3->contents().size());
1199 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1200 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1201 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001202}
1203
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001204// Create a typical audio answer, and ensure it matches what we expect.
1205TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1206 f1_.set_secure(SEC_ENABLED);
1207 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001208 std::unique_ptr<SessionDescription> offer =
1209 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001210 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001211 std::unique_ptr<SessionDescription> answer =
1212 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001213 const ContentInfo* ac = answer->GetContentByName("audio");
1214 const ContentInfo* vc = answer->GetContentByName("video");
1215 ASSERT_TRUE(ac != NULL);
1216 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001217 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001218 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001220 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001221 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1223 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001224 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001225 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226}
1227
jbauchcb560652016-08-04 05:20:32 -07001228// Create a typical audio answer with GCM ciphers enabled, and ensure it
1229// matches what we expect.
1230TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1231 f1_.set_secure(SEC_ENABLED);
1232 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001233 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001234 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001235 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001236 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001237 std::unique_ptr<SessionDescription> answer =
1238 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001239 const ContentInfo* ac = answer->GetContentByName("audio");
1240 const ContentInfo* vc = answer->GetContentByName("video");
1241 ASSERT_TRUE(ac != NULL);
1242 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001243 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001244 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001245 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001246 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001247 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001248 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1249 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001250 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001251 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001252}
1253
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254// Create a typical video answer, and ensure it matches what we expect.
1255TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1256 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001257 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 f1_.set_secure(SEC_ENABLED);
1259 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001260 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001262 std::unique_ptr<SessionDescription> answer =
1263 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 const ContentInfo* ac = answer->GetContentByName("audio");
1265 const ContentInfo* vc = answer->GetContentByName("video");
1266 ASSERT_TRUE(ac != NULL);
1267 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001268 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1269 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001270 const AudioContentDescription* acd = ac->media_description()->as_audio();
1271 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001273 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001275 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001277 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001279 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001280 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1281 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001282 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001283 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001284}
1285
jbauchcb560652016-08-04 05:20:32 -07001286// Create a typical video answer with GCM ciphers enabled, and ensure it
1287// matches what we expect.
1288TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1289 TestVideoGcmCipher(true, true);
1290}
1291
1292// Create a typical video answer with GCM ciphers enabled for the offer only,
1293// and ensure it matches what we expect.
1294TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1295 TestVideoGcmCipher(true, false);
1296}
1297
1298// Create a typical video answer with GCM ciphers enabled for the answer only,
1299// and ensure it matches what we expect.
1300TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1301 TestVideoGcmCipher(false, true);
1302}
1303
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001304TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001305 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001306 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 f1_.set_secure(SEC_ENABLED);
1308 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001309 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001311 std::unique_ptr<SessionDescription> answer =
1312 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001313 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001314 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001315 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001316 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001317 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1318 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001319 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001320 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001321 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001322 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001324 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001325 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001326 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001327 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001328 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001329 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001330 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001331 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001332 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333}
1334
jbauchcb560652016-08-04 05:20:32 -07001335TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001336 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001337 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001338 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001339 f1_.set_secure(SEC_ENABLED);
1340 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001341 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001342 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001343 std::unique_ptr<SessionDescription> answer =
1344 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001345 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001346 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001347 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001348 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001349 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1350 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001351 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001352 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001353 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001354 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001355 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001356 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001357 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001358 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001359 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001360 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001361 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001362 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001363 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001364 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001365}
1366
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001367// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1368// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001369TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1370 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001371 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001372 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001373 ASSERT_TRUE(offer.get() != NULL);
1374 ContentInfo* dc_offer = offer->GetContentByName("data");
1375 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001376 SctpDataContentDescription* dcd_offer =
1377 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001378 EXPECT_TRUE(dcd_offer->use_sctpmap());
1379
Steve Anton6fe1fba2018-12-11 10:15:23 -08001380 std::unique_ptr<SessionDescription> answer =
1381 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001382 const ContentInfo* dc_answer = answer->GetContentByName("data");
1383 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001384 const SctpDataContentDescription* dcd_answer =
1385 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001386 EXPECT_TRUE(dcd_answer->use_sctpmap());
1387}
1388
1389// The answer's use_sctpmap flag should match the offer's.
1390TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1391 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001392 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001393 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001394 ASSERT_TRUE(offer.get() != NULL);
1395 ContentInfo* dc_offer = offer->GetContentByName("data");
1396 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001397 SctpDataContentDescription* dcd_offer =
1398 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001399 dcd_offer->set_use_sctpmap(false);
1400
Steve Anton6fe1fba2018-12-11 10:15:23 -08001401 std::unique_ptr<SessionDescription> answer =
1402 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001403 const ContentInfo* dc_answer = answer->GetContentByName("data");
1404 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001405 const SctpDataContentDescription* dcd_answer =
1406 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001407 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001408}
1409
deadbeef8b7e9ad2017-05-25 09:38:55 -07001410// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1411// and "TCP/DTLS/SCTP" offers.
1412TEST_F(MediaSessionDescriptionFactoryTest,
1413 TestCreateDataAnswerToDifferentOfferedProtos) {
1414 // Need to enable DTLS offer/answer generation (disabled by default in this
1415 // test).
1416 f1_.set_secure(SEC_ENABLED);
1417 f2_.set_secure(SEC_ENABLED);
1418 tdf1_.set_secure(SEC_ENABLED);
1419 tdf2_.set_secure(SEC_ENABLED);
1420
1421 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001422 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001423 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001424 ASSERT_TRUE(offer.get() != nullptr);
1425 ContentInfo* dc_offer = offer->GetContentByName("data");
1426 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001427 SctpDataContentDescription* dcd_offer =
1428 dc_offer->media_description()->as_sctp();
1429 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001430
1431 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1432 "TCP/DTLS/SCTP"};
1433 for (const std::string& proto : protos) {
1434 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001435 std::unique_ptr<SessionDescription> answer =
1436 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001437 const ContentInfo* dc_answer = answer->GetContentByName("data");
1438 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001439 const SctpDataContentDescription* dcd_answer =
1440 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001441 EXPECT_FALSE(dc_answer->rejected);
1442 EXPECT_EQ(proto, dcd_answer->protocol());
1443 }
1444}
1445
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001446TEST_F(MediaSessionDescriptionFactoryTest,
1447 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1448 // Need to enable DTLS offer/answer generation (disabled by default in this
1449 // test).
1450 f1_.set_secure(SEC_ENABLED);
1451 f2_.set_secure(SEC_ENABLED);
1452 tdf1_.set_secure(SEC_ENABLED);
1453 tdf2_.set_secure(SEC_ENABLED);
1454
1455 MediaSessionOptions opts;
1456 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1457 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1458 ASSERT_TRUE(offer.get() != nullptr);
1459 ContentInfo* dc_offer = offer->GetContentByName("data");
1460 ASSERT_TRUE(dc_offer != nullptr);
1461 SctpDataContentDescription* dcd_offer =
1462 dc_offer->media_description()->as_sctp();
1463 ASSERT_TRUE(dcd_offer);
1464 dcd_offer->set_max_message_size(1234);
1465 std::unique_ptr<SessionDescription> answer =
1466 f2_.CreateAnswer(offer.get(), opts, nullptr);
1467 const ContentInfo* dc_answer = answer->GetContentByName("data");
1468 ASSERT_TRUE(dc_answer != nullptr);
1469 const SctpDataContentDescription* dcd_answer =
1470 dc_answer->media_description()->as_sctp();
1471 EXPECT_FALSE(dc_answer->rejected);
1472 EXPECT_EQ(1234, dcd_answer->max_message_size());
1473}
1474
1475TEST_F(MediaSessionDescriptionFactoryTest,
1476 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1477 // Need to enable DTLS offer/answer generation (disabled by default in this
1478 // test).
1479 f1_.set_secure(SEC_ENABLED);
1480 f2_.set_secure(SEC_ENABLED);
1481 tdf1_.set_secure(SEC_ENABLED);
1482 tdf2_.set_secure(SEC_ENABLED);
1483
1484 MediaSessionOptions opts;
1485 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1486 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1487 ASSERT_TRUE(offer.get() != nullptr);
1488 ContentInfo* dc_offer = offer->GetContentByName("data");
1489 ASSERT_TRUE(dc_offer != nullptr);
1490 SctpDataContentDescription* dcd_offer =
1491 dc_offer->media_description()->as_sctp();
1492 ASSERT_TRUE(dcd_offer);
1493 dcd_offer->set_max_message_size(0);
1494 std::unique_ptr<SessionDescription> answer =
1495 f2_.CreateAnswer(offer.get(), opts, nullptr);
1496 const ContentInfo* dc_answer = answer->GetContentByName("data");
1497 ASSERT_TRUE(dc_answer != nullptr);
1498 const SctpDataContentDescription* dcd_answer =
1499 dc_answer->media_description()->as_sctp();
1500 EXPECT_FALSE(dc_answer->rejected);
1501 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1502}
1503
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001504// Verifies that the order of the media contents in the offer is preserved in
1505// the answer.
1506TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1507 MediaSessionOptions opts;
1508
1509 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001510 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001511 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001512 ASSERT_TRUE(offer1.get() != NULL);
1513
1514 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001515 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1516 RtpTransceiverDirection::kRecvOnly, kActive,
1517 &opts);
kwiberg31022942016-03-11 14:18:21 -08001518 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001519 f1_.CreateOffer(opts, offer1.get()));
1520 ASSERT_TRUE(offer2.get() != NULL);
1521
1522 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001523 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1524 RtpTransceiverDirection::kRecvOnly, kActive,
1525 &opts);
kwiberg31022942016-03-11 14:18:21 -08001526 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001527 f1_.CreateOffer(opts, offer2.get()));
1528 ASSERT_TRUE(offer3.get() != NULL);
1529
Steve Anton6fe1fba2018-12-11 10:15:23 -08001530 std::unique_ptr<SessionDescription> answer =
1531 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001532 ASSERT_TRUE(answer.get() != NULL);
1533 EXPECT_EQ(3u, answer->contents().size());
1534 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1535 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1536 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1537}
1538
ossu075af922016-06-14 03:29:38 -07001539// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1540// answerer settings.
1541
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001542// This test that the media direction is set to send/receive in an answer if
1543// the offer is send receive.
1544TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001545 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1546 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001547}
1548
1549// This test that the media direction is set to receive only in an answer if
1550// the offer is send only.
1551TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001552 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1553 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554}
1555
1556// This test that the media direction is set to send only in an answer if
1557// the offer is recv only.
1558TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001559 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1560 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001561}
1562
1563// This test that the media direction is set to inactive in an answer if
1564// the offer is inactive.
1565TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001566 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1567 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568}
1569
1570// Test that a data content with an unknown protocol is rejected in an answer.
1571TEST_F(MediaSessionDescriptionFactoryTest,
1572 CreateDataAnswerToOfferWithUnknownProtocol) {
1573 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001574 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001575 f1_.set_secure(SEC_ENABLED);
1576 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001577 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001578 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001579 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001580 RtpDataContentDescription* dcd_offer =
1581 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001583 // Offer must be acceptable as an RTP protocol in order to be set.
1584 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001585 dcd_offer->set_protocol(protocol);
1586
Steve Anton6fe1fba2018-12-11 10:15:23 -08001587 std::unique_ptr<SessionDescription> answer =
1588 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001589
1590 const ContentInfo* dc_answer = answer->GetContentByName("data");
1591 ASSERT_TRUE(dc_answer != NULL);
1592 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001593 const RtpDataContentDescription* dcd_answer =
1594 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001595 ASSERT_TRUE(dcd_answer != NULL);
1596 EXPECT_EQ(protocol, dcd_answer->protocol());
1597}
1598
1599// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1600TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001601 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001602 f1_.set_secure(SEC_DISABLED);
1603 f2_.set_secure(SEC_DISABLED);
1604 tdf1_.set_secure(SEC_DISABLED);
1605 tdf2_.set_secure(SEC_DISABLED);
1606
Steve Anton6fe1fba2018-12-11 10:15:23 -08001607 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001608 const AudioContentDescription* offer_acd =
1609 GetFirstAudioContentDescription(offer.get());
1610 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001611 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001612
Steve Anton6fe1fba2018-12-11 10:15:23 -08001613 std::unique_ptr<SessionDescription> answer =
1614 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001615
1616 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1617 ASSERT_TRUE(ac_answer != NULL);
1618 EXPECT_FALSE(ac_answer->rejected);
1619
1620 const AudioContentDescription* answer_acd =
1621 GetFirstAudioContentDescription(answer.get());
1622 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001623 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001624}
1625
1626// Create a video offer and answer and ensure the RTP header extensions
1627// matches what we expect.
1628TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1629 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001630 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001631 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1632 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1633 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1634 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1635
Steve Anton6fe1fba2018-12-11 10:15:23 -08001636 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001637 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001638 std::unique_ptr<SessionDescription> answer =
1639 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640
Yves Gerey665174f2018-06-19 15:03:05 +02001641 EXPECT_EQ(
1642 MAKE_VECTOR(kAudioRtpExtension1),
1643 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1644 EXPECT_EQ(
1645 MAKE_VECTOR(kVideoRtpExtension1),
1646 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1647 EXPECT_EQ(
1648 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1649 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1650 EXPECT_EQ(
1651 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1652 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001653}
1654
Johannes Kronce8e8672019-02-22 13:06:44 +01001655// Create a audio/video offer and answer and ensure that the
1656// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1657// supported and should take precedence even though not listed among locally
1658// supported extensions.
1659TEST_F(MediaSessionDescriptionFactoryTest,
1660 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1661 TestTransportSequenceNumberNegotiation(
1662 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1663 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1664 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1665}
1666TEST_F(MediaSessionDescriptionFactoryTest,
1667 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1668 TestTransportSequenceNumberNegotiation(
1669 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1670 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1671 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1672}
1673TEST_F(MediaSessionDescriptionFactoryTest,
1674 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1675 TestTransportSequenceNumberNegotiation(
1676 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1677 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1678 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1679}
1680
jbauch5869f502017-06-29 12:31:36 -07001681TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001682 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1683 MediaSessionOptions opts;
1684 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1685
1686 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1687 f1_.set_audio_rtp_header_extensions(offered);
1688 f1_.set_video_rtp_header_extensions(offered);
1689 const auto local = MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01);
1690 f2_.set_audio_rtp_header_extensions(local);
1691 f2_.set_video_rtp_header_extensions(local);
1692 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1693 std::unique_ptr<SessionDescription> answer =
1694 f2_.CreateAnswer(offer.get(), opts, nullptr);
1695 EXPECT_THAT(
1696 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1697 ElementsAreArray(offered));
1698 EXPECT_THAT(
1699 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1700 ElementsAreArray(offered));
1701}
1702
1703TEST_F(MediaSessionDescriptionFactoryTest,
1704 TestNegotiateFrameDescriptorWhenExposedLocally) {
1705 MediaSessionOptions opts;
1706 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1707
1708 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1709 f1_.set_audio_rtp_header_extensions(offered);
1710 f1_.set_video_rtp_header_extensions(offered);
1711 const auto local = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1712 f2_.set_audio_rtp_header_extensions(local);
1713 f2_.set_video_rtp_header_extensions(local);
1714 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1715 std::unique_ptr<SessionDescription> answer =
1716 f2_.CreateAnswer(offer.get(), opts, nullptr);
1717 EXPECT_THAT(
1718 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1719 ElementsAreArray(offered));
1720 EXPECT_THAT(
1721 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1722 ElementsAreArray(offered));
1723}
1724
1725TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001726 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1727 MediaSessionOptions opts;
1728 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1729
1730 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1731 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1732 f1_.set_video_rtp_header_extensions({offer_dd});
1733 f2_.set_video_rtp_header_extensions({local_tsn});
1734 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1735 std::unique_ptr<SessionDescription> answer =
1736 f2_.CreateAnswer(offer.get(), opts, nullptr);
1737 EXPECT_THAT(
1738 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1739 ElementsAre(offer_dd));
1740}
1741
1742TEST_F(MediaSessionDescriptionFactoryTest,
1743 NegotiateDependencyDescriptorWhenExposedLocally) {
1744 MediaSessionOptions opts;
1745 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1746
1747 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1748 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
1749 f1_.set_video_rtp_header_extensions({offer_dd});
1750 f2_.set_video_rtp_header_extensions({local_dd});
1751 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1752 std::unique_ptr<SessionDescription> answer =
1753 f2_.CreateAnswer(offer.get(), opts, nullptr);
1754 EXPECT_THAT(
1755 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1756 ElementsAre(offer_dd));
1757}
1758
1759TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001760 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1761 MediaSessionOptions opts;
1762 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1763
1764 const cricket::RtpHeaderExtensions offered_extensions = {
1765 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1766 const cricket::RtpHeaderExtensions local_extensions = {
1767 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
1768 f1_.set_video_rtp_header_extensions(offered_extensions);
1769 f1_.set_audio_rtp_header_extensions(offered_extensions);
1770 f2_.set_video_rtp_header_extensions(local_extensions);
1771 f2_.set_audio_rtp_header_extensions(local_extensions);
1772
1773 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1774 std::unique_ptr<SessionDescription> answer =
1775 f2_.CreateAnswer(offer.get(), opts, nullptr);
1776 EXPECT_THAT(
1777 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1778 ElementsAreArray(offered_extensions));
1779 EXPECT_THAT(
1780 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1781 ElementsAreArray(offered_extensions));
1782}
1783
1784TEST_F(MediaSessionDescriptionFactoryTest,
1785 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1786 MediaSessionOptions opts;
1787 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1788
1789 const cricket::RtpHeaderExtensions offered_extensions = {
1790 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1791 const cricket::RtpHeaderExtensions local_extensions = {
1792 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
1793 f1_.set_video_rtp_header_extensions(offered_extensions);
1794 f1_.set_audio_rtp_header_extensions(offered_extensions);
1795 f2_.set_video_rtp_header_extensions(local_extensions);
1796 f2_.set_audio_rtp_header_extensions(local_extensions);
1797
1798 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1799 std::unique_ptr<SessionDescription> answer =
1800 f2_.CreateAnswer(offer.get(), opts, nullptr);
1801 EXPECT_THAT(
1802 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1803 ElementsAreArray(offered_extensions));
1804 EXPECT_THAT(
1805 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1806 ElementsAreArray(offered_extensions));
1807}
1808
1809TEST_F(MediaSessionDescriptionFactoryTest,
1810 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1811 MediaSessionOptions opts;
1812 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1813
1814 const cricket::RtpHeaderExtensions offered_extensions = {
1815 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1816 const cricket::RtpHeaderExtensions local_extensions = {
1817 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
1818 f1_.set_video_rtp_header_extensions(offered_extensions);
1819 f1_.set_audio_rtp_header_extensions(offered_extensions);
1820 f2_.set_video_rtp_header_extensions(local_extensions);
1821 f2_.set_audio_rtp_header_extensions(local_extensions);
1822
1823 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1824 std::unique_ptr<SessionDescription> answer =
1825 f2_.CreateAnswer(offer.get(), opts, nullptr);
1826 EXPECT_THAT(
1827 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1828 IsEmpty());
1829 EXPECT_THAT(
1830 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1831 IsEmpty());
1832}
1833
1834TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001835 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001836 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001837 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001838
1839 f1_.set_enable_encrypted_rtp_header_extensions(true);
1840 f2_.set_enable_encrypted_rtp_header_extensions(true);
1841
Yves Gerey665174f2018-06-19 15:03:05 +02001842 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1843 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1844 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1845 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001846
Steve Anton6fe1fba2018-12-11 10:15:23 -08001847 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001848 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001849 std::unique_ptr<SessionDescription> answer =
1850 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001851
Yves Gerey665174f2018-06-19 15:03:05 +02001852 EXPECT_EQ(
1853 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1854 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1855 EXPECT_EQ(
1856 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1857 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1858 EXPECT_EQ(
1859 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1860 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1861 EXPECT_EQ(
1862 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1863 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001864}
1865
1866TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001867 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001868 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001869 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001870
1871 f1_.set_enable_encrypted_rtp_header_extensions(true);
1872
Yves Gerey665174f2018-06-19 15:03:05 +02001873 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1874 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1875 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1876 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001877
Steve Anton6fe1fba2018-12-11 10:15:23 -08001878 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001879 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001880 std::unique_ptr<SessionDescription> answer =
1881 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001882
Yves Gerey665174f2018-06-19 15:03:05 +02001883 EXPECT_EQ(
1884 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1885 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1886 EXPECT_EQ(
1887 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1888 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1889 EXPECT_EQ(
1890 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1891 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1892 EXPECT_EQ(
1893 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1894 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001895}
1896
1897TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001898 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001899 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001900 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001901
1902 f2_.set_enable_encrypted_rtp_header_extensions(true);
1903
Yves Gerey665174f2018-06-19 15:03:05 +02001904 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1905 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1906 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1907 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001908
Steve Anton6fe1fba2018-12-11 10:15:23 -08001909 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001910 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001911 std::unique_ptr<SessionDescription> answer =
1912 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001913
Yves Gerey665174f2018-06-19 15:03:05 +02001914 EXPECT_EQ(
1915 MAKE_VECTOR(kAudioRtpExtension1),
1916 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1917 EXPECT_EQ(
1918 MAKE_VECTOR(kVideoRtpExtension1),
1919 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1920 EXPECT_EQ(
1921 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1922 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1923 EXPECT_EQ(
1924 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1925 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001926}
1927
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001928// Create an audio, video, data answer without legacy StreamParams.
1929TEST_F(MediaSessionDescriptionFactoryTest,
1930 TestCreateAnswerWithoutLegacyStreams) {
1931 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001932 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1933 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001934 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001935 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001936 std::unique_ptr<SessionDescription> answer =
1937 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001938 const ContentInfo* ac = answer->GetContentByName("audio");
1939 const ContentInfo* vc = answer->GetContentByName("video");
1940 const ContentInfo* dc = answer->GetContentByName("data");
1941 ASSERT_TRUE(ac != NULL);
1942 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001943 const AudioContentDescription* acd = ac->media_description()->as_audio();
1944 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001945 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001946
1947 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1948 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1949 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1950}
1951
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001952// Create a typical video answer, and ensure it matches what we expect.
1953TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1954 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001955 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1956 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1957 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001958
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001959 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001960 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1961 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1962 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001963
kwiberg31022942016-03-11 14:18:21 -08001964 std::unique_ptr<SessionDescription> offer;
1965 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001966
1967 offer_opts.rtcp_mux_enabled = true;
1968 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001969 offer = f1_.CreateOffer(offer_opts, NULL);
1970 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1972 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001973 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001974 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1975 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001976 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1978 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001979 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001980 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1981 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001982 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983
1984 offer_opts.rtcp_mux_enabled = true;
1985 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001986 offer = f1_.CreateOffer(offer_opts, NULL);
1987 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001988 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1989 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001990 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001991 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1992 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001993 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1995 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001996 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001997 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1998 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001999 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002000
2001 offer_opts.rtcp_mux_enabled = false;
2002 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002003 offer = f1_.CreateOffer(offer_opts, NULL);
2004 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002005 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2006 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002007 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2009 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002010 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2012 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002013 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2015 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002016 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002017
2018 offer_opts.rtcp_mux_enabled = false;
2019 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002020 offer = f1_.CreateOffer(offer_opts, NULL);
2021 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002022 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2023 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002024 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2026 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002027 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2029 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002030 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002031 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2032 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002033 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034}
2035
2036// Create an audio-only answer to a video offer.
2037TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2038 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002039 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2040 RtpTransceiverDirection::kRecvOnly, kActive,
2041 &opts);
2042 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2043 RtpTransceiverDirection::kRecvOnly, kActive,
2044 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002045 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002046 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002047
2048 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002049 std::unique_ptr<SessionDescription> answer =
2050 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002051 const ContentInfo* ac = answer->GetContentByName("audio");
2052 const ContentInfo* vc = answer->GetContentByName("video");
2053 ASSERT_TRUE(ac != NULL);
2054 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002055 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002056 EXPECT_TRUE(vc->rejected);
2057}
2058
2059// Create an audio-only answer to an offer with data.
2060TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002061 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002062 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002063 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2064 RtpTransceiverDirection::kRecvOnly, kActive,
2065 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002066 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002067 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002068
2069 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002070 std::unique_ptr<SessionDescription> answer =
2071 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072 const ContentInfo* ac = answer->GetContentByName("audio");
2073 const ContentInfo* dc = answer->GetContentByName("data");
2074 ASSERT_TRUE(ac != NULL);
2075 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002076 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002077 EXPECT_TRUE(dc->rejected);
2078}
2079
2080// Create an answer that rejects the contents which are rejected in the offer.
2081TEST_F(MediaSessionDescriptionFactoryTest,
2082 CreateAnswerToOfferWithRejectedMedia) {
2083 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002084 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2085 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002086 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002087 ASSERT_TRUE(offer.get() != NULL);
2088 ContentInfo* ac = offer->GetContentByName("audio");
2089 ContentInfo* vc = offer->GetContentByName("video");
2090 ContentInfo* dc = offer->GetContentByName("data");
2091 ASSERT_TRUE(ac != NULL);
2092 ASSERT_TRUE(vc != NULL);
2093 ASSERT_TRUE(dc != NULL);
2094 ac->rejected = true;
2095 vc->rejected = true;
2096 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002097 std::unique_ptr<SessionDescription> answer =
2098 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002099 ac = answer->GetContentByName("audio");
2100 vc = answer->GetContentByName("video");
2101 dc = answer->GetContentByName("data");
2102 ASSERT_TRUE(ac != NULL);
2103 ASSERT_TRUE(vc != NULL);
2104 ASSERT_TRUE(dc != NULL);
2105 EXPECT_TRUE(ac->rejected);
2106 EXPECT_TRUE(vc->rejected);
2107 EXPECT_TRUE(dc->rejected);
2108}
2109
Johannes Kron0854eb62018-10-10 22:33:20 +02002110TEST_F(MediaSessionDescriptionFactoryTest,
2111 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2112 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002113 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002114 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002115 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002116 ASSERT_TRUE(offer.get() != NULL);
2117 std::unique_ptr<SessionDescription> answer_no_support(
2118 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002119 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002120
2121 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002122 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002123 ASSERT_TRUE(offer.get() != NULL);
2124 std::unique_ptr<SessionDescription> answer_support(
2125 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002126 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002127}
2128
2129TEST_F(MediaSessionDescriptionFactoryTest,
2130 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2131 MediaSessionOptions opts;
2132 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002133 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002134 MediaContentDescription* video_offer =
2135 offer->GetContentDescriptionByName("video");
2136 ASSERT_TRUE(video_offer);
2137 MediaContentDescription* audio_offer =
2138 offer->GetContentDescriptionByName("audio");
2139 ASSERT_TRUE(audio_offer);
2140
2141 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002142 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2143 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002144
2145 ASSERT_TRUE(offer.get() != NULL);
2146 std::unique_ptr<SessionDescription> answer_no_support(
2147 f2_.CreateAnswer(offer.get(), opts, NULL));
2148 MediaContentDescription* video_answer =
2149 answer_no_support->GetContentDescriptionByName("video");
2150 MediaContentDescription* audio_answer =
2151 answer_no_support->GetContentDescriptionByName("audio");
2152 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002153 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002154 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002155 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002156
2157 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002158 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2159 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002160 ASSERT_TRUE(offer.get() != NULL);
2161 std::unique_ptr<SessionDescription> answer_support(
2162 f2_.CreateAnswer(offer.get(), opts, NULL));
2163 video_answer = answer_support->GetContentDescriptionByName("video");
2164 audio_answer = answer_support->GetContentDescriptionByName("audio");
2165 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002166 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002167 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002168 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002169}
2170
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171// Create an audio and video offer with:
2172// - one video track
2173// - two audio tracks
2174// - two data tracks
2175// and ensure it matches what we expect. Also updates the initial offer by
2176// adding a new video track and replaces one of the audio tracks.
2177TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2178 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002179 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002180 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2181 {kMediaStream1}, 1, &opts);
2182 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2183 {kMediaStream1}, 1, &opts);
2184 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2185 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002186
Steve Anton4e70a722017-11-28 14:57:10 -08002187 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002188 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2189 {kMediaStream1}, 1, &opts);
2190 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2191 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002192
2193 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002194 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002195
2196 ASSERT_TRUE(offer.get() != NULL);
2197 const ContentInfo* ac = offer->GetContentByName("audio");
2198 const ContentInfo* vc = offer->GetContentByName("video");
2199 const ContentInfo* dc = offer->GetContentByName("data");
2200 ASSERT_TRUE(ac != NULL);
2201 ASSERT_TRUE(vc != NULL);
2202 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002203 const AudioContentDescription* acd = ac->media_description()->as_audio();
2204 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002205 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002206 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002207 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002208
2209 const StreamParamsVec& audio_streams = acd->streams();
2210 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002211 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002212 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2213 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2214 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2215 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2216 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2217 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2218
2219 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2220 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002221 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002222
2223 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002224 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002225 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002226
2227 const StreamParamsVec& video_streams = vcd->streams();
2228 ASSERT_EQ(1U, video_streams.size());
2229 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2230 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2231 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2232 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2233
2234 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002235 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002236 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002237
2238 const StreamParamsVec& data_streams = dcd->streams();
2239 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002240 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002241 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2242 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2243 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2244 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2245 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2246 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2247
2248 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002249 dcd->bandwidth()); // default bandwidth (auto)
2250 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002251 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002252
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002253 // Update the offer. Add a new video track that is not synched to the
2254 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002255 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2256 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002257 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002258 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2259 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002260 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002261 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2262 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002263 std::unique_ptr<SessionDescription> updated_offer(
2264 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002265
2266 ASSERT_TRUE(updated_offer.get() != NULL);
2267 ac = updated_offer->GetContentByName("audio");
2268 vc = updated_offer->GetContentByName("video");
2269 dc = updated_offer->GetContentByName("data");
2270 ASSERT_TRUE(ac != NULL);
2271 ASSERT_TRUE(vc != NULL);
2272 ASSERT_TRUE(dc != NULL);
2273 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002274 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002275 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002276 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002277 const RtpDataContentDescription* updated_dcd =
2278 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002279
2280 EXPECT_EQ(acd->type(), updated_acd->type());
2281 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2282 EXPECT_EQ(vcd->type(), updated_vcd->type());
2283 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2284 EXPECT_EQ(dcd->type(), updated_dcd->type());
2285 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002286 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002287 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002288 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002289 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002290 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002291 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2292
2293 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2294 ASSERT_EQ(2U, updated_audio_streams.size());
2295 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2296 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2297 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2298 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2299 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2300
2301 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2302 ASSERT_EQ(2U, updated_video_streams.size());
2303 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2304 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002305 // All the media streams in one PeerConnection share one RTCP CNAME.
2306 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002307
2308 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2309 ASSERT_EQ(2U, updated_data_streams.size());
2310 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2311 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2312 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2313 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2314 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002315 // The stream correctly got the CNAME from the MediaSessionOptions.
2316 // The Expected RTCP CNAME is the default one as we are using the default
2317 // MediaSessionOptions.
2318 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002319}
2320
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002321// Create an offer with simulcast video stream.
2322TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2323 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002324 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2325 RtpTransceiverDirection::kRecvOnly, kActive,
2326 &opts);
2327 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2328 RtpTransceiverDirection::kSendRecv, kActive,
2329 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002330 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002331 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2332 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002333 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002334
2335 ASSERT_TRUE(offer.get() != NULL);
2336 const ContentInfo* vc = offer->GetContentByName("video");
2337 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002338 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002339
2340 const StreamParamsVec& video_streams = vcd->streams();
2341 ASSERT_EQ(1U, video_streams.size());
2342 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2343 const SsrcGroup* sim_ssrc_group =
2344 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2345 ASSERT_TRUE(sim_ssrc_group != NULL);
2346 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2347}
2348
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002349MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2350 const RidDescription& rid1 = ::testing::get<0>(arg);
2351 const RidDescription& rid2 = ::testing::get<1>(arg);
2352 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2353}
2354
2355static void CheckSimulcastInSessionDescription(
2356 const SessionDescription* description,
2357 const std::string& content_name,
2358 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002359 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002360 ASSERT_NE(description, nullptr);
2361 const ContentInfo* content = description->GetContentByName(content_name);
2362 ASSERT_NE(content, nullptr);
2363 const MediaContentDescription* cd = content->media_description();
2364 ASSERT_NE(cd, nullptr);
2365 const StreamParamsVec& streams = cd->streams();
2366 ASSERT_THAT(streams, SizeIs(1));
2367 const StreamParams& stream = streams[0];
2368 ASSERT_THAT(stream.ssrcs, IsEmpty());
2369 EXPECT_TRUE(stream.has_rids());
2370 const std::vector<RidDescription> rids = stream.rids();
2371
2372 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2373
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002374 EXPECT_TRUE(cd->HasSimulcast());
2375 const SimulcastDescription& simulcast = cd->simulcast_description();
2376 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2377 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2378
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002379 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002380}
2381
2382// Create an offer with spec-compliant simulcast video stream.
2383TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2384 MediaSessionOptions opts;
2385 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2386 RtpTransceiverDirection::kSendRecv, kActive,
2387 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002388 std::vector<RidDescription> send_rids;
2389 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2390 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2391 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2392 SimulcastLayerList simulcast_layers;
2393 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2394 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2395 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2396 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2397 {kMediaStream1}, send_rids,
2398 simulcast_layers, 0, &opts);
2399 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2400
2401 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002402 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002403}
2404
2405// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2406// In this scenario, RIDs do not need to be negotiated (there is only one).
2407TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2408 MediaSessionOptions opts;
2409 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2410 RtpTransceiverDirection::kSendRecv, kActive,
2411 &opts);
2412 RidDescription rid("f", RidDirection::kSend);
2413 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2414 {kMediaStream1}, {rid},
2415 SimulcastLayerList(), 0, &opts);
2416 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2417
2418 ASSERT_NE(offer.get(), nullptr);
2419 const ContentInfo* content = offer->GetContentByName("video");
2420 ASSERT_NE(content, nullptr);
2421 const MediaContentDescription* cd = content->media_description();
2422 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002423 const StreamParamsVec& streams = cd->streams();
2424 ASSERT_THAT(streams, SizeIs(1));
2425 const StreamParams& stream = streams[0];
2426 ASSERT_THAT(stream.ssrcs, IsEmpty());
2427 EXPECT_FALSE(stream.has_rids());
2428 EXPECT_FALSE(cd->HasSimulcast());
2429}
2430
2431// Create an answer with spec-compliant simulcast video stream.
2432// In this scenario, the SFU is the caller requesting that we send Simulcast.
2433TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2434 MediaSessionOptions offer_opts;
2435 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2436 RtpTransceiverDirection::kSendRecv, kActive,
2437 &offer_opts);
2438 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2439 {kMediaStream1}, 1, &offer_opts);
2440 std::unique_ptr<SessionDescription> offer =
2441 f1_.CreateOffer(offer_opts, nullptr);
2442
2443 MediaSessionOptions answer_opts;
2444 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2445 RtpTransceiverDirection::kSendRecv, kActive,
2446 &answer_opts);
2447
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002448 std::vector<RidDescription> rid_descriptions{
2449 RidDescription("f", RidDirection::kSend),
2450 RidDescription("h", RidDirection::kSend),
2451 RidDescription("q", RidDirection::kSend),
2452 };
2453 SimulcastLayerList simulcast_layers;
2454 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2455 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2456 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2457 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2458 {kMediaStream1}, rid_descriptions,
2459 simulcast_layers, 0, &answer_opts);
2460 std::unique_ptr<SessionDescription> answer =
2461 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2462
2463 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002464 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002465}
2466
2467// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2468// In this scenario, RIDs do not need to be negotiated (there is only one).
2469// Note that RID Direction is not the same as the transceiver direction.
2470TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2471 MediaSessionOptions offer_opts;
2472 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2473 RtpTransceiverDirection::kSendRecv, kActive,
2474 &offer_opts);
2475 RidDescription rid_offer("f", RidDirection::kSend);
2476 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2477 {kMediaStream1}, {rid_offer},
2478 SimulcastLayerList(), 0, &offer_opts);
2479 std::unique_ptr<SessionDescription> offer =
2480 f1_.CreateOffer(offer_opts, nullptr);
2481
2482 MediaSessionOptions answer_opts;
2483 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2484 RtpTransceiverDirection::kSendRecv, kActive,
2485 &answer_opts);
2486
2487 RidDescription rid_answer("f", RidDirection::kReceive);
2488 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2489 {kMediaStream1}, {rid_answer},
2490 SimulcastLayerList(), 0, &answer_opts);
2491 std::unique_ptr<SessionDescription> answer =
2492 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2493
2494 ASSERT_NE(answer.get(), nullptr);
2495 const ContentInfo* content = offer->GetContentByName("video");
2496 ASSERT_NE(content, nullptr);
2497 const MediaContentDescription* cd = content->media_description();
2498 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002499 const StreamParamsVec& streams = cd->streams();
2500 ASSERT_THAT(streams, SizeIs(1));
2501 const StreamParams& stream = streams[0];
2502 ASSERT_THAT(stream.ssrcs, IsEmpty());
2503 EXPECT_FALSE(stream.has_rids());
2504 EXPECT_FALSE(cd->HasSimulcast());
2505}
2506
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002507// Create an audio and video answer to a standard video offer with:
2508// - one video track
2509// - two audio tracks
2510// - two data tracks
2511// and ensure it matches what we expect. Also updates the initial answer by
2512// adding a new video track and removes one of the audio tracks.
2513TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2514 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002515 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2516 RtpTransceiverDirection::kRecvOnly, kActive,
2517 &offer_opts);
2518 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2519 RtpTransceiverDirection::kRecvOnly, kActive,
2520 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002521 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002522 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2523 RtpTransceiverDirection::kRecvOnly, kActive,
2524 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002525 f1_.set_secure(SEC_ENABLED);
2526 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002527 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528
zhihuang1c378ed2017-08-17 14:10:50 -07002529 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002530 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2531 RtpTransceiverDirection::kSendRecv, kActive,
2532 &answer_opts);
2533 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2534 RtpTransceiverDirection::kSendRecv, kActive,
2535 &answer_opts);
2536 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2537 {kMediaStream1}, 1, &answer_opts);
2538 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2539 {kMediaStream1}, 1, &answer_opts);
2540 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2541 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002542
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002543 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2544 RtpTransceiverDirection::kSendRecv, kActive,
2545 &answer_opts);
2546 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2547 {kMediaStream1}, 1, &answer_opts);
2548 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2549 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002550 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002551
Steve Anton6fe1fba2018-12-11 10:15:23 -08002552 std::unique_ptr<SessionDescription> answer =
2553 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002554
2555 ASSERT_TRUE(answer.get() != NULL);
2556 const ContentInfo* ac = answer->GetContentByName("audio");
2557 const ContentInfo* vc = answer->GetContentByName("video");
2558 const ContentInfo* dc = answer->GetContentByName("data");
2559 ASSERT_TRUE(ac != NULL);
2560 ASSERT_TRUE(vc != NULL);
2561 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002562 const AudioContentDescription* acd = ac->media_description()->as_audio();
2563 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002564 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002565 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2566 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2567 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002568
2569 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002570 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002571
2572 const StreamParamsVec& audio_streams = acd->streams();
2573 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002574 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002575 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2576 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2577 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2578 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2579 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2580 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2581
2582 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2583 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2584
2585 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002586 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002587
2588 const StreamParamsVec& video_streams = vcd->streams();
2589 ASSERT_EQ(1U, video_streams.size());
2590 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2591 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2592 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2593 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2594
2595 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002596 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002597
2598 const StreamParamsVec& data_streams = dcd->streams();
2599 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002600 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002601 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2602 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2603 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2604 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2605 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2606 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2607
2608 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002609 dcd->bandwidth()); // default bandwidth (auto)
2610 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002611
2612 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002613 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002614 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2615 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002616 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2617 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002618 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002619 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002620
2621 ASSERT_TRUE(updated_answer.get() != NULL);
2622 ac = updated_answer->GetContentByName("audio");
2623 vc = updated_answer->GetContentByName("video");
2624 dc = updated_answer->GetContentByName("data");
2625 ASSERT_TRUE(ac != NULL);
2626 ASSERT_TRUE(vc != NULL);
2627 ASSERT_TRUE(dc != NULL);
2628 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002629 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002630 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002631 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002632 const RtpDataContentDescription* updated_dcd =
2633 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002634
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002635 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002636 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002637 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002638 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002639 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002640 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2641
2642 EXPECT_EQ(acd->type(), updated_acd->type());
2643 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2644 EXPECT_EQ(vcd->type(), updated_vcd->type());
2645 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2646 EXPECT_EQ(dcd->type(), updated_dcd->type());
2647 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2648
2649 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2650 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002651 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002652
2653 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2654 ASSERT_EQ(2U, updated_video_streams.size());
2655 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2656 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002657 // All media streams in one PeerConnection share one CNAME.
2658 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002659
2660 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2661 ASSERT_EQ(1U, updated_data_streams.size());
2662 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2663}
2664
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002665// Create an updated offer after creating an answer to the original offer and
2666// verify that the codecs that were part of the original answer are not changed
2667// in the updated offer.
2668TEST_F(MediaSessionDescriptionFactoryTest,
2669 RespondentCreatesOfferAfterCreatingAnswer) {
2670 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002671 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002672
Steve Anton6fe1fba2018-12-11 10:15:23 -08002673 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2674 std::unique_ptr<SessionDescription> answer =
2675 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002676
2677 const AudioContentDescription* acd =
2678 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002679 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680
2681 const VideoContentDescription* vcd =
2682 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002683 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684
kwiberg31022942016-03-11 14:18:21 -08002685 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686 f2_.CreateOffer(opts, answer.get()));
2687
2688 // The expected audio codecs are the common audio codecs from the first
2689 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2690 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002691 // TODO(wu): |updated_offer| should not include the codec
2692 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002693 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002694 kAudioCodecsAnswer[0],
2695 kAudioCodecsAnswer[1],
2696 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002697 };
2698
2699 // The expected video codecs are the common video codecs from the first
2700 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2701 // preference order.
2702 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002703 kVideoCodecsAnswer[0],
2704 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002705 };
2706
2707 const AudioContentDescription* updated_acd =
2708 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002709 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002710
2711 const VideoContentDescription* updated_vcd =
2712 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002713 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714}
2715
Steve Anton5c72e712018-12-10 14:25:30 -08002716// Test that a reoffer does not reuse audio codecs from a previous media section
2717// that is being recycled.
2718TEST_F(MediaSessionDescriptionFactoryTest,
2719 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002720 f1_.set_video_codecs({});
2721 f2_.set_video_codecs({});
Steve Anton5c72e712018-12-10 14:25:30 -08002722
2723 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002724 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2725 RtpTransceiverDirection::kSendRecv, kActive,
2726 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002727 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2728 std::unique_ptr<SessionDescription> answer =
2729 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002730
2731 // Recycle the media section by changing its mid.
2732 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002733 std::unique_ptr<SessionDescription> reoffer =
2734 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002735
2736 // Expect that the results of the first negotiation are ignored. If the m=
2737 // section was not recycled the payload types would match the initial offerer.
2738 const AudioContentDescription* acd =
2739 GetFirstAudioContentDescription(reoffer.get());
2740 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2741}
2742
2743// Test that a reoffer does not reuse video codecs from a previous media section
2744// that is being recycled.
2745TEST_F(MediaSessionDescriptionFactoryTest,
2746 ReOfferDoesNotReUseRecycledVideoCodecs) {
2747 f1_.set_audio_codecs({}, {});
2748 f2_.set_audio_codecs({}, {});
2749
2750 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002751 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2752 RtpTransceiverDirection::kSendRecv, kActive,
2753 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002754 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2755 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002756
2757 // Recycle the media section by changing its mid.
2758 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002759 std::unique_ptr<SessionDescription> reoffer =
2760 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002761
2762 // Expect that the results of the first negotiation are ignored. If the m=
2763 // section was not recycled the payload types would match the initial offerer.
2764 const VideoContentDescription* vcd =
2765 GetFirstVideoContentDescription(reoffer.get());
2766 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2767}
2768
2769// Test that a reanswer does not reuse audio codecs from a previous media
2770// section that is being recycled.
2771TEST_F(MediaSessionDescriptionFactoryTest,
2772 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002773 f1_.set_video_codecs({});
2774 f2_.set_video_codecs({});
Steve Anton5c72e712018-12-10 14:25:30 -08002775
2776 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2777 // second offer/answer is forward (|f1_| as offerer).
2778 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002779 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2780 RtpTransceiverDirection::kSendRecv, kActive,
2781 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002782 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2783 std::unique_ptr<SessionDescription> answer =
2784 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002785
2786 // Recycle the media section by changing its mid.
2787 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002788 std::unique_ptr<SessionDescription> reoffer =
2789 f1_.CreateOffer(opts, answer.get());
2790 std::unique_ptr<SessionDescription> reanswer =
2791 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002792
2793 // Expect that the results of the first negotiation are ignored. If the m=
2794 // section was not recycled the payload types would match the initial offerer.
2795 const AudioContentDescription* acd =
2796 GetFirstAudioContentDescription(reanswer.get());
2797 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2798}
2799
2800// Test that a reanswer does not reuse video codecs from a previous media
2801// section that is being recycled.
2802TEST_F(MediaSessionDescriptionFactoryTest,
2803 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2804 f1_.set_audio_codecs({}, {});
2805 f2_.set_audio_codecs({}, {});
2806
2807 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2808 // second offer/answer is forward (|f1_| as offerer).
2809 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002810 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2811 RtpTransceiverDirection::kSendRecv, kActive,
2812 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002813 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2814 std::unique_ptr<SessionDescription> answer =
2815 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002816
2817 // Recycle the media section by changing its mid.
2818 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002819 std::unique_ptr<SessionDescription> reoffer =
2820 f1_.CreateOffer(opts, answer.get());
2821 std::unique_ptr<SessionDescription> reanswer =
2822 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002823
2824 // Expect that the results of the first negotiation are ignored. If the m=
2825 // section was not recycled the payload types would match the initial offerer.
2826 const VideoContentDescription* vcd =
2827 GetFirstVideoContentDescription(reanswer.get());
2828 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2829}
2830
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002831// Create an updated offer after creating an answer to the original offer and
2832// verify that the codecs that were part of the original answer are not changed
2833// in the updated offer. In this test Rtx is enabled.
2834TEST_F(MediaSessionDescriptionFactoryTest,
2835 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2836 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002837 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2838 RtpTransceiverDirection::kRecvOnly, kActive,
2839 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002840 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002841 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002842 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002843 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002844
2845 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002846 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002847 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002848 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002849
Steve Anton6fe1fba2018-12-11 10:15:23 -08002850 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002851 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002852 std::unique_ptr<SessionDescription> answer =
2853 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002854
2855 const VideoContentDescription* vcd =
2856 GetFirstVideoContentDescription(answer.get());
2857
2858 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002859 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2860 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861
2862 EXPECT_EQ(expected_codecs, vcd->codecs());
2863
deadbeef67cf2c12016-04-13 10:07:16 -07002864 // Now, make sure we get same result (except for the order) if |f2_| creates
2865 // an updated offer even though the default payload types between |f1_| and
2866 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002867 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002868 f2_.CreateOffer(opts, answer.get()));
2869 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002870 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002871 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2872
2873 const VideoContentDescription* updated_vcd =
2874 GetFirstVideoContentDescription(updated_answer.get());
2875
2876 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2877}
2878
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002879// Regression test for:
2880// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2881// Existing codecs should always appear before new codecs in re-offers. But
2882// under a specific set of circumstances, the existing RTX codec was ending up
2883// added to the end of the list.
2884TEST_F(MediaSessionDescriptionFactoryTest,
2885 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2886 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002887 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2888 RtpTransceiverDirection::kRecvOnly, kActive,
2889 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002890 // We specifically choose different preferred payload types for VP8 to
2891 // trigger the issue.
2892 cricket::VideoCodec vp8_offerer(100, "VP8");
2893 cricket::VideoCodec vp8_offerer_rtx =
2894 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2895 cricket::VideoCodec vp8_answerer(110, "VP8");
2896 cricket::VideoCodec vp8_answerer_rtx =
2897 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2898 cricket::VideoCodec vp9(120, "VP9");
2899 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2900
2901 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2902 // We also specifically cause the answerer to prefer VP9, such that if it
2903 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2904 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2905 vp8_answerer_rtx};
2906
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002907 f1_.set_video_codecs(f1_codecs);
2908 f2_.set_video_codecs(f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002909 std::vector<AudioCodec> audio_codecs;
2910 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2911 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2912
2913 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002914 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002915 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002916 std::unique_ptr<SessionDescription> answer =
2917 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002918
2919 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2920 // But if the bug is triggered, RTX for VP8 ends up last.
2921 std::unique_ptr<SessionDescription> updated_offer(
2922 f2_.CreateOffer(opts, answer.get()));
2923
2924 const VideoContentDescription* vcd =
2925 GetFirstVideoContentDescription(updated_offer.get());
2926 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2927 ASSERT_EQ(4u, codecs.size());
2928 EXPECT_EQ(vp8_offerer, codecs[0]);
2929 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2930 EXPECT_EQ(vp9, codecs[2]);
2931 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002932}
2933
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002934// Create an updated offer that adds video after creating an audio only answer
2935// to the original offer. This test verifies that if a video codec and the RTX
2936// codec have the same default payload type as an audio codec that is already in
2937// use, the added codecs payload types are changed.
2938TEST_F(MediaSessionDescriptionFactoryTest,
2939 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2940 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002941 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002942 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002943 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002944
2945 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002946 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2947 RtpTransceiverDirection::kRecvOnly, kActive,
2948 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002949
Steve Anton6fe1fba2018-12-11 10:15:23 -08002950 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2951 std::unique_ptr<SessionDescription> answer =
2952 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002953
2954 const AudioContentDescription* acd =
2955 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002956 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002957
2958 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2959 // reference be the same as an audio codec that was negotiated in the
2960 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002961 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002962 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002963
2964 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2965 int used_pl_type = acd->codecs()[0].id;
2966 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002967 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00002968 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002969
kwiberg31022942016-03-11 14:18:21 -08002970 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002971 f2_.CreateOffer(opts, answer.get()));
2972 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002973 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2975
2976 const AudioContentDescription* updated_acd =
2977 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002978 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002979
2980 const VideoContentDescription* updated_vcd =
2981 GetFirstVideoContentDescription(updated_answer.get());
2982
2983 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002984 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002985 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002986 EXPECT_NE(used_pl_type, new_h264_pl_type);
2987 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002988 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002989 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2990 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2991}
2992
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002993// Create an updated offer with RTX after creating an answer to an offer
2994// without RTX, and with different default payload types.
2995// Verify that the added RTX codec references the correct payload type.
2996TEST_F(MediaSessionDescriptionFactoryTest,
2997 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2998 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002999 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003000
3001 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3002 // This creates rtx for H264 with the payload type |f2_| uses.
3003 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003004 f2_.set_video_codecs(f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003005
Steve Anton6fe1fba2018-12-11 10:15:23 -08003006 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003007 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003008 std::unique_ptr<SessionDescription> answer =
3009 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003010
3011 const VideoContentDescription* vcd =
3012 GetFirstVideoContentDescription(answer.get());
3013
3014 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3015 EXPECT_EQ(expected_codecs, vcd->codecs());
3016
3017 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
3018 // updated offer, even though the default payload types are different from
3019 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08003020 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003021 f2_.CreateOffer(opts, answer.get()));
3022 ASSERT_TRUE(updated_offer);
3023
3024 const VideoContentDescription* updated_vcd =
3025 GetFirstVideoContentDescription(updated_offer.get());
3026
3027 // New offer should attempt to add H263, and RTX for H264.
3028 expected_codecs.push_back(kVideoCodecs2[1]);
3029 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3030 &expected_codecs);
3031 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3032}
3033
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003034// Test that RTX is ignored when there is no associated payload type parameter.
3035TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3036 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003037 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3038 RtpTransceiverDirection::kRecvOnly, kActive,
3039 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003040 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003041 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003042 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003043 f1_.set_video_codecs(f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003044
3045 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003046 // This creates RTX for H264 with the payload type |f2_| uses.
3047 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003048 f2_.set_video_codecs(f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003049
Steve Anton6fe1fba2018-12-11 10:15:23 -08003050 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003051 ASSERT_TRUE(offer.get() != NULL);
3052 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3053 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3054 // is possible to test that that RTX is dropped when
3055 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003056 MediaContentDescription* media_desc =
3057 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3058 ASSERT_TRUE(media_desc);
3059 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003060 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003061 for (VideoCodec& codec : codecs) {
3062 if (codec.name.find(cricket::kRtxCodecName) == 0) {
3063 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003064 }
3065 }
3066 desc->set_codecs(codecs);
3067
Steve Anton6fe1fba2018-12-11 10:15:23 -08003068 std::unique_ptr<SessionDescription> answer =
3069 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003070
Steve Anton64b626b2019-01-28 17:25:26 -08003071 EXPECT_THAT(
3072 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3073 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003074}
3075
3076// Test that RTX will be filtered out in the answer if its associated payload
3077// type doesn't match the local value.
3078TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3079 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003080 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3081 RtpTransceiverDirection::kRecvOnly, kActive,
3082 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003083 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3084 // This creates RTX for H264 in sender.
3085 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003086 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003087
3088 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3089 // This creates RTX for H263 in receiver.
3090 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003091 f2_.set_video_codecs(f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003092
Steve Anton6fe1fba2018-12-11 10:15:23 -08003093 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003094 ASSERT_TRUE(offer.get() != NULL);
3095 // Associated payload type doesn't match, therefore, RTX codec is removed in
3096 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003097 std::unique_ptr<SessionDescription> answer =
3098 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003099
Steve Anton64b626b2019-01-28 17:25:26 -08003100 EXPECT_THAT(
3101 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3102 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003103}
3104
3105// Test that when multiple RTX codecs are offered, only the matched RTX codec
3106// is added in the answer, and the unsupported RTX codec is filtered out.
3107TEST_F(MediaSessionDescriptionFactoryTest,
3108 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3109 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003110 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3111 RtpTransceiverDirection::kRecvOnly, kActive,
3112 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003113 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3114 // This creates RTX for H264-SVC in sender.
3115 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003116 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003117
3118 // This creates RTX for H264 in sender.
3119 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003120 f1_.set_video_codecs(f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003121
3122 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3123 // This creates RTX for H264 in receiver.
3124 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003125 f2_.set_video_codecs(f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003126
3127 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3128 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003129 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003130 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003131 std::unique_ptr<SessionDescription> answer =
3132 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003133 const VideoContentDescription* vcd =
3134 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003135 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3136 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3137 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003138
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003139 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003140}
3141
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003142// Test that after one RTX codec has been negotiated, a new offer can attempt
3143// to add another.
3144TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3145 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003146 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3147 RtpTransceiverDirection::kRecvOnly, kActive,
3148 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003149 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3150 // This creates RTX for H264 for the offerer.
3151 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003152 f1_.set_video_codecs(f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003153
Steve Anton6fe1fba2018-12-11 10:15:23 -08003154 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003155 ASSERT_TRUE(offer);
3156 const VideoContentDescription* vcd =
3157 GetFirstVideoContentDescription(offer.get());
3158
3159 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3160 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3161 &expected_codecs);
3162 EXPECT_EQ(expected_codecs, vcd->codecs());
3163
3164 // Now, attempt to add RTX for H264-SVC.
3165 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003166 f1_.set_video_codecs(f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003167
kwiberg31022942016-03-11 14:18:21 -08003168 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003169 f1_.CreateOffer(opts, offer.get()));
3170 ASSERT_TRUE(updated_offer);
3171 vcd = GetFirstVideoContentDescription(updated_offer.get());
3172
3173 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3174 &expected_codecs);
3175 EXPECT_EQ(expected_codecs, vcd->codecs());
3176}
3177
Noah Richards2e7a0982015-05-18 14:02:54 -07003178// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3179// generated for each simulcast ssrc and correctly grouped.
3180TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3181 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003182 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3183 RtpTransceiverDirection::kSendRecv, kActive,
3184 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003185 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003186 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3187 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003188
3189 // Use a single real codec, and then add RTX for it.
3190 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003191 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003192 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003193 f1_.set_video_codecs(f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003194
3195 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3196 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003197 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003198 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003199 MediaContentDescription* media_desc =
3200 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3201 ASSERT_TRUE(media_desc);
3202 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003203 const StreamParamsVec& streams = desc->streams();
3204 // Single stream.
3205 ASSERT_EQ(1u, streams.size());
3206 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3207 EXPECT_EQ(6u, streams[0].ssrcs.size());
3208 // And should have a SIM group for the simulcast.
3209 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3210 // And a FID group for RTX.
3211 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003212 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003213 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3214 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003215 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003216 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3217 EXPECT_EQ(3u, fid_ssrcs.size());
3218}
3219
brandtr03d5fb12016-11-22 03:37:59 -08003220// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3221// together with a FEC-FR grouping.
3222TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3223 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003224 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3225 RtpTransceiverDirection::kSendRecv, kActive,
3226 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003227 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003228 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3229 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003230
3231 // Use a single real codec, and then add FlexFEC for it.
3232 std::vector<VideoCodec> f1_codecs;
3233 f1_codecs.push_back(VideoCodec(97, "H264"));
3234 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003235 f1_.set_video_codecs(f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003236
3237 // Ensure that the offer has a single FlexFEC ssrc and that
3238 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003239 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003240 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003241 MediaContentDescription* media_desc =
3242 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3243 ASSERT_TRUE(media_desc);
3244 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003245 const StreamParamsVec& streams = desc->streams();
3246 // Single stream.
3247 ASSERT_EQ(1u, streams.size());
3248 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3249 EXPECT_EQ(2u, streams[0].ssrcs.size());
3250 // And should have a FEC-FR group for FlexFEC.
3251 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3252 std::vector<uint32_t> primary_ssrcs;
3253 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3254 ASSERT_EQ(1u, primary_ssrcs.size());
3255 uint32_t flexfec_ssrc;
3256 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3257 EXPECT_NE(flexfec_ssrc, 0u);
3258}
3259
3260// Test that FlexFEC is disabled for simulcast.
3261// TODO(brandtr): Remove this test when we support simulcast, either through
3262// multiple FlexfecSenders, or through multistream protection.
3263TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3264 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003265 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3266 RtpTransceiverDirection::kSendRecv, kActive,
3267 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003268 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003269 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3270 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003271
3272 // Use a single real codec, and then add FlexFEC for it.
3273 std::vector<VideoCodec> f1_codecs;
3274 f1_codecs.push_back(VideoCodec(97, "H264"));
3275 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00003276 f1_.set_video_codecs(f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003277
3278 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3279 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003280 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003281 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003282 MediaContentDescription* media_desc =
3283 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3284 ASSERT_TRUE(media_desc);
3285 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003286 const StreamParamsVec& streams = desc->streams();
3287 // Single stream.
3288 ASSERT_EQ(1u, streams.size());
3289 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3290 EXPECT_EQ(3u, streams[0].ssrcs.size());
3291 // And should have a SIM group for the simulcast.
3292 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3293 // And not a FEC-FR group for FlexFEC.
3294 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3295 std::vector<uint32_t> primary_ssrcs;
3296 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3297 EXPECT_EQ(3u, primary_ssrcs.size());
3298 for (uint32_t primary_ssrc : primary_ssrcs) {
3299 uint32_t flexfec_ssrc;
3300 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3301 }
3302}
3303
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003304// Create an updated offer after creating an answer to the original offer and
3305// verify that the RTP header extensions that were part of the original answer
3306// are not changed in the updated offer.
3307TEST_F(MediaSessionDescriptionFactoryTest,
3308 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3309 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003310 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003311
3312 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3313 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3314 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3315 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3316
Steve Anton6fe1fba2018-12-11 10:15:23 -08003317 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3318 std::unique_ptr<SessionDescription> answer =
3319 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003320
Yves Gerey665174f2018-06-19 15:03:05 +02003321 EXPECT_EQ(
3322 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3323 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3324 EXPECT_EQ(
3325 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3326 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003327
kwiberg31022942016-03-11 14:18:21 -08003328 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003329 f2_.CreateOffer(opts, answer.get()));
3330
3331 // The expected RTP header extensions in the new offer are the resulting
3332 // extensions from the first offer/answer exchange plus the extensions only
3333 // |f2_| offer.
3334 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003335 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003336 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003337 kAudioRtpExtensionAnswer[0],
3338 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003339 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003340 };
3341
3342 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003343 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003344 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003345 kVideoRtpExtensionAnswer[0],
3346 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003347 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003348 };
3349
3350 const AudioContentDescription* updated_acd =
3351 GetFirstAudioContentDescription(updated_offer.get());
3352 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3353 updated_acd->rtp_header_extensions());
3354
3355 const VideoContentDescription* updated_vcd =
3356 GetFirstVideoContentDescription(updated_offer.get());
3357 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3358 updated_vcd->rtp_header_extensions());
3359}
3360
deadbeefa5b273a2015-08-20 17:30:13 -07003361// Verify that if the same RTP extension URI is used for audio and video, the
3362// same ID is used. Also verify that the ID isn't changed when creating an
3363// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003364TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003365 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003366 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003367
3368 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3369 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3370
Steve Anton6fe1fba2018-12-11 10:15:23 -08003371 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003372
3373 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3374 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003375 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003376 kVideoRtpExtension3[0],
3377 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003378 };
3379
Yves Gerey665174f2018-06-19 15:03:05 +02003380 EXPECT_EQ(
3381 MAKE_VECTOR(kAudioRtpExtension3),
3382 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3383 EXPECT_EQ(
3384 MAKE_VECTOR(kExpectedVideoRtpExtension),
3385 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003386
3387 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003388 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003389 f1_.CreateOffer(opts, offer.get()));
3390
3391 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003392 GetFirstAudioContentDescription(updated_offer.get())
3393 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003394 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003395 GetFirstVideoContentDescription(updated_offer.get())
3396 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003397}
3398
jbauch5869f502017-06-29 12:31:36 -07003399// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3400TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3401 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003402 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003403
3404 f1_.set_enable_encrypted_rtp_header_extensions(true);
3405 f2_.set_enable_encrypted_rtp_header_extensions(true);
3406
3407 f1_.set_audio_rtp_header_extensions(
3408 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3409 f1_.set_video_rtp_header_extensions(
3410 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3411
Steve Anton6fe1fba2018-12-11 10:15:23 -08003412 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003413
3414 // The extensions that are shared between audio and video should use the same
3415 // id.
3416 const RtpExtension kExpectedVideoRtpExtension[] = {
3417 kVideoRtpExtension3ForEncryption[0],
3418 kAudioRtpExtension3ForEncryptionOffer[1],
3419 kAudioRtpExtension3ForEncryptionOffer[2],
3420 };
3421
Yves Gerey665174f2018-06-19 15:03:05 +02003422 EXPECT_EQ(
3423 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3424 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3425 EXPECT_EQ(
3426 MAKE_VECTOR(kExpectedVideoRtpExtension),
3427 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003428
3429 // Nothing should change when creating a new offer
3430 std::unique_ptr<SessionDescription> updated_offer(
3431 f1_.CreateOffer(opts, offer.get()));
3432
3433 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003434 GetFirstAudioContentDescription(updated_offer.get())
3435 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003436 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003437 GetFirstVideoContentDescription(updated_offer.get())
3438 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003439}
3440
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003441TEST(MediaSessionDescription, CopySessionDescription) {
3442 SessionDescription source;
3443 cricket::ContentGroup group(cricket::CN_AUDIO);
3444 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003445 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003446 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003447 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3448 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003449 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003450 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003451 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003452 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3453 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003454 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003455
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003456 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003457 ASSERT_TRUE(copy.get() != NULL);
3458 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3459 const ContentInfo* ac = copy->GetContentByName("audio");
3460 const ContentInfo* vc = copy->GetContentByName("video");
3461 ASSERT_TRUE(ac != NULL);
3462 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003463 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003464 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003465 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3466 EXPECT_EQ(1u, acd->first_ssrc());
3467
Steve Anton5adfafd2017-12-20 16:34:00 -08003468 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003469 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003470 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3471 EXPECT_EQ(2u, vcd->first_ssrc());
3472}
3473
3474// The below TestTransportInfoXXX tests create different offers/answers, and
3475// ensure the TransportInfo in the SessionDescription matches what we expect.
3476TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3477 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003478 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3479 RtpTransceiverDirection::kRecvOnly, kActive,
3480 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003481 TestTransportInfo(true, options, false);
3482}
3483
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003484TEST_F(MediaSessionDescriptionFactoryTest,
3485 TestTransportInfoOfferIceRenomination) {
3486 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003487 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3488 RtpTransceiverDirection::kRecvOnly, kActive,
3489 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003490 options.media_description_options[0]
3491 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003492 TestTransportInfo(true, options, false);
3493}
3494
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003495TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3496 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003497 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3498 RtpTransceiverDirection::kRecvOnly, kActive,
3499 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003500 TestTransportInfo(true, options, true);
3501}
3502
3503TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3504 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003505 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3506 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3507 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003508 TestTransportInfo(true, options, false);
3509}
3510
3511TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003512 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003513 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003514 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3515 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3516 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003517 TestTransportInfo(true, options, true);
3518}
3519
3520TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3521 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003522 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3523 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3524 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003525 options.bundle_enabled = true;
3526 TestTransportInfo(true, options, false);
3527}
3528
3529TEST_F(MediaSessionDescriptionFactoryTest,
3530 TestTransportInfoOfferBundleCurrent) {
3531 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003532 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3533 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3534 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003535 options.bundle_enabled = true;
3536 TestTransportInfo(true, options, true);
3537}
3538
3539TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3540 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003541 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3542 RtpTransceiverDirection::kRecvOnly, kActive,
3543 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003544 TestTransportInfo(false, options, false);
3545}
3546
3547TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003548 TestTransportInfoAnswerIceRenomination) {
3549 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003550 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3551 RtpTransceiverDirection::kRecvOnly, kActive,
3552 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003553 options.media_description_options[0]
3554 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003555 TestTransportInfo(false, options, false);
3556}
3557
3558TEST_F(MediaSessionDescriptionFactoryTest,
3559 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003560 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003561 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3562 RtpTransceiverDirection::kRecvOnly, kActive,
3563 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003564 TestTransportInfo(false, options, true);
3565}
3566
3567TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3568 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003569 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3570 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3571 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003572 TestTransportInfo(false, options, false);
3573}
3574
3575TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003576 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003577 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003578 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3579 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3580 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003581 TestTransportInfo(false, options, true);
3582}
3583
3584TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3585 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003586 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3587 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3588 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003589 options.bundle_enabled = true;
3590 TestTransportInfo(false, options, false);
3591}
3592
3593TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003594 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003595 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003596 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3597 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3598 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003599 options.bundle_enabled = true;
3600 TestTransportInfo(false, options, true);
3601}
3602
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003603TEST_F(MediaSessionDescriptionFactoryTest,
3604 TestTransportInfoOfferBundlesTransportOptions) {
3605 MediaSessionOptions options;
3606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3607
3608 cricket::OpaqueTransportParameters audio_params;
3609 audio_params.protocol = "audio-transport";
3610 audio_params.parameters = "audio-params";
3611 FindFirstMediaDescriptionByMid("audio", &options)
3612 ->transport_options.opaque_parameters = audio_params;
3613
3614 cricket::OpaqueTransportParameters video_params;
3615 video_params.protocol = "video-transport";
3616 video_params.parameters = "video-params";
3617 FindFirstMediaDescriptionByMid("video", &options)
3618 ->transport_options.opaque_parameters = video_params;
3619
3620 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3621}
3622
3623TEST_F(MediaSessionDescriptionFactoryTest,
3624 TestTransportInfoAnswerBundlesTransportOptions) {
3625 MediaSessionOptions options;
3626 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3627
3628 cricket::OpaqueTransportParameters audio_params;
3629 audio_params.protocol = "audio-transport";
3630 audio_params.parameters = "audio-params";
3631 FindFirstMediaDescriptionByMid("audio", &options)
3632 ->transport_options.opaque_parameters = audio_params;
3633
3634 cricket::OpaqueTransportParameters video_params;
3635 video_params.protocol = "video-transport";
3636 video_params.parameters = "video-params";
3637 FindFirstMediaDescriptionByMid("video", &options)
3638 ->transport_options.opaque_parameters = video_params;
3639
3640 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3641}
3642
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003643TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3644 MediaSessionOptions options;
3645 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3646 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3647 &options);
3648
3649 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3650 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3651 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3652
3653 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3654
3655 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3656 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3657 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3658}
3659
3660TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3661 MediaSessionOptions options;
3662 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3663 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3664 &options);
3665
3666 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3667 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3668 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3669
3670 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3671 std::unique_ptr<SessionDescription> answer =
3672 f1_.CreateAnswer(offer.get(), options, nullptr);
3673
3674 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3675 "foo");
3676 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3677 "bar");
3678 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3679}
3680
3681TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3682 MediaSessionOptions options;
3683 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3684 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3685 &options);
3686
3687 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3688
3689 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3690 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3691 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3692
3693 std::unique_ptr<SessionDescription> answer =
3694 f1_.CreateAnswer(offer.get(), options, nullptr);
3695
3696 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3697 absl::nullopt);
3698 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3699 absl::nullopt);
3700 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3701 absl::nullopt);
3702}
3703
3704TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3705 MediaSessionOptions options;
3706 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3707 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3708 &options);
3709
3710 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3711 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3712 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3713
3714 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3715
3716 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3717 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3718 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3719
3720 std::unique_ptr<SessionDescription> answer =
3721 f1_.CreateAnswer(offer.get(), options, nullptr);
3722
3723 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3724 absl::nullopt);
3725 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3726 absl::nullopt);
3727 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3728 absl::nullopt);
3729}
3730
3731TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3732 MediaSessionOptions options;
3733 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3734 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3735 &options);
3736
3737 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3738 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3739 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3740
3741 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3742
3743 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3744 absl::nullopt;
3745 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3746 absl::nullopt;
3747 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3748 absl::nullopt;
3749
3750 std::unique_ptr<SessionDescription> answer =
3751 f1_.CreateAnswer(offer.get(), options, nullptr);
3752
3753 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3754 absl::nullopt);
3755 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3756 absl::nullopt);
3757 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3758 absl::nullopt);
3759}
3760
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003761// Create an offer with bundle enabled and verify the crypto parameters are
3762// the common set of the available cryptos.
3763TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3764 TestCryptoWithBundle(true);
3765}
3766
3767// Create an answer with bundle enabled and verify the crypto parameters are
3768// the common set of the available cryptos.
3769TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3770 TestCryptoWithBundle(false);
3771}
3772
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003773// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3774// DTLS is not enabled locally.
3775TEST_F(MediaSessionDescriptionFactoryTest,
3776 TestOfferDtlsSavpfWithoutDtlsFailed) {
3777 f1_.set_secure(SEC_ENABLED);
3778 f2_.set_secure(SEC_ENABLED);
3779 tdf1_.set_secure(SEC_DISABLED);
3780 tdf2_.set_secure(SEC_DISABLED);
3781
Steve Anton6fe1fba2018-12-11 10:15:23 -08003782 std::unique_ptr<SessionDescription> offer =
3783 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003784 ASSERT_TRUE(offer.get() != NULL);
3785 ContentInfo* offer_content = offer->GetContentByName("audio");
3786 ASSERT_TRUE(offer_content != NULL);
3787 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003788 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003789 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3790
Steve Anton6fe1fba2018-12-11 10:15:23 -08003791 std::unique_ptr<SessionDescription> answer =
3792 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003793 ASSERT_TRUE(answer != NULL);
3794 ContentInfo* answer_content = answer->GetContentByName("audio");
3795 ASSERT_TRUE(answer_content != NULL);
3796
3797 ASSERT_TRUE(answer_content->rejected);
3798}
3799
3800// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3801// UDP/TLS/RTP/SAVPF.
3802TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3803 f1_.set_secure(SEC_ENABLED);
3804 f2_.set_secure(SEC_ENABLED);
3805 tdf1_.set_secure(SEC_ENABLED);
3806 tdf2_.set_secure(SEC_ENABLED);
3807
Steve Anton6fe1fba2018-12-11 10:15:23 -08003808 std::unique_ptr<SessionDescription> offer =
3809 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003810 ASSERT_TRUE(offer.get() != NULL);
3811 ContentInfo* offer_content = offer->GetContentByName("audio");
3812 ASSERT_TRUE(offer_content != NULL);
3813 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003814 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003815 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3816
Steve Anton6fe1fba2018-12-11 10:15:23 -08003817 std::unique_ptr<SessionDescription> answer =
3818 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003819 ASSERT_TRUE(answer != NULL);
3820
3821 const ContentInfo* answer_content = answer->GetContentByName("audio");
3822 ASSERT_TRUE(answer_content != NULL);
3823 ASSERT_FALSE(answer_content->rejected);
3824
3825 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003826 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003827 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003828}
3829
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003830// Test that we include both SDES and DTLS in the offer, but only include SDES
3831// in the answer if DTLS isn't negotiated.
3832TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3833 f1_.set_secure(SEC_ENABLED);
3834 f2_.set_secure(SEC_ENABLED);
3835 tdf1_.set_secure(SEC_ENABLED);
3836 tdf2_.set_secure(SEC_DISABLED);
3837 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003838 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003839 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003840 const cricket::MediaContentDescription* audio_media_desc;
3841 const cricket::MediaContentDescription* video_media_desc;
3842 const cricket::TransportDescription* audio_trans_desc;
3843 const cricket::TransportDescription* video_trans_desc;
3844
3845 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003846 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003847 ASSERT_TRUE(offer.get() != NULL);
3848
Steve Antonb1c1de12017-12-21 15:14:30 -08003849 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003850 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003851 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003852 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003853 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003854 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3855
3856 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3857 ASSERT_TRUE(audio_trans_desc != NULL);
3858 video_trans_desc = offer->GetTransportDescriptionByName("video");
3859 ASSERT_TRUE(video_trans_desc != NULL);
3860 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3861 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3862
3863 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003864 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003865 ASSERT_TRUE(answer.get() != NULL);
3866
Steve Antonb1c1de12017-12-21 15:14:30 -08003867 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003868 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003869 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003870 ASSERT_TRUE(video_media_desc != NULL);
3871 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3872 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3873
3874 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3875 ASSERT_TRUE(audio_trans_desc != NULL);
3876 video_trans_desc = answer->GetTransportDescriptionByName("video");
3877 ASSERT_TRUE(video_trans_desc != NULL);
3878 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3879 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3880
3881 // Enable DTLS; the answer should now only have DTLS support.
3882 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003883 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003884 ASSERT_TRUE(answer.get() != NULL);
3885
Steve Antonb1c1de12017-12-21 15:14:30 -08003886 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003887 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003888 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003889 ASSERT_TRUE(video_media_desc != NULL);
3890 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3891 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003892 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3893 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003894
3895 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3896 ASSERT_TRUE(audio_trans_desc != NULL);
3897 video_trans_desc = answer->GetTransportDescriptionByName("video");
3898 ASSERT_TRUE(video_trans_desc != NULL);
3899 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3900 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003901
3902 // Try creating offer again. DTLS enabled now, crypto's should be empty
3903 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003904 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003905 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003906 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003907 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003908 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003909 ASSERT_TRUE(video_media_desc != NULL);
3910 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3911 EXPECT_TRUE(video_media_desc->cryptos().empty());
3912
3913 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3914 ASSERT_TRUE(audio_trans_desc != NULL);
3915 video_trans_desc = offer->GetTransportDescriptionByName("video");
3916 ASSERT_TRUE(video_trans_desc != NULL);
3917 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3918 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003919}
3920
3921// Test that an answer can't be created if cryptos are required but the offer is
3922// unsecure.
3923TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003924 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003925 f1_.set_secure(SEC_DISABLED);
3926 tdf1_.set_secure(SEC_DISABLED);
3927 f2_.set_secure(SEC_REQUIRED);
3928 tdf1_.set_secure(SEC_ENABLED);
3929
Steve Anton6fe1fba2018-12-11 10:15:23 -08003930 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003931 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003932 std::unique_ptr<SessionDescription> answer =
3933 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003934 EXPECT_TRUE(answer.get() == NULL);
3935}
3936
3937// Test that we accept a DTLS offer without SDES and create an appropriate
3938// answer.
3939TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3940 f1_.set_secure(SEC_DISABLED);
3941 f2_.set_secure(SEC_ENABLED);
3942 tdf1_.set_secure(SEC_ENABLED);
3943 tdf2_.set_secure(SEC_ENABLED);
3944 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003945 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3946 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3947 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003948
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003949 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003950 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003951 ASSERT_TRUE(offer.get() != NULL);
3952
3953 const AudioContentDescription* audio_offer =
3954 GetFirstAudioContentDescription(offer.get());
3955 ASSERT_TRUE(audio_offer->cryptos().empty());
3956 const VideoContentDescription* video_offer =
3957 GetFirstVideoContentDescription(offer.get());
3958 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003959 const RtpDataContentDescription* data_offer =
3960 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003961 ASSERT_TRUE(data_offer->cryptos().empty());
3962
3963 const cricket::TransportDescription* audio_offer_trans_desc =
3964 offer->GetTransportDescriptionByName("audio");
3965 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3966 const cricket::TransportDescription* video_offer_trans_desc =
3967 offer->GetTransportDescriptionByName("video");
3968 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3969 const cricket::TransportDescription* data_offer_trans_desc =
3970 offer->GetTransportDescriptionByName("data");
3971 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3972
3973 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003974 std::unique_ptr<SessionDescription> answer =
3975 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003976 ASSERT_TRUE(answer.get() != NULL);
3977
3978 const cricket::TransportDescription* audio_answer_trans_desc =
3979 answer->GetTransportDescriptionByName("audio");
3980 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3981 const cricket::TransportDescription* video_answer_trans_desc =
3982 answer->GetTransportDescriptionByName("video");
3983 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3984 const cricket::TransportDescription* data_answer_trans_desc =
3985 answer->GetTransportDescriptionByName("data");
3986 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3987}
3988
3989// Verifies if vad_enabled option is set to false, CN codecs are not present in
3990// offer or answer.
3991TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3992 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003993 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003995 ASSERT_TRUE(offer.get() != NULL);
3996 const ContentInfo* audio_content = offer->GetContentByName("audio");
3997 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3998
3999 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08004000 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004001 ASSERT_TRUE(offer.get() != NULL);
4002 audio_content = offer->GetContentByName("audio");
4003 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08004004 std::unique_ptr<SessionDescription> answer =
4005 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004006 ASSERT_TRUE(answer.get() != NULL);
4007 audio_content = answer->GetContentByName("audio");
4008 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
4009}
deadbeef44f08192015-12-15 16:20:09 -08004010
zhihuang1c378ed2017-08-17 14:10:50 -07004011// Test that the generated MIDs match the existing offer.
4012TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08004013 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004014 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
4015 RtpTransceiverDirection::kRecvOnly, kActive,
4016 &opts);
4017 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
4018 RtpTransceiverDirection::kRecvOnly, kActive,
4019 &opts);
deadbeef44f08192015-12-15 16:20:09 -08004020 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004021 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
4022 RtpTransceiverDirection::kSendRecv, kActive,
4023 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004024 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004025 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08004026 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08004027 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07004028
deadbeef44f08192015-12-15 16:20:09 -08004029 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
4030 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
4031 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
4032 ASSERT_TRUE(audio_content != nullptr);
4033 ASSERT_TRUE(video_content != nullptr);
4034 ASSERT_TRUE(data_content != nullptr);
4035 EXPECT_EQ("audio_modified", audio_content->name);
4036 EXPECT_EQ("video_modified", video_content->name);
4037 EXPECT_EQ("data_modified", data_content->name);
4038}
zhihuangcf5b37c2016-05-05 11:44:35 -07004039
zhihuang1c378ed2017-08-17 14:10:50 -07004040// The following tests verify that the unified plan SDP is supported.
4041// Test that we can create an offer with multiple media sections of same media
4042// type.
4043TEST_F(MediaSessionDescriptionFactoryTest,
4044 CreateOfferWithMultipleAVMediaSections) {
4045 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004046 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4047 RtpTransceiverDirection::kSendRecv, kActive,
4048 &opts);
4049 AttachSenderToMediaDescriptionOptions(
4050 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004051
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004052 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4053 RtpTransceiverDirection::kSendRecv, kActive,
4054 &opts);
4055 AttachSenderToMediaDescriptionOptions(
4056 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004057
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004058 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4059 RtpTransceiverDirection::kSendRecv, kActive,
4060 &opts);
4061 AttachSenderToMediaDescriptionOptions(
4062 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004063
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004064 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4065 RtpTransceiverDirection::kSendRecv, kActive,
4066 &opts);
4067 AttachSenderToMediaDescriptionOptions(
4068 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004069 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004070 ASSERT_TRUE(offer);
4071
4072 ASSERT_EQ(4u, offer->contents().size());
4073 EXPECT_FALSE(offer->contents()[0].rejected);
4074 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004075 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004076 ASSERT_EQ(1u, acd->streams().size());
4077 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004078 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004079
4080 EXPECT_FALSE(offer->contents()[1].rejected);
4081 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004082 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004083 ASSERT_EQ(1u, vcd->streams().size());
4084 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004085 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004086
4087 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004088 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004089 ASSERT_EQ(1u, acd->streams().size());
4090 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004091 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004092
4093 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004094 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004095 ASSERT_EQ(1u, vcd->streams().size());
4096 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004097 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004098}
4099
4100// Test that we can create an answer with multiple media sections of same media
4101// type.
4102TEST_F(MediaSessionDescriptionFactoryTest,
4103 CreateAnswerWithMultipleAVMediaSections) {
4104 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004105 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4106 RtpTransceiverDirection::kSendRecv, kActive,
4107 &opts);
4108 AttachSenderToMediaDescriptionOptions(
4109 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004110
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004111 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4112 RtpTransceiverDirection::kSendRecv, kActive,
4113 &opts);
4114 AttachSenderToMediaDescriptionOptions(
4115 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004116
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004117 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4118 RtpTransceiverDirection::kSendRecv, kActive,
4119 &opts);
4120 AttachSenderToMediaDescriptionOptions(
4121 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004122
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004123 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4124 RtpTransceiverDirection::kSendRecv, kActive,
4125 &opts);
4126 AttachSenderToMediaDescriptionOptions(
4127 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004128
Steve Anton6fe1fba2018-12-11 10:15:23 -08004129 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004130 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004131 std::unique_ptr<SessionDescription> answer =
4132 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004133
4134 ASSERT_EQ(4u, answer->contents().size());
4135 EXPECT_FALSE(answer->contents()[0].rejected);
4136 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004137 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004138 ASSERT_EQ(1u, acd->streams().size());
4139 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004140 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004141
4142 EXPECT_FALSE(answer->contents()[1].rejected);
4143 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004144 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004145 ASSERT_EQ(1u, vcd->streams().size());
4146 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004147 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004148
4149 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004150 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004151 ASSERT_EQ(1u, acd->streams().size());
4152 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004153 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004154
4155 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004156 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004157 ASSERT_EQ(1u, vcd->streams().size());
4158 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004159 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004160}
4161
4162// Test that the media section will be rejected in offer if the corresponding
4163// MediaDescriptionOptions is stopped by the offerer.
4164TEST_F(MediaSessionDescriptionFactoryTest,
4165 CreateOfferWithMediaSectionStoppedByOfferer) {
4166 // Create an offer with two audio sections and one of them is stopped.
4167 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004168 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4169 RtpTransceiverDirection::kSendRecv, kActive,
4170 &offer_opts);
4171 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4172 RtpTransceiverDirection::kInactive, kStopped,
4173 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004174 std::unique_ptr<SessionDescription> offer =
4175 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004176 ASSERT_TRUE(offer);
4177 ASSERT_EQ(2u, offer->contents().size());
4178 EXPECT_FALSE(offer->contents()[0].rejected);
4179 EXPECT_TRUE(offer->contents()[1].rejected);
4180}
4181
4182// Test that the media section will be rejected in answer if the corresponding
4183// MediaDescriptionOptions is stopped by the offerer.
4184TEST_F(MediaSessionDescriptionFactoryTest,
4185 CreateAnswerWithMediaSectionStoppedByOfferer) {
4186 // Create an offer with two audio sections and one of them is stopped.
4187 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004188 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4189 RtpTransceiverDirection::kSendRecv, kActive,
4190 &offer_opts);
4191 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4192 RtpTransceiverDirection::kInactive, kStopped,
4193 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004194 std::unique_ptr<SessionDescription> offer =
4195 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004196 ASSERT_TRUE(offer);
4197 ASSERT_EQ(2u, offer->contents().size());
4198 EXPECT_FALSE(offer->contents()[0].rejected);
4199 EXPECT_TRUE(offer->contents()[1].rejected);
4200
4201 // Create an answer based on the offer.
4202 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004203 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4204 RtpTransceiverDirection::kSendRecv, kActive,
4205 &answer_opts);
4206 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4207 RtpTransceiverDirection::kSendRecv, kActive,
4208 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004209 std::unique_ptr<SessionDescription> answer =
4210 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004211 ASSERT_EQ(2u, answer->contents().size());
4212 EXPECT_FALSE(answer->contents()[0].rejected);
4213 EXPECT_TRUE(answer->contents()[1].rejected);
4214}
4215
4216// Test that the media section will be rejected in answer if the corresponding
4217// MediaDescriptionOptions is stopped by the answerer.
4218TEST_F(MediaSessionDescriptionFactoryTest,
4219 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4220 // Create an offer with two audio sections.
4221 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004222 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4223 RtpTransceiverDirection::kSendRecv, kActive,
4224 &offer_opts);
4225 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4226 RtpTransceiverDirection::kSendRecv, kActive,
4227 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004228 std::unique_ptr<SessionDescription> offer =
4229 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004230 ASSERT_TRUE(offer);
4231 ASSERT_EQ(2u, offer->contents().size());
4232 ASSERT_FALSE(offer->contents()[0].rejected);
4233 ASSERT_FALSE(offer->contents()[1].rejected);
4234
4235 // The answerer rejects one of the audio sections.
4236 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004237 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4238 RtpTransceiverDirection::kSendRecv, kActive,
4239 &answer_opts);
4240 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4241 RtpTransceiverDirection::kInactive, kStopped,
4242 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004243 std::unique_ptr<SessionDescription> answer =
4244 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004245 ASSERT_EQ(2u, answer->contents().size());
4246 EXPECT_FALSE(answer->contents()[0].rejected);
4247 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004248
4249 // The TransportInfo of the rejected m= section is expected to be added in the
4250 // answer.
4251 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004252}
4253
4254// Test the generated media sections has the same order of the
4255// corresponding MediaDescriptionOptions.
4256TEST_F(MediaSessionDescriptionFactoryTest,
4257 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4258 MediaSessionOptions opts;
4259 // This tests put video section first because normally audio comes first by
4260 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004261 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4262 RtpTransceiverDirection::kSendRecv, kActive,
4263 &opts);
4264 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4265 RtpTransceiverDirection::kSendRecv, kActive,
4266 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004267 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004268
4269 ASSERT_TRUE(offer);
4270 ASSERT_EQ(2u, offer->contents().size());
4271 EXPECT_EQ("video", offer->contents()[0].name);
4272 EXPECT_EQ("audio", offer->contents()[1].name);
4273}
4274
4275// Test that different media sections using the same codec have same payload
4276// type.
4277TEST_F(MediaSessionDescriptionFactoryTest,
4278 PayloadTypesSharedByMediaSectionsOfSameType) {
4279 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004280 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4281 RtpTransceiverDirection::kSendRecv, kActive,
4282 &opts);
4283 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4284 RtpTransceiverDirection::kSendRecv, kActive,
4285 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004286 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004287 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004288 ASSERT_TRUE(offer);
4289 ASSERT_EQ(2u, offer->contents().size());
4290 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004291 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004292 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004293 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004294 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4295 ASSERT_EQ(2u, vcd1->codecs().size());
4296 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4297 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4298 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4299 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4300
4301 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004302 std::unique_ptr<SessionDescription> answer =
4303 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004304 ASSERT_TRUE(answer);
4305 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004306 vcd1 = answer->contents()[0].media_description()->as_video();
4307 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004308 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4309 ASSERT_EQ(1u, vcd1->codecs().size());
4310 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4311 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4312}
4313
4314// Test that the codec preference order per media section is respected in
4315// subsequent offer.
4316TEST_F(MediaSessionDescriptionFactoryTest,
4317 CreateOfferRespectsCodecPreferenceOrder) {
4318 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004319 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4320 RtpTransceiverDirection::kSendRecv, kActive,
4321 &opts);
4322 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4323 RtpTransceiverDirection::kSendRecv, kActive,
4324 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004325 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004326 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004327 ASSERT_TRUE(offer);
4328 ASSERT_EQ(2u, offer->contents().size());
4329 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004330 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004331 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004332 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004333 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4334 EXPECT_EQ(video_codecs, vcd1->codecs());
4335 EXPECT_EQ(video_codecs, vcd2->codecs());
4336
4337 // Change the codec preference of the first video section and create a
4338 // follow-up offer.
4339 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4340 vcd1->set_codecs(video_codecs_reverse);
4341 std::unique_ptr<SessionDescription> updated_offer(
4342 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004343 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4344 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004345 // The video codec preference order should be respected.
4346 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4347 EXPECT_EQ(video_codecs, vcd2->codecs());
4348}
4349
4350// Test that the codec preference order per media section is respected in
4351// the answer.
4352TEST_F(MediaSessionDescriptionFactoryTest,
4353 CreateAnswerRespectsCodecPreferenceOrder) {
4354 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004355 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4356 RtpTransceiverDirection::kSendRecv, kActive,
4357 &opts);
4358 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4359 RtpTransceiverDirection::kSendRecv, kActive,
4360 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004361 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004362 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004363 ASSERT_TRUE(offer);
4364 ASSERT_EQ(2u, offer->contents().size());
4365 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004366 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004367 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004368 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004369 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4370 EXPECT_EQ(video_codecs, vcd1->codecs());
4371 EXPECT_EQ(video_codecs, vcd2->codecs());
4372
4373 // Change the codec preference of the first video section and create an
4374 // answer.
4375 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4376 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004377 std::unique_ptr<SessionDescription> answer =
4378 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004379 vcd1 = answer->contents()[0].media_description()->as_video();
4380 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004381 // The video codec preference order should be respected.
4382 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4383 EXPECT_EQ(video_codecs, vcd2->codecs());
4384}
4385
Zhi Huang6f367472017-11-22 13:20:02 -08004386// Test that when creating an answer, the codecs use local parameters instead of
4387// the remote ones.
4388TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4389 const std::string audio_param_name = "audio_param";
4390 const std::string audio_value1 = "audio_v1";
4391 const std::string audio_value2 = "audio_v2";
4392 const std::string video_param_name = "video_param";
4393 const std::string video_value1 = "video_v1";
4394 const std::string video_value2 = "video_v2";
4395
4396 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4397 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4398 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4399 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4400
4401 // Set the parameters for codecs.
4402 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4403 video_codecs1[0].SetParam(video_param_name, video_value1);
4404 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4405 video_codecs2[0].SetParam(video_param_name, video_value2);
4406
4407 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004408 f1_.set_video_codecs(video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004409 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004410 f2_.set_video_codecs(video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004411
4412 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004413 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4414 RtpTransceiverDirection::kSendRecv, kActive,
4415 &opts);
4416 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4417 RtpTransceiverDirection::kSendRecv, kActive,
4418 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004419
Steve Anton6fe1fba2018-12-11 10:15:23 -08004420 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004421 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004422 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4423 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004424 std::string value;
4425 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4426 EXPECT_EQ(audio_value1, value);
4427 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4428 EXPECT_EQ(video_value1, value);
4429
Steve Anton6fe1fba2018-12-11 10:15:23 -08004430 std::unique_ptr<SessionDescription> answer =
4431 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004432 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004433 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4434 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004435 // Use the parameters from the local codecs.
4436 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4437 EXPECT_EQ(audio_value2, value);
4438 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4439 EXPECT_EQ(video_value2, value);
4440}
4441
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004442// Test that matching packetization-mode is part of the criteria for matching
4443// H264 codecs (in addition to profile-level-id). Previously, this was not the
4444// case, so the first H264 codec with the same profile-level-id would match and
4445// the payload type in the answer would be incorrect.
4446// This is a regression test for bugs.webrtc.org/8808
4447TEST_F(MediaSessionDescriptionFactoryTest,
4448 H264MatchCriteriaIncludesPacketizationMode) {
4449 // Create two H264 codecs with the same profile level ID and different
4450 // packetization modes.
4451 VideoCodec h264_pm0(96, "H264");
4452 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4453 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4454 VideoCodec h264_pm1(97, "H264");
4455 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4456 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4457
4458 // Offerer will send both codecs, answerer should choose the one with matching
4459 // packetization mode (and not the first one it sees).
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004460 f1_.set_video_codecs({h264_pm0, h264_pm1});
4461 f2_.set_video_codecs({h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004462
4463 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004464 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4465 RtpTransceiverDirection::kSendRecv, kActive,
4466 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004467
Steve Anton6fe1fba2018-12-11 10:15:23 -08004468 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004469 ASSERT_TRUE(offer);
4470
Steve Anton6fe1fba2018-12-11 10:15:23 -08004471 std::unique_ptr<SessionDescription> answer =
4472 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004473 ASSERT_TRUE(answer);
4474
4475 // Answer should have one negotiated codec with packetization-mode=1 using the
4476 // offered payload type.
4477 ASSERT_EQ(1u, answer->contents().size());
4478 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4479 ASSERT_EQ(1u, answer_vcd->codecs().size());
4480 auto answer_codec = answer_vcd->codecs()[0];
4481 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4482}
4483
zhihuangcf5b37c2016-05-05 11:44:35 -07004484class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4485 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004486 MediaProtocolTest()
4487 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004488 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4489 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004490 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004491 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004492 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4493 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron8e8b36a2020-02-07 14:23:45 +00004494 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004495 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004496 f1_.set_secure(SEC_ENABLED);
4497 f2_.set_secure(SEC_ENABLED);
4498 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004499 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004500 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004501 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004502 tdf1_.set_secure(SEC_ENABLED);
4503 tdf2_.set_secure(SEC_ENABLED);
4504 }
4505
4506 protected:
4507 MediaSessionDescriptionFactory f1_;
4508 MediaSessionDescriptionFactory f2_;
4509 TransportDescriptionFactory tdf1_;
4510 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004511 UniqueRandomIdGenerator ssrc_generator1;
4512 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004513};
4514
4515TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4516 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004517 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004518 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004519 ASSERT_TRUE(offer.get() != nullptr);
4520 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004521 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004522 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004523 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004524 std::unique_ptr<SessionDescription> answer =
4525 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004526 const ContentInfo* ac = answer->GetContentByName("audio");
4527 const ContentInfo* vc = answer->GetContentByName("video");
4528 ASSERT_TRUE(ac != nullptr);
4529 ASSERT_TRUE(vc != nullptr);
4530 EXPECT_FALSE(ac->rejected); // the offer is accepted
4531 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004532 const AudioContentDescription* acd = ac->media_description()->as_audio();
4533 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004534 EXPECT_EQ(GetParam(), acd->protocol());
4535 EXPECT_EQ(GetParam(), vcd->protocol());
4536}
4537
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004538INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4539 MediaProtocolTest,
4540 ::testing::ValuesIn(kMediaProtocols));
4541INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4542 MediaProtocolTest,
4543 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004544
4545TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4546 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004547 UniqueRandomIdGenerator ssrc_generator;
4548 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004549 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4550 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4551
4552 // The merged list of codecs should contain any send codecs that are also
4553 // nominally in the recieve codecs list. Payload types should be picked from
4554 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4555 // (set to 1). This equals what happens when the send codecs are used in an
4556 // offer and the receive codecs are used in the following answer.
4557 const std::vector<AudioCodec> sendrecv_codecs =
4558 MAKE_VECTOR(kAudioCodecsAnswer);
4559 const std::vector<AudioCodec> no_codecs;
4560
4561 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4562 << "Please don't change shared test data!";
4563 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4564 << "Please don't change shared test data!";
4565 // Alter iLBC send codec to have zero channels, to test that that is handled
4566 // properly.
4567 send_codecs[1].channels = 0;
4568
4569 // Alther iLBC receive codec to be lowercase, to test that case conversions
4570 // are handled properly.
4571 recv_codecs[2].name = "ilbc";
4572
4573 // Test proper merge
4574 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004575 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4576 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4577 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004578
4579 // Test empty send codecs list
4580 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004581 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4582 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4583 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004584
4585 // Test empty recv codecs list
4586 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004587 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4588 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4589 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004590
4591 // Test all empty codec lists
4592 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004593 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4594 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4595 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004596}
4597
4598namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004599// Compare the two vectors of codecs ignoring the payload type.
4600template <class Codec>
4601bool CodecsMatch(const std::vector<Codec>& codecs1,
4602 const std::vector<Codec>& codecs2) {
4603 if (codecs1.size() != codecs2.size()) {
4604 return false;
4605 }
4606
4607 for (size_t i = 0; i < codecs1.size(); ++i) {
4608 if (!codecs1[i].Matches(codecs2[i])) {
4609 return false;
4610 }
4611 }
4612 return true;
4613}
4614
Steve Anton4e70a722017-11-28 14:57:10 -08004615void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004616 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004617 UniqueRandomIdGenerator ssrc_generator;
4618 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004619 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4620 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4621 const std::vector<AudioCodec> sendrecv_codecs =
4622 MAKE_VECTOR(kAudioCodecsAnswer);
4623 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004624
4625 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004626 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4627 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004628
Steve Anton4e70a722017-11-28 14:57:10 -08004629 if (direction == RtpTransceiverDirection::kSendRecv ||
4630 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004631 AttachSenderToMediaDescriptionOptions(
4632 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004633 }
ossu075af922016-06-14 03:29:38 -07004634
Steve Anton6fe1fba2018-12-11 10:15:23 -08004635 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004636 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004637 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004638
4639 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004640 // that the codecs put in are right. This happens when we neither want to
4641 // send nor receive audio. The checks are still in place if at some point
4642 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004643 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004644 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004645 // sendrecv and inactive should both present lists as if the channel was
4646 // to be used for sending and receiving. Inactive essentially means it
4647 // might eventually be used anything, but we don't know more at this
4648 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004649 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004650 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004651 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004652 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004653 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004654 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004655 }
4656 }
4657}
4658
4659static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004660 AudioCodec(0, "codec0", 16000, -1, 1),
4661 AudioCodec(1, "codec1", 8000, 13300, 1),
4662 AudioCodec(2, "codec2", 8000, 64000, 1),
4663 AudioCodec(3, "codec3", 8000, 64000, 1),
4664 AudioCodec(4, "codec4", 8000, 0, 2),
4665 AudioCodec(5, "codec5", 32000, 0, 1),
4666 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004667
zhihuang1c378ed2017-08-17 14:10:50 -07004668/* The codecs groups below are chosen as per the matrix below. The objective
4669 * is to have different sets of codecs in the inputs, to get unique sets of
4670 * codecs after negotiation, depending on offer and answer communication
4671 * directions. One-way directions in the offer should either result in the
4672 * opposite direction in the answer, or an inactive answer. Regardless, the
4673 * choice of codecs should be as if the answer contained the opposite
4674 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004675 *
4676 * | Offer | Answer | Result
4677 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4678 * 0 | x - - | - x - | x - - - -
4679 * 1 | x x x | - x - | x - - x -
4680 * 2 | - x - | x - - | - x - - -
4681 * 3 | x x x | x - - | - x x - -
4682 * 4 | - x - | x x x | - x - - -
4683 * 5 | x - - | x x x | x - - - -
4684 * 6 | x x x | x x x | x x x x x
4685 */
4686// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004687static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4688static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004689// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4690// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004691static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4692static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004693// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004694static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4695static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4696static const int kResultSendrecv_SendCodecs[] = {3, 6};
4697static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4698static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004699
4700template <typename T, int IDXS>
4701std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4702 std::vector<T> out;
4703 out.reserve(IDXS);
4704 for (int idx : indices)
4705 out.push_back(array[idx]);
4706
4707 return out;
4708}
4709
Steve Anton4e70a722017-11-28 14:57:10 -08004710void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4711 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004712 bool add_legacy_stream) {
4713 TransportDescriptionFactory offer_tdf;
4714 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004715 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4716 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4717 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004718 offer_factory.set_audio_codecs(
4719 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4720 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4721 answer_factory.set_audio_codecs(
4722 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4723 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4724
ossu075af922016-06-14 03:29:38 -07004725 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004726 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4727 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004728
Steve Anton4e70a722017-11-28 14:57:10 -08004729 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004730 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4731 kAudioTrack1, {kMediaStream1}, 1,
4732 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004733 }
4734
Steve Anton6fe1fba2018-12-11 10:15:23 -08004735 std::unique_ptr<SessionDescription> offer =
4736 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004737 ASSERT_TRUE(offer.get() != NULL);
4738
4739 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004740 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4741 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004742
Steve Anton4e70a722017-11-28 14:57:10 -08004743 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004744 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4745 kAudioTrack1, {kMediaStream1}, 1,
4746 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004747 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004748 std::unique_ptr<SessionDescription> answer =
4749 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004750 const ContentInfo* ac = answer->GetContentByName("audio");
4751
zhihuang1c378ed2017-08-17 14:10:50 -07004752 // If the factory didn't add any audio content to the answer, we cannot
4753 // check that the codecs put in are right. This happens when we neither want
4754 // to send nor receive audio. The checks are still in place if at some point
4755 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004756 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004757 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4758 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004759
ossu075af922016-06-14 03:29:38 -07004760 std::vector<AudioCodec> target_codecs;
4761 // For offers with sendrecv or inactive, we should never reply with more
4762 // codecs than offered, with these codec sets.
4763 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004764 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004765 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4766 kResultSendrecv_SendrecvCodecs);
4767 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004768 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004769 target_codecs =
4770 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004771 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004772 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004773 target_codecs =
4774 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004775 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004776 case RtpTransceiverDirection::kSendRecv:
4777 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004778 target_codecs =
4779 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004780 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004781 target_codecs =
4782 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004783 } else {
4784 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4785 kResultSendrecv_SendrecvCodecs);
4786 }
4787 break;
Markus Handell45c104b2020-03-11 10:51:13 +01004788 default:
4789 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004790 }
4791
zhihuang1c378ed2017-08-17 14:10:50 -07004792 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004793 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004794 bool first = true;
4795 os << "{";
4796 for (const auto& c : codecs) {
4797 os << (first ? " " : ", ") << c.id;
4798 first = false;
4799 }
4800 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004801 return os.Release();
ossu075af922016-06-14 03:29:38 -07004802 };
4803
4804 EXPECT_TRUE(acd->codecs() == target_codecs)
4805 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004806 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4807 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004808 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004809 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4810 << "; got: "
4811 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004812 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004813 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004814 << "Only inactive offers are allowed to not generate any audio "
4815 "content";
ossu075af922016-06-14 03:29:38 -07004816 }
4817}
brandtr03d5fb12016-11-22 03:37:59 -08004818
4819} // namespace
ossu075af922016-06-14 03:29:38 -07004820
4821class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004822 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004823
4824TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004825 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004826}
4827
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004828INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4829 AudioCodecsOfferTest,
4830 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4831 RtpTransceiverDirection::kRecvOnly,
4832 RtpTransceiverDirection::kSendRecv,
4833 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004834
4835class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004836 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4837 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004838 bool>> {};
ossu075af922016-06-14 03:29:38 -07004839
4840TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004841 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4842 ::testing::get<1>(GetParam()),
4843 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004844}
4845
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004846INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004847 MediaSessionDescriptionFactoryTest,
4848 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004849 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4850 RtpTransceiverDirection::kRecvOnly,
4851 RtpTransceiverDirection::kSendRecv,
4852 RtpTransceiverDirection::kInactive),
4853 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4854 RtpTransceiverDirection::kRecvOnly,
4855 RtpTransceiverDirection::kSendRecv,
4856 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004857 ::testing::Bool()));