blob: 6dc6d7602116e2759608222420cd8b7d20be60ca [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
Harald Alvestrandc24a2182022-02-23 13:44:59 +000013#include <stddef.h>
14
Amit Hilbuch77938e62018-12-21 09:23:38 -080015#include <algorithm>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000016#include <cstdint>
17#include <map>
kwiberg31022942016-03-11 14:18:21 -080018#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <string>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000020#include <tuple>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000021#include <vector>
22
Steve Anton64b626b2019-01-28 17:25:26 -080023#include "absl/algorithm/container.h"
Mirko Bonadei57cabed2020-04-01 12:03:11 +020024#include "absl/strings/match.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000025#include "absl/strings/string_view.h"
26#include "api/candidate.h"
27#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "media/base/codec.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000029#include "media/base/media_constants.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020031#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "p2p/base/p2p_constants.h"
33#include "p2p/base/transport_description.h"
34#include "p2p/base/transport_info.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000035#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080036#include "pc/rtp_media_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000037#include "rtc_base/arraysize.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080039#include "rtc_base/fake_ssl_identity.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000040#include "rtc_base/rtc_certificate.h"
41#include "rtc_base/ssl_identity.h"
42#include "rtc_base/ssl_stream_adapter.h"
43#include "rtc_base/string_encode.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020044#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080045#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080046#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000047#include "test/gtest.h"
Jonas Orelanded99dae2022-03-09 09:28:10 +010048#include "test/scoped_key_value_config.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049
Harald Alvestrand0d018412021-11-04 13:52:31 +000050#define ASSERT_CRYPTO(cd, s, cs) \
51 ASSERT_EQ(s, cd->cryptos().size()); \
52 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
53
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054typedef std::vector<cricket::Candidate> Candidates;
55
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080056using cricket::AudioCodec;
57using cricket::AudioContentDescription;
58using cricket::ContentInfo;
Harald Alvestrand0d018412021-11-04 13:52:31 +000059using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080060using cricket::GetFirstAudioContent;
61using cricket::GetFirstAudioContentDescription;
62using cricket::GetFirstDataContent;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080063using cricket::GetFirstVideoContent;
64using cricket::GetFirstVideoContentDescription;
65using cricket::kAutoBandwidth;
66using cricket::MEDIA_TYPE_AUDIO;
67using cricket::MEDIA_TYPE_DATA;
68using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070070using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080071using cricket::MediaProtocolType;
72using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073using cricket::MediaSessionOptions;
74using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080075using cricket::RidDescription;
76using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020077using cricket::SctpDataContentDescription;
Harald Alvestrand0d018412021-11-04 13:52:31 +000078using cricket::SEC_DISABLED;
79using cricket::SEC_ENABLED;
80using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080082using cricket::SimulcastDescription;
83using cricket::SimulcastLayer;
84using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085using cricket::SsrcGroup;
86using cricket::StreamParams;
87using cricket::StreamParamsVec;
88using cricket::TransportDescription;
89using cricket::TransportDescriptionFactory;
90using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080092using cricket::VideoContentDescription;
Mirko Bonadei7750d802021-07-26 17:27:42 +020093using rtc::kCsAeadAes128Gcm;
94using rtc::kCsAeadAes256Gcm;
95using rtc::kCsAesCm128HmacSha1_32;
96using rtc::kCsAesCm128HmacSha1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080097using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020098using ::testing::Contains;
99using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +0100100using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200101using ::testing::ElementsAreArray;
102using ::testing::Eq;
103using ::testing::Field;
104using ::testing::IsEmpty;
105using ::testing::IsFalse;
106using ::testing::Ne;
107using ::testing::Not;
108using ::testing::Pointwise;
109using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700110using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800111using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
113static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700114 AudioCodec(103, "ISAC", 16000, -1, 1),
115 AudioCodec(102, "iLBC", 8000, 13300, 1),
116 AudioCodec(0, "PCMU", 8000, 64000, 1),
117 AudioCodec(8, "PCMA", 8000, 64000, 1),
118 AudioCodec(117, "red", 8000, 0, 1),
119 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120
121static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200122 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700123 AudioCodec(0, "PCMU", 8000, 64000, 1),
124 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125};
126
127static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700128 AudioCodec(102, "iLBC", 8000, 13300, 1),
129 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130};
131
perkj26752742016-10-24 01:21:16 -0700132static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
133 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
zhihuang1c378ed2017-08-17 14:10:50 -0700135static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
136 VideoCodec(96, "H264-SVC")};
137
perkj26752742016-10-24 01:21:16 -0700138static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
139 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140
perkj26752742016-10-24 01:21:16 -0700141static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
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),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200152 RtpExtension("http://google.com/testing/audio_something", 11, true),
jbauch5869f502017-06-29 12:31:36 -0700153};
154
isheriff6f8d6862016-05-26 11:24:55 -0700155static const RtpExtension kAudioRtpExtension2[] = {
156 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
157 RtpExtension("http://google.com/testing/audio_something_else", 8),
158 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159};
160
isheriff6f8d6862016-05-26 11:24:55 -0700161static const RtpExtension kAudioRtpExtension3[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700164};
165
jbauch5869f502017-06-29 12:31:36 -0700166static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
167 RtpExtension("http://google.com/testing/audio_something", 2),
168 // Use RTP extension that supports encryption.
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
170};
171
172static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
173 RtpExtension("http://google.com/testing/audio_something", 2),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200175 RtpExtension("http://google.com/testing/audio_something", 14, true),
176 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
177};
178
179static const RtpExtension kVideoRtpExtension3ForEncryptionOffer[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
182 RtpExtension("http://google.com/testing/video_something", 12, true),
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
jbauch5869f502017-06-29 12:31:36 -0700184};
185
isheriff6f8d6862016-05-26 11:24:55 -0700186static const RtpExtension kAudioRtpExtensionAnswer[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188};
189
jbauch5869f502017-06-29 12:31:36 -0700190static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
192};
193
isheriff6f8d6862016-05-26 11:24:55 -0700194static const RtpExtension kVideoRtpExtension1[] = {
195 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
196 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197};
198
jbauch5869f502017-06-29 12:31:36 -0700199static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
200 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
201 RtpExtension("http://google.com/testing/video_something", 13),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200202 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
203 RtpExtension("http://google.com/testing/video_something", 7, true),
jbauch5869f502017-06-29 12:31:36 -0700204};
205
isheriff6f8d6862016-05-26 11:24:55 -0700206static const RtpExtension kVideoRtpExtension2[] = {
207 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
208 RtpExtension("http://google.com/testing/video_something_else", 14),
209 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210};
211
isheriff6f8d6862016-05-26 11:24:55 -0700212static const RtpExtension kVideoRtpExtension3[] = {
213 RtpExtension("http://google.com/testing/video_something", 4),
214 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700215};
216
jbauch5869f502017-06-29 12:31:36 -0700217static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
218 RtpExtension("http://google.com/testing/video_something", 4),
219 // Use RTP extension that supports encryption.
220 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
221};
222
isheriff6f8d6862016-05-26 11:24:55 -0700223static const RtpExtension kVideoRtpExtensionAnswer[] = {
224 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225};
226
jbauch5869f502017-06-29 12:31:36 -0700227static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200228 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
jbauch5869f502017-06-29 12:31:36 -0700229};
230
Johannes Kronce8e8672019-02-22 13:06:44 +0100231static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
232 RtpExtension("http://www.ietf.org/id/"
233 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
234 1),
235};
236
237static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
238 RtpExtension("http://www.ietf.org/id/"
239 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
240 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100241 RtpExtension(
242 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
243 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100244};
245
246static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100247 RtpExtension(
248 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
249 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100250};
251
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100252static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
253 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
254 "generic-frame-descriptor-00",
255 3),
256};
257
Peter Boström0c4e06b2015-10-07 12:23:21 +0200258static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
259static const uint32_t kSimSsrc[] = {10, 20, 30};
260static const uint32_t kFec1Ssrc[] = {10, 11};
261static const uint32_t kFec2Ssrc[] = {20, 21};
262static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263
264static const char kMediaStream1[] = "stream_1";
265static const char kMediaStream2[] = "stream_2";
266static const char kVideoTrack1[] = "video_1";
267static const char kVideoTrack2[] = "video_2";
268static const char kAudioTrack1[] = "audio_1";
269static const char kAudioTrack2[] = "audio_2";
270static const char kAudioTrack3[] = "audio_3";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271
zhihuangcf5b37c2016-05-05 11:44:35 -0700272static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
273 "RTP/SAVPF"};
274static const char* kMediaProtocolsDtls[] = {
275 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
276 "UDP/TLS/RTP/SAVP"};
277
Harald Alvestrand0d018412021-11-04 13:52:31 +0000278// SRTP cipher name negotiated by the tests. This must be updated if the
279// default changes.
280static const char* kDefaultSrtpCryptoSuite = kCsAesCm128HmacSha1_80;
281static const char* kDefaultSrtpCryptoSuiteGcm = kCsAeadAes256Gcm;
282
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800283// These constants are used to make the code using "AddMediaDescriptionOptions"
284// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700285static constexpr bool kStopped = true;
286static constexpr bool kActive = false;
287
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000288static bool IsMediaContentOfType(const ContentInfo* content,
289 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800290 RTC_DCHECK(content);
291 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000292}
293
Steve Anton4e70a722017-11-28 14:57:10 -0800294static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800295 RTC_DCHECK(content);
296 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000297}
298
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000299static void AddRtxCodec(const VideoCodec& rtx_codec,
300 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800301 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000302 codecs->push_back(rtx_codec);
303}
304
305template <class T>
306static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
307 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100308 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000309 for (const auto& codec : codecs) {
310 codec_names.push_back(codec.name);
311 }
312 return codec_names;
313}
314
zhihuang1c378ed2017-08-17 14:10:50 -0700315// This is used for test only. MIDs are not the identification of the
316// MediaDescriptionOptions since some end points may not support MID and the SDP
317// may not contain 'mid'.
318std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
319 const std::string& mid,
320 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800321 return absl::c_find_if(
322 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700323 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
324}
325
326std::vector<MediaDescriptionOptions>::const_iterator
327FindFirstMediaDescriptionByMid(const std::string& mid,
328 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800329 return absl::c_find_if(
330 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700331 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700332}
333
Artem Titov880fa812021-07-30 22:30:23 +0200334// Add a media section to the `session_options`.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800335static void AddMediaDescriptionOptions(MediaType type,
336 const std::string& mid,
337 RtpTransceiverDirection direction,
338 bool stopped,
339 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800340 opts->media_description_options.push_back(
341 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700342}
343
Steve Anton4e70a722017-11-28 14:57:10 -0800344static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700345 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800346 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
347 opts);
348 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
349 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700350}
351
Florent Castelli516e2842021-04-19 15:29:50 +0200352static void AddDataSection(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700353 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800354 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700355}
356
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800357static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700358 const std::string& mid,
359 MediaType type,
360 const std::string& track_id,
361 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800362 const std::vector<RidDescription>& rids,
363 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700364 int num_sim_layer,
365 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700366 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
367 switch (type) {
368 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700369 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700370 break;
371 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800372 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
373 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700374 break;
zhihuang1c378ed2017-08-17 14:10:50 -0700375 default:
Artem Titovd3251962021-11-15 16:57:07 +0100376 RTC_DCHECK_NOTREACHED();
zhihuang1c378ed2017-08-17 14:10:50 -0700377 }
378}
379
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800380static void AttachSenderToMediaDescriptionOptions(
381 const std::string& mid,
382 MediaType type,
383 const std::string& track_id,
384 const std::vector<std::string>& stream_ids,
385 int num_sim_layer,
386 MediaSessionOptions* session_options) {
387 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
388 SimulcastLayerList(), num_sim_layer,
389 session_options);
390}
391
zhihuang1c378ed2017-08-17 14:10:50 -0700392static void DetachSenderFromMediaSection(const std::string& mid,
393 const std::string& track_id,
394 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700395 std::vector<cricket::SenderOptions>& sender_options_list =
396 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
397 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800398 absl::c_find_if(sender_options_list,
399 [track_id](const cricket::SenderOptions& sender_options) {
400 return sender_options.track_id == track_id;
401 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700402 RTC_DCHECK(sender_it != sender_options_list.end());
403 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700404}
405
406// Helper function used to create a default MediaSessionOptions for Plan B SDP.
407// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
408static MediaSessionOptions CreatePlanBMediaSessionOptions() {
409 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800410 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
411 RtpTransceiverDirection::kRecvOnly, kActive,
412 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700413 return session_options;
414}
415
Harald Alvestrand0d018412021-11-04 13:52:31 +0000416// prefers GCM SDES crypto suites by removing non-GCM defaults.
417void PreferGcmCryptoParameters(CryptoParamsVec* cryptos) {
418 cryptos->erase(
419 std::remove_if(cryptos->begin(), cryptos->end(),
420 [](const cricket::CryptoParams& crypto) {
421 return crypto.cipher_suite != kCsAeadAes256Gcm &&
422 crypto.cipher_suite != kCsAeadAes128Gcm;
423 }),
424 cryptos->end());
425}
426
zhihuang1c378ed2017-08-17 14:10:50 -0700427// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
428// was designed for Plan B SDP, where only one audio "m=" section and one video
429// "m=" section could be generated, and ordering couldn't be controlled. Many of
430// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200431class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800433 MediaSessionDescriptionFactoryTest()
Jonas Orelanded99dae2022-03-09 09:28:10 +0100434 : tdf1_(field_trials),
435 tdf2_(field_trials),
436 f1_(&tdf1_, &ssrc_generator1),
437 f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700438 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
439 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200440 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
441 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -0700442 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
443 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200444 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
445 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000446 tdf1_.set_certificate(rtc::RTCCertificate::Create(
447 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
448 tdf2_.set_certificate(rtc::RTCCertificate::Create(
449 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 }
451
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000452 // Create a video StreamParamsVec object with:
453 // - one video stream with 3 simulcast streams and FEC,
454 StreamParamsVec CreateComplexVideoStreamParamsVec() {
455 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
456 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
457 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
458 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
459
460 std::vector<SsrcGroup> ssrc_groups;
461 ssrc_groups.push_back(sim_group);
462 ssrc_groups.push_back(fec_group1);
463 ssrc_groups.push_back(fec_group2);
464 ssrc_groups.push_back(fec_group3);
465
466 StreamParams simulcast_params;
467 simulcast_params.id = kVideoTrack1;
468 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
469 simulcast_params.ssrc_groups = ssrc_groups;
470 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800471 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000472
473 StreamParamsVec video_streams;
474 video_streams.push_back(simulcast_params);
475
476 return video_streams;
477 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000478
Harald Alvestrand0d018412021-11-04 13:52:31 +0000479 bool CompareCryptoParams(const CryptoParamsVec& c1,
480 const CryptoParamsVec& c2) {
481 if (c1.size() != c2.size())
482 return false;
483 for (size_t i = 0; i < c1.size(); ++i)
484 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
485 c1[i].key_params != c2[i].key_params ||
486 c1[i].session_params != c2[i].session_params)
487 return false;
488 return true;
489 }
490
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700491 // Returns true if the transport info contains "renomination" as an
492 // ICE option.
493 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800494 return absl::c_linear_search(transport_info->description.transport_options,
495 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700496 }
497
zhihuang1c378ed2017-08-17 14:10:50 -0700498 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700499 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 bool has_current_desc) {
501 const std::string current_audio_ufrag = "current_audio_ufrag";
502 const std::string current_audio_pwd = "current_audio_pwd";
503 const std::string current_video_ufrag = "current_video_ufrag";
504 const std::string current_video_pwd = "current_video_pwd";
505 const std::string current_data_ufrag = "current_data_ufrag";
506 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800507 std::unique_ptr<SessionDescription> current_desc;
508 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200510 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800511 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200512 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800513 TransportDescription(current_audio_ufrag, current_audio_pwd)));
514 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200515 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800516 TransportDescription(current_video_ufrag, current_video_pwd)));
517 current_desc->AddTransportInfo(TransportInfo(
518 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 }
520 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800521 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522 } else {
kwiberg31022942016-03-11 14:18:21 -0800523 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800524 offer = f1_.CreateOffer(options, NULL);
525 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 }
527 ASSERT_TRUE(desc.get() != NULL);
528 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000529 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 EXPECT_TRUE(ti_audio != NULL);
531 if (has_current_desc) {
532 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
533 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
534 } else {
535 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
536 ti_audio->description.ice_ufrag.size());
537 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
538 ti_audio->description.ice_pwd.size());
539 }
zhihuang1c378ed2017-08-17 14:10:50 -0700540 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700541 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700542 EXPECT_EQ(
543 media_desc_options_it->transport_options.enable_ice_renomination,
544 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 } else {
546 EXPECT_TRUE(ti_audio == NULL);
547 }
548 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000549 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700551 auto media_desc_options_it =
552 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 if (options.bundle_enabled) {
554 EXPECT_EQ(ti_audio->description.ice_ufrag,
555 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200556 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 } else {
558 if (has_current_desc) {
559 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
560 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
561 } else {
562 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
563 ti_video->description.ice_ufrag.size());
564 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
565 ti_video->description.ice_pwd.size());
566 }
567 }
zhihuang1c378ed2017-08-17 14:10:50 -0700568 EXPECT_EQ(
569 media_desc_options_it->transport_options.enable_ice_renomination,
570 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 } else {
572 EXPECT_TRUE(ti_video == NULL);
573 }
574 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
575 if (options.has_data()) {
576 EXPECT_TRUE(ti_data != NULL);
577 if (options.bundle_enabled) {
578 EXPECT_EQ(ti_audio->description.ice_ufrag,
579 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200580 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 } else {
582 if (has_current_desc) {
583 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
584 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
585 } else {
586 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
587 ti_data->description.ice_ufrag.size());
588 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
589 ti_data->description.ice_pwd.size());
590 }
591 }
zhihuang1c378ed2017-08-17 14:10:50 -0700592 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700593 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700594 EXPECT_EQ(
595 media_desc_options_it->transport_options.enable_ice_renomination,
596 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700597
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700599 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 }
601 }
602
Harald Alvestrand0d018412021-11-04 13:52:31 +0000603 void TestCryptoWithBundle(bool offer) {
604 f1_.set_secure(SEC_ENABLED);
605 MediaSessionOptions options;
606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
607 std::unique_ptr<SessionDescription> ref_desc;
608 std::unique_ptr<SessionDescription> desc;
609 if (offer) {
610 options.bundle_enabled = false;
611 ref_desc = f1_.CreateOffer(options, NULL);
612 options.bundle_enabled = true;
613 desc = f1_.CreateOffer(options, ref_desc.get());
614 } else {
615 options.bundle_enabled = true;
616 ref_desc = f1_.CreateOffer(options, NULL);
617 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
618 }
619 ASSERT_TRUE(desc);
620 const cricket::MediaContentDescription* audio_media_desc =
621 desc->GetContentDescriptionByName("audio");
622 ASSERT_TRUE(audio_media_desc);
623 const cricket::MediaContentDescription* video_media_desc =
624 desc->GetContentDescriptionByName("video");
625 ASSERT_TRUE(video_media_desc);
626 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
627 video_media_desc->cryptos()));
628 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
629 EXPECT_EQ(kDefaultSrtpCryptoSuite,
630 audio_media_desc->cryptos()[0].cipher_suite);
631
632 // Verify the selected crypto is one from the reference audio
633 // media content.
634 const cricket::MediaContentDescription* ref_audio_media_desc =
635 ref_desc->GetContentDescriptionByName("audio");
636 bool found = false;
637 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
638 if (ref_audio_media_desc->cryptos()[i].Matches(
639 audio_media_desc->cryptos()[0])) {
640 found = true;
641 break;
642 }
643 }
644 EXPECT_TRUE(found);
645 }
646
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 // This test that the audio and video media direction is set to
Artem Titov880fa812021-07-30 22:30:23 +0200648 // `expected_direction_in_answer` in an answer if the offer direction is set
649 // to `direction_in_offer` and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800651 RtpTransceiverDirection direction_in_offer,
652 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700653 MediaSessionOptions offer_opts;
654 AddAudioVideoSections(direction_in_offer, &offer_opts);
655
Steve Anton6fe1fba2018-12-11 10:15:23 -0800656 std::unique_ptr<SessionDescription> offer =
657 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700659 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700661 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663
zhihuang1c378ed2017-08-17 14:10:50 -0700664 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800665 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800666 std::unique_ptr<SessionDescription> answer =
667 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 const AudioContentDescription* acd_answer =
669 GetFirstAudioContentDescription(answer.get());
670 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
671 const VideoContentDescription* vcd_answer =
672 GetFirstVideoContentDescription(answer.get());
673 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
674 }
675
676 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800677 RTC_DCHECK(content);
678 RTC_CHECK(content->media_description());
679 const cricket::AudioContentDescription* audio_desc =
680 content->media_description()->as_audio();
681 RTC_CHECK(audio_desc);
682 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
683 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800685 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 }
687 return true;
688 }
689
Harald Alvestrand0d018412021-11-04 13:52:31 +0000690 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
691 MediaSessionOptions offer_opts;
692 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
693 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
694
695 MediaSessionOptions answer_opts;
696 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
697 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
698
699 f1_.set_secure(SEC_ENABLED);
700 f2_.set_secure(SEC_ENABLED);
701 std::unique_ptr<SessionDescription> offer =
702 f1_.CreateOffer(offer_opts, NULL);
703 ASSERT_TRUE(offer.get() != NULL);
704 if (gcm_offer && gcm_answer) {
705 for (cricket::ContentInfo& content : offer->contents()) {
706 auto cryptos = content.media_description()->cryptos();
707 PreferGcmCryptoParameters(&cryptos);
708 content.media_description()->set_cryptos(cryptos);
709 }
710 }
711 std::unique_ptr<SessionDescription> answer =
712 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
713 const ContentInfo* ac = answer->GetContentByName("audio");
714 const ContentInfo* vc = answer->GetContentByName("video");
715 ASSERT_TRUE(ac != NULL);
716 ASSERT_TRUE(vc != NULL);
717 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
718 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
719 const AudioContentDescription* acd = ac->media_description()->as_audio();
720 const VideoContentDescription* vcd = vc->media_description()->as_video();
721 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
722 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
723 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
724 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
725 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
726 if (gcm_offer && gcm_answer) {
727 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
728 } else {
729 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
730 }
731 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
732 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
733 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
734 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
735 if (gcm_offer && gcm_answer) {
736 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
737 } else {
738 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
739 }
740 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
741 }
742
Johannes Kronce8e8672019-02-22 13:06:44 +0100743 void TestTransportSequenceNumberNegotiation(
744 const cricket::RtpHeaderExtensions& local,
745 const cricket::RtpHeaderExtensions& offered,
746 const cricket::RtpHeaderExtensions& expectedAnswer) {
747 MediaSessionOptions opts;
748 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +0200749 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100750 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
751 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +0200752 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100753 std::unique_ptr<SessionDescription> answer =
754 f2_.CreateAnswer(offer.get(), opts, NULL);
755
756 EXPECT_EQ(
757 expectedAnswer,
758 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
759 EXPECT_EQ(
760 expectedAnswer,
761 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
762 }
763
Markus Handell755c65d2020-06-24 01:06:10 +0200764 std::vector<webrtc::RtpHeaderExtensionCapability>
765 HeaderExtensionCapabilitiesFromRtpExtensions(
766 cricket::RtpHeaderExtensions extensions) {
767 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
768 for (const auto& extension : extensions) {
769 webrtc::RtpHeaderExtensionCapability capability(
770 extension.uri, extension.id,
771 webrtc::RtpTransceiverDirection::kSendRecv);
772 capabilities.push_back(capability);
773 }
774 return capabilities;
775 }
776
777 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
778 cricket::RtpHeaderExtensions video_exts,
779 MediaSessionOptions* opts) {
780 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
781 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
782 for (auto& entry : opts->media_description_options) {
783 switch (entry.type) {
784 case MEDIA_TYPE_AUDIO:
785 entry.header_extensions = audio_caps;
786 break;
787 case MEDIA_TYPE_VIDEO:
788 entry.header_extensions = video_caps;
789 break;
790 default:
791 break;
792 }
793 }
794 }
795
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 protected:
Jonas Orelanded99dae2022-03-09 09:28:10 +0100797 webrtc::test::ScopedKeyValueConfig field_trials;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800798 UniqueRandomIdGenerator ssrc_generator1;
799 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 TransportDescriptionFactory tdf1_;
801 TransportDescriptionFactory tdf2_;
Jonas Orelanded99dae2022-03-09 09:28:10 +0100802 MediaSessionDescriptionFactory f1_;
803 MediaSessionDescriptionFactory f2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804};
805
806// Create a typical audio offer, and ensure it matches what we expect.
807TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000808 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800809 std::unique_ptr<SessionDescription> offer =
810 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 ASSERT_TRUE(offer.get() != NULL);
812 const ContentInfo* ac = offer->GetContentByName("audio");
813 const ContentInfo* vc = offer->GetContentByName("video");
814 ASSERT_TRUE(ac != NULL);
815 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800816 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800817 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700819 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700820 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
822 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000823 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
824 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825}
826
827// Create a typical video offer, and ensure it matches what we expect.
828TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
829 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800830 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000831 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800832 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 ASSERT_TRUE(offer.get() != NULL);
834 const ContentInfo* ac = offer->GetContentByName("audio");
835 const ContentInfo* vc = offer->GetContentByName("video");
836 ASSERT_TRUE(ac != NULL);
837 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800838 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
839 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800840 const AudioContentDescription* acd = ac->media_description()->as_audio();
841 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700843 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700844 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
846 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000847 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
848 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200850 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700851 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
853 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000854 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
855 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856}
857
858// Test creating an offer with bundle where the Codecs have the same dynamic
859// RTP playlod type. The test verifies that the offer don't contain the
860// duplicate RTP payload types.
861TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200862 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700863 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865
866 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800867 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800869 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 const VideoContentDescription* vcd =
871 GetFirstVideoContentDescription(offer.get());
872 const AudioContentDescription* acd =
873 GetFirstAudioContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874 ASSERT_TRUE(NULL != vcd);
875 ASSERT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
878 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879}
880
zhihuang1c378ed2017-08-17 14:10:50 -0700881// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882// after an audio only session has been negotiated.
883TEST_F(MediaSessionDescriptionFactoryTest,
884 TestCreateUpdatedVideoOfferWithBundle) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000885 f1_.set_secure(SEC_ENABLED);
886 f2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800888 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
889 RtpTransceiverDirection::kRecvOnly, kActive,
890 &opts);
891 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
892 RtpTransceiverDirection::kInactive, kStopped,
893 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800895 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
896 std::unique_ptr<SessionDescription> answer =
897 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000898
899 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800900 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800902 std::unique_ptr<SessionDescription> updated_offer(
903 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904
905 const AudioContentDescription* acd =
906 GetFirstAudioContentDescription(updated_offer.get());
907 const VideoContentDescription* vcd =
908 GetFirstVideoContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909 EXPECT_TRUE(NULL != vcd);
910 EXPECT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911
Harald Alvestrand0d018412021-11-04 13:52:31 +0000912 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
913 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
914 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
915 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916}
917
wu@webrtc.org78187522013-10-07 23:32:02 +0000918// Create an SCTP data offer with bundle without error.
919TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
920 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000921 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200922 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000923 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800924 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000925 EXPECT_TRUE(offer.get() != NULL);
926 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000927 auto dcd = GetFirstSctpDataContentDescription(offer.get());
928 ASSERT_TRUE(dcd);
929 // Since this transport is insecure, the protocol should be "SCTP".
930 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
931}
932
933// Create an SCTP data offer with bundle without error.
934TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
935 MediaSessionOptions opts;
936 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200937 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000938 f1_.set_secure(SEC_ENABLED);
939 tdf1_.set_secure(SEC_ENABLED);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
941 EXPECT_TRUE(offer.get() != NULL);
942 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
943 auto dcd = GetFirstSctpDataContentDescription(offer.get());
944 ASSERT_TRUE(dcd);
945 // The protocol should now be "UDP/DTLS/SCTP"
946 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000947}
948
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000949// Test creating an sctp data channel from an already generated offer.
950TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
951 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000952 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200953 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000954 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800955 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000956 ASSERT_TRUE(offer1.get() != NULL);
957 const ContentInfo* data = offer1->GetContentByName("data");
958 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800959 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000960
kwiberg31022942016-03-11 14:18:21 -0800961 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000962 f1_.CreateOffer(opts, offer1.get()));
963 data = offer2->GetContentByName("data");
964 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800965 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000966}
967
Steve Anton2bed3972019-01-04 17:04:30 -0800968// Test that if BUNDLE is enabled and all media sections are rejected then the
969// BUNDLE group is not present in the re-offer.
970TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
971 MediaSessionOptions opts;
972 opts.bundle_enabled = true;
973 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
974 RtpTransceiverDirection::kSendRecv, kActive,
975 &opts);
976 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
977
978 opts.media_description_options[0].stopped = true;
979 std::unique_ptr<SessionDescription> reoffer =
980 f1_.CreateOffer(opts, offer.get());
981
982 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
983}
984
985// Test that if BUNDLE is enabled and the remote re-offer does not include a
986// BUNDLE group since all media sections are rejected, then the re-answer also
987// does not include a BUNDLE group.
988TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
989 MediaSessionOptions opts;
990 opts.bundle_enabled = true;
991 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
992 RtpTransceiverDirection::kSendRecv, kActive,
993 &opts);
994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
995 std::unique_ptr<SessionDescription> answer =
996 f2_.CreateAnswer(offer.get(), opts, nullptr);
997
998 opts.media_description_options[0].stopped = true;
999 std::unique_ptr<SessionDescription> reoffer =
1000 f1_.CreateOffer(opts, offer.get());
1001 std::unique_ptr<SessionDescription> reanswer =
1002 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1003
1004 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1005}
1006
1007// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1008// was rejected then the new offerer-tagged media section is the non-rejected
1009// media section.
1010TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1011 MediaSessionOptions opts;
1012 opts.bundle_enabled = true;
1013 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1014 RtpTransceiverDirection::kSendRecv, kActive,
1015 &opts);
1016 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1017
1018 // Reject the audio m= section and add a video m= section.
1019 opts.media_description_options[0].stopped = true;
1020 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1021 RtpTransceiverDirection::kSendRecv, kActive,
1022 &opts);
1023 std::unique_ptr<SessionDescription> reoffer =
1024 f1_.CreateOffer(opts, offer.get());
1025
1026 const cricket::ContentGroup* bundle_group =
1027 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1028 ASSERT_TRUE(bundle_group);
1029 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1030 EXPECT_TRUE(bundle_group->HasContentName("video"));
1031}
1032
1033// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1034// was rejected and a new media section is added, then the re-answer BUNDLE
1035// group will contain only the non-rejected media section.
1036TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1037 MediaSessionOptions opts;
1038 opts.bundle_enabled = true;
1039 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1040 RtpTransceiverDirection::kSendRecv, kActive,
1041 &opts);
1042 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1043 std::unique_ptr<SessionDescription> answer =
1044 f2_.CreateAnswer(offer.get(), opts, nullptr);
1045
1046 // Reject the audio m= section and add a video m= section.
1047 opts.media_description_options[0].stopped = true;
1048 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1049 RtpTransceiverDirection::kSendRecv, kActive,
1050 &opts);
1051 std::unique_ptr<SessionDescription> reoffer =
1052 f1_.CreateOffer(opts, offer.get());
1053 std::unique_ptr<SessionDescription> reanswer =
1054 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1055
1056 const cricket::ContentGroup* bundle_group =
1057 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1058 ASSERT_TRUE(bundle_group);
1059 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1060 EXPECT_TRUE(bundle_group->HasContentName("video"));
1061}
1062
Henrik Boströmf8187e02021-04-26 21:04:26 +02001063TEST_F(MediaSessionDescriptionFactoryTest,
1064 CreateAnswerForOfferWithMultipleBundleGroups) {
1065 // Create an offer with 4 m= sections, initially without BUNDLE groups.
1066 MediaSessionOptions opts;
1067 opts.bundle_enabled = false;
1068 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "1",
1069 RtpTransceiverDirection::kSendRecv, kActive,
1070 &opts);
1071 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "2",
1072 RtpTransceiverDirection::kSendRecv, kActive,
1073 &opts);
1074 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "3",
1075 RtpTransceiverDirection::kSendRecv, kActive,
1076 &opts);
1077 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "4",
1078 RtpTransceiverDirection::kSendRecv, kActive,
1079 &opts);
1080 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1081 ASSERT_TRUE(offer->groups().empty());
1082
1083 // Munge the offer to have two groups. Offers like these cannot be generated
1084 // without munging, but it is valid to receive such offers from remote
1085 // endpoints.
1086 cricket::ContentGroup bundle_group1(cricket::GROUP_TYPE_BUNDLE);
1087 bundle_group1.AddContentName("1");
1088 bundle_group1.AddContentName("2");
1089 cricket::ContentGroup bundle_group2(cricket::GROUP_TYPE_BUNDLE);
1090 bundle_group2.AddContentName("3");
1091 bundle_group2.AddContentName("4");
1092 offer->AddGroup(bundle_group1);
1093 offer->AddGroup(bundle_group2);
1094
1095 // If BUNDLE is enabled, the answer to this offer should accept both BUNDLE
1096 // groups.
1097 opts.bundle_enabled = true;
1098 std::unique_ptr<SessionDescription> answer =
1099 f2_.CreateAnswer(offer.get(), opts, nullptr);
1100
1101 std::vector<const cricket::ContentGroup*> answer_groups =
1102 answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1103 ASSERT_EQ(answer_groups.size(), 2u);
1104 EXPECT_EQ(answer_groups[0]->content_names().size(), 2u);
1105 EXPECT_TRUE(answer_groups[0]->HasContentName("1"));
1106 EXPECT_TRUE(answer_groups[0]->HasContentName("2"));
1107 EXPECT_EQ(answer_groups[1]->content_names().size(), 2u);
1108 EXPECT_TRUE(answer_groups[1]->HasContentName("3"));
1109 EXPECT_TRUE(answer_groups[1]->HasContentName("4"));
1110
1111 // If BUNDLE is disabled, the answer to this offer should reject both BUNDLE
1112 // groups.
1113 opts.bundle_enabled = false;
1114 answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1115
1116 answer_groups = answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1117 // Rejected groups are still listed, but they are empty.
1118 ASSERT_EQ(answer_groups.size(), 2u);
1119 EXPECT_TRUE(answer_groups[0]->content_names().empty());
1120 EXPECT_TRUE(answer_groups[1]->content_names().empty());
1121}
1122
Steve Anton2bed3972019-01-04 17:04:30 -08001123// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1124// and there is still a non-rejected media section that was in the initial
1125// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1126// media section.
1127TEST_F(MediaSessionDescriptionFactoryTest,
1128 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1129 MediaSessionOptions opts;
1130 opts.bundle_enabled = true;
1131 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1132 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1133 std::unique_ptr<SessionDescription> answer =
1134 f2_.CreateAnswer(offer.get(), opts, nullptr);
1135
1136 // Reject the audio m= section.
1137 opts.media_description_options[0].stopped = true;
1138 std::unique_ptr<SessionDescription> reoffer =
1139 f1_.CreateOffer(opts, offer.get());
1140
1141 const TransportDescription* offer_tagged =
1142 offer->GetTransportDescriptionByName("audio");
1143 ASSERT_TRUE(offer_tagged);
1144 const TransportDescription* reoffer_tagged =
1145 reoffer->GetTransportDescriptionByName("video");
1146 ASSERT_TRUE(reoffer_tagged);
1147 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1148 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1149}
1150
1151// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1152// and there is still a non-rejected media section that was in the initial
1153// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1154// media section.
1155TEST_F(MediaSessionDescriptionFactoryTest,
1156 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1157 MediaSessionOptions opts;
1158 opts.bundle_enabled = true;
1159 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1160 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1161 std::unique_ptr<SessionDescription> answer =
1162 f2_.CreateAnswer(offer.get(), opts, nullptr);
1163
1164 // Reject the audio m= section.
1165 opts.media_description_options[0].stopped = true;
1166 std::unique_ptr<SessionDescription> reoffer =
1167 f1_.CreateOffer(opts, offer.get());
1168 std::unique_ptr<SessionDescription> reanswer =
1169 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1170
1171 const TransportDescription* answer_tagged =
1172 answer->GetTransportDescriptionByName("audio");
1173 ASSERT_TRUE(answer_tagged);
1174 const TransportDescription* reanswer_tagged =
1175 reanswer->GetTransportDescriptionByName("video");
1176 ASSERT_TRUE(reanswer_tagged);
1177 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1178 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1179}
1180
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181// Create an audio, video offer without legacy StreamParams.
1182TEST_F(MediaSessionDescriptionFactoryTest,
1183 TestCreateOfferWithoutLegacyStreams) {
1184 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001185 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001186 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001187 ASSERT_TRUE(offer.get() != NULL);
1188 const ContentInfo* ac = offer->GetContentByName("audio");
1189 const ContentInfo* vc = offer->GetContentByName("video");
1190 ASSERT_TRUE(ac != NULL);
1191 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001192 const AudioContentDescription* acd = ac->media_description()->as_audio();
1193 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194
Yves Gerey665174f2018-06-19 15:03:05 +02001195 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1196 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197}
1198
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001199// Creates an audio+video sendonly offer.
1200TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001201 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001202 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001203 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1204 {kMediaStream1}, 1, &opts);
1205 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1206 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001207
Steve Anton6fe1fba2018-12-11 10:15:23 -08001208 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001209 ASSERT_TRUE(offer.get() != NULL);
1210 EXPECT_EQ(2u, offer->contents().size());
1211 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1212 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1213
Steve Anton4e70a722017-11-28 14:57:10 -08001214 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1215 GetMediaDirection(&offer->contents()[0]));
1216 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1217 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001218}
1219
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001220// Verifies that the order of the media contents in the current
1221// SessionDescription is preserved in the new SessionDescription.
1222TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1223 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001224 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001225
kwiberg31022942016-03-11 14:18:21 -08001226 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001227 ASSERT_TRUE(offer1.get() != NULL);
1228 EXPECT_EQ(1u, offer1->contents().size());
1229 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1230
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001231 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1232 RtpTransceiverDirection::kRecvOnly, kActive,
1233 &opts);
kwiberg31022942016-03-11 14:18:21 -08001234 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001235 f1_.CreateOffer(opts, offer1.get()));
1236 ASSERT_TRUE(offer2.get() != NULL);
1237 EXPECT_EQ(2u, offer2->contents().size());
1238 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1239 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1240
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001241 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1242 RtpTransceiverDirection::kRecvOnly, kActive,
1243 &opts);
kwiberg31022942016-03-11 14:18:21 -08001244 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001245 f1_.CreateOffer(opts, offer2.get()));
1246 ASSERT_TRUE(offer3.get() != NULL);
1247 EXPECT_EQ(3u, offer3->contents().size());
1248 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1249 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1250 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001251}
1252
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253// Create a typical audio answer, and ensure it matches what we expect.
1254TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001255 f1_.set_secure(SEC_ENABLED);
1256 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001257 std::unique_ptr<SessionDescription> offer =
1258 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001260 std::unique_ptr<SessionDescription> answer =
1261 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 const ContentInfo* ac = answer->GetContentByName("audio");
1263 const ContentInfo* vc = answer->GetContentByName("video");
1264 ASSERT_TRUE(ac != NULL);
1265 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001266 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001267 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001269 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001270 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1272 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001273 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1274 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
1275}
1276
1277// Create a typical audio answer with GCM ciphers enabled, and ensure it
1278// matches what we expect.
1279TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1280 f1_.set_secure(SEC_ENABLED);
1281 f2_.set_secure(SEC_ENABLED);
1282 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1283 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
1284 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1285 ASSERT_TRUE(offer.get() != NULL);
1286 for (cricket::ContentInfo& content : offer->contents()) {
1287 auto cryptos = content.media_description()->cryptos();
1288 PreferGcmCryptoParameters(&cryptos);
1289 content.media_description()->set_cryptos(cryptos);
1290 }
1291 std::unique_ptr<SessionDescription> answer =
1292 f2_.CreateAnswer(offer.get(), opts, NULL);
1293 const ContentInfo* ac = answer->GetContentByName("audio");
1294 const ContentInfo* vc = answer->GetContentByName("video");
1295 ASSERT_TRUE(ac != NULL);
1296 ASSERT_TRUE(vc == NULL);
1297 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1298 const AudioContentDescription* acd = ac->media_description()->as_audio();
1299 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1300 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
1301 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
1302 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1303 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1304 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
1305 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001306}
1307
Philipp Hancke2f3168f2022-05-16 14:41:32 +02001308// Create an audio answer with no common codecs, and ensure it is rejected.
1309TEST_F(MediaSessionDescriptionFactoryTest,
1310 TestCreateAudioAnswerWithNoCommonCodecs) {
1311 MediaSessionOptions opts;
1312 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1313 RtpTransceiverDirection::kSendRecv, kActive,
1314 &opts);
1315 std::vector f1_codecs = {AudioCodec(96, "opus", 48000, -1, 1)};
1316 f1_.set_audio_codecs(f1_codecs, f1_codecs);
1317
1318 std::vector f2_codecs = {AudioCodec(0, "PCMU", 8000, -1, 1)};
1319 f2_.set_audio_codecs(f2_codecs, f2_codecs);
1320
1321 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1322 std::unique_ptr<SessionDescription> answer =
1323 f2_.CreateAnswer(offer.get(), opts, NULL);
1324 const ContentInfo* ac = answer->GetContentByName("audio");
1325 ASSERT_TRUE(ac != NULL);
1326 EXPECT_TRUE(ac->rejected);
1327}
1328
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001329// Create a typical video answer, and ensure it matches what we expect.
1330TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1331 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001332 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00001333 f1_.set_secure(SEC_ENABLED);
1334 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001335 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001336 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001337 std::unique_ptr<SessionDescription> answer =
1338 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339 const ContentInfo* ac = answer->GetContentByName("audio");
1340 const ContentInfo* vc = answer->GetContentByName("video");
1341 ASSERT_TRUE(ac != NULL);
1342 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001343 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1344 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001345 const AudioContentDescription* acd = ac->media_description()->as_audio();
1346 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001347 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001348 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001349 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001350 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001352 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001353 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001354 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001355 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1356 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001357 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1358 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
1359}
1360
1361// Create a typical video answer with GCM ciphers enabled, and ensure it
1362// matches what we expect.
1363TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1364 TestVideoGcmCipher(true, true);
1365}
1366
1367// Create a typical video answer with GCM ciphers enabled for the offer only,
1368// and ensure it matches what we expect.
1369TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1370 TestVideoGcmCipher(true, false);
1371}
1372
1373// Create a typical video answer with GCM ciphers enabled for the answer only,
1374// and ensure it matches what we expect.
1375TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1376 TestVideoGcmCipher(false, true);
jbauchcb560652016-08-04 05:20:32 -07001377}
1378
Philipp Hancke2f3168f2022-05-16 14:41:32 +02001379// Create a video answer with no common codecs, and ensure it is rejected.
1380TEST_F(MediaSessionDescriptionFactoryTest,
1381 TestCreateVideoAnswerWithNoCommonCodecs) {
1382 MediaSessionOptions opts;
1383 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1384 RtpTransceiverDirection::kSendRecv, kActive,
1385 &opts);
1386 std::vector f1_codecs = {VideoCodec(96, "H264")};
1387 f1_.set_video_codecs(f1_codecs, f1_codecs);
1388
1389 std::vector f2_codecs = {VideoCodec(97, "VP8")};
1390 f2_.set_video_codecs(f2_codecs, f2_codecs);
1391
1392 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1393 std::unique_ptr<SessionDescription> answer =
1394 f2_.CreateAnswer(offer.get(), opts, NULL);
1395 const ContentInfo* vc = answer->GetContentByName("video");
1396 ASSERT_TRUE(vc != NULL);
1397 EXPECT_TRUE(vc->rejected);
1398}
1399
1400// Create a video answer with no common codecs (but a common FEC codec), and
1401// ensure it is rejected.
1402TEST_F(MediaSessionDescriptionFactoryTest,
1403 TestCreateVideoAnswerWithOnlyFecCodecsCommon) {
1404 MediaSessionOptions opts;
1405 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1406 RtpTransceiverDirection::kSendRecv, kActive,
1407 &opts);
1408 std::vector f1_codecs = {VideoCodec(96, "H264"),
1409 VideoCodec(118, "flexfec-03")};
1410 f1_.set_video_codecs(f1_codecs, f1_codecs);
1411
1412 std::vector f2_codecs = {VideoCodec(97, "VP8"),
1413 VideoCodec(118, "flexfec-03")};
1414 f2_.set_video_codecs(f2_codecs, f2_codecs);
1415
1416 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1417 std::unique_ptr<SessionDescription> answer =
1418 f2_.CreateAnswer(offer.get(), opts, NULL);
1419 const ContentInfo* vc = answer->GetContentByName("video");
1420 ASSERT_TRUE(vc != NULL);
1421 EXPECT_TRUE(vc->rejected);
1422}
1423
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001424// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1425// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001426TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1427 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001428 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001429 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001430 ASSERT_TRUE(offer.get() != NULL);
1431 ContentInfo* dc_offer = offer->GetContentByName("data");
1432 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001433 SctpDataContentDescription* dcd_offer =
1434 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001435 EXPECT_TRUE(dcd_offer->use_sctpmap());
1436
Steve Anton6fe1fba2018-12-11 10:15:23 -08001437 std::unique_ptr<SessionDescription> answer =
1438 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001439 const ContentInfo* dc_answer = answer->GetContentByName("data");
1440 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001441 const SctpDataContentDescription* dcd_answer =
1442 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001443 EXPECT_TRUE(dcd_answer->use_sctpmap());
1444}
1445
1446// The answer's use_sctpmap flag should match the offer's.
1447TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1448 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001449 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001450 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001451 ASSERT_TRUE(offer.get() != NULL);
1452 ContentInfo* dc_offer = offer->GetContentByName("data");
1453 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001454 SctpDataContentDescription* dcd_offer =
1455 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001456 dcd_offer->set_use_sctpmap(false);
1457
Steve Anton6fe1fba2018-12-11 10:15:23 -08001458 std::unique_ptr<SessionDescription> answer =
1459 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001460 const ContentInfo* dc_answer = answer->GetContentByName("data");
1461 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001462 const SctpDataContentDescription* dcd_answer =
1463 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001464 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001465}
1466
deadbeef8b7e9ad2017-05-25 09:38:55 -07001467// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1468// and "TCP/DTLS/SCTP" offers.
1469TEST_F(MediaSessionDescriptionFactoryTest,
1470 TestCreateDataAnswerToDifferentOfferedProtos) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001471 // Need to enable DTLS offer/answer generation (disabled by default in this
1472 // test).
1473 f1_.set_secure(SEC_ENABLED);
1474 f2_.set_secure(SEC_ENABLED);
1475 tdf1_.set_secure(SEC_ENABLED);
1476 tdf2_.set_secure(SEC_ENABLED);
1477
deadbeef8b7e9ad2017-05-25 09:38:55 -07001478 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001479 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001480 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001481 ASSERT_TRUE(offer.get() != nullptr);
1482 ContentInfo* dc_offer = offer->GetContentByName("data");
1483 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001484 SctpDataContentDescription* dcd_offer =
1485 dc_offer->media_description()->as_sctp();
1486 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001487
1488 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1489 "TCP/DTLS/SCTP"};
1490 for (const std::string& proto : protos) {
1491 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001492 std::unique_ptr<SessionDescription> answer =
1493 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001494 const ContentInfo* dc_answer = answer->GetContentByName("data");
1495 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001496 const SctpDataContentDescription* dcd_answer =
1497 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001498 EXPECT_FALSE(dc_answer->rejected);
1499 EXPECT_EQ(proto, dcd_answer->protocol());
1500 }
1501}
1502
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001503TEST_F(MediaSessionDescriptionFactoryTest,
1504 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001505 // Need to enable DTLS offer/answer generation (disabled by default in this
1506 // test).
1507 f1_.set_secure(SEC_ENABLED);
1508 f2_.set_secure(SEC_ENABLED);
1509 tdf1_.set_secure(SEC_ENABLED);
1510 tdf2_.set_secure(SEC_ENABLED);
1511
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001512 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001513 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001514 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1515 ASSERT_TRUE(offer.get() != nullptr);
1516 ContentInfo* dc_offer = offer->GetContentByName("data");
1517 ASSERT_TRUE(dc_offer != nullptr);
1518 SctpDataContentDescription* dcd_offer =
1519 dc_offer->media_description()->as_sctp();
1520 ASSERT_TRUE(dcd_offer);
1521 dcd_offer->set_max_message_size(1234);
1522 std::unique_ptr<SessionDescription> answer =
1523 f2_.CreateAnswer(offer.get(), opts, nullptr);
1524 const ContentInfo* dc_answer = answer->GetContentByName("data");
1525 ASSERT_TRUE(dc_answer != nullptr);
1526 const SctpDataContentDescription* dcd_answer =
1527 dc_answer->media_description()->as_sctp();
1528 EXPECT_FALSE(dc_answer->rejected);
1529 EXPECT_EQ(1234, dcd_answer->max_message_size());
1530}
1531
1532TEST_F(MediaSessionDescriptionFactoryTest,
1533 TestCreateDataAnswerToOfferWithZeroMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001534 // Need to enable DTLS offer/answer generation (disabled by default in this
1535 // test).
1536 f1_.set_secure(SEC_ENABLED);
1537 f2_.set_secure(SEC_ENABLED);
1538 tdf1_.set_secure(SEC_ENABLED);
1539 tdf2_.set_secure(SEC_ENABLED);
1540
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001541 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001542 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001543 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1544 ASSERT_TRUE(offer.get() != nullptr);
1545 ContentInfo* dc_offer = offer->GetContentByName("data");
1546 ASSERT_TRUE(dc_offer != nullptr);
1547 SctpDataContentDescription* dcd_offer =
1548 dc_offer->media_description()->as_sctp();
1549 ASSERT_TRUE(dcd_offer);
1550 dcd_offer->set_max_message_size(0);
1551 std::unique_ptr<SessionDescription> answer =
1552 f2_.CreateAnswer(offer.get(), opts, nullptr);
1553 const ContentInfo* dc_answer = answer->GetContentByName("data");
1554 ASSERT_TRUE(dc_answer != nullptr);
1555 const SctpDataContentDescription* dcd_answer =
1556 dc_answer->media_description()->as_sctp();
1557 EXPECT_FALSE(dc_answer->rejected);
1558 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1559}
1560
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001561// Verifies that the order of the media contents in the offer is preserved in
1562// the answer.
1563TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1564 MediaSessionOptions opts;
1565
1566 // Creates a data only offer.
Florent Castelli516e2842021-04-19 15:29:50 +02001567 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001568 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001569 ASSERT_TRUE(offer1.get() != NULL);
1570
1571 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001572 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1573 RtpTransceiverDirection::kRecvOnly, kActive,
1574 &opts);
kwiberg31022942016-03-11 14:18:21 -08001575 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001576 f1_.CreateOffer(opts, offer1.get()));
1577 ASSERT_TRUE(offer2.get() != NULL);
1578
1579 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001580 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1581 RtpTransceiverDirection::kRecvOnly, kActive,
1582 &opts);
kwiberg31022942016-03-11 14:18:21 -08001583 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001584 f1_.CreateOffer(opts, offer2.get()));
1585 ASSERT_TRUE(offer3.get() != NULL);
1586
Steve Anton6fe1fba2018-12-11 10:15:23 -08001587 std::unique_ptr<SessionDescription> answer =
1588 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001589 ASSERT_TRUE(answer.get() != NULL);
1590 EXPECT_EQ(3u, answer->contents().size());
1591 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1592 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1593 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1594}
1595
ossu075af922016-06-14 03:29:38 -07001596// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1597// answerer settings.
1598
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001599// This test that the media direction is set to send/receive in an answer if
1600// the offer is send receive.
1601TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001602 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1603 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604}
1605
1606// This test that the media direction is set to receive only in an answer if
1607// the offer is send only.
1608TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001609 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1610 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611}
1612
1613// This test that the media direction is set to send only in an answer if
1614// the offer is recv only.
1615TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001616 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1617 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001618}
1619
1620// This test that the media direction is set to inactive in an answer if
1621// the offer is inactive.
1622TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001623 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1624 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001625}
1626
Harald Alvestrand0d018412021-11-04 13:52:31 +00001627// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001628TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001629 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Harald Alvestrand0d018412021-11-04 13:52:31 +00001630 f1_.set_secure(SEC_DISABLED);
1631 f2_.set_secure(SEC_DISABLED);
1632 tdf1_.set_secure(SEC_DISABLED);
1633 tdf2_.set_secure(SEC_DISABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634
Steve Anton6fe1fba2018-12-11 10:15:23 -08001635 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001636 const AudioContentDescription* offer_acd =
1637 GetFirstAudioContentDescription(offer.get());
1638 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001639 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640
Steve Anton6fe1fba2018-12-11 10:15:23 -08001641 std::unique_ptr<SessionDescription> answer =
1642 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001643
1644 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1645 ASSERT_TRUE(ac_answer != NULL);
1646 EXPECT_FALSE(ac_answer->rejected);
1647
1648 const AudioContentDescription* answer_acd =
1649 GetFirstAudioContentDescription(answer.get());
1650 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001651 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001652}
1653
1654// Create a video offer and answer and ensure the RTP header extensions
1655// matches what we expect.
1656TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1657 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001658 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +02001659 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1660 MAKE_VECTOR(kVideoRtpExtension1), &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001661
Steve Anton6fe1fba2018-12-11 10:15:23 -08001662 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001663 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001664 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1665 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001666 std::unique_ptr<SessionDescription> answer =
1667 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668
Yves Gerey665174f2018-06-19 15:03:05 +02001669 EXPECT_EQ(
1670 MAKE_VECTOR(kAudioRtpExtension1),
1671 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1672 EXPECT_EQ(
1673 MAKE_VECTOR(kVideoRtpExtension1),
1674 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1675 EXPECT_EQ(
1676 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1677 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1678 EXPECT_EQ(
1679 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1680 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001681}
1682
Johannes Kronce8e8672019-02-22 13:06:44 +01001683// Create a audio/video offer and answer and ensure that the
1684// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1685// supported and should take precedence even though not listed among locally
1686// supported extensions.
1687TEST_F(MediaSessionDescriptionFactoryTest,
1688 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1689 TestTransportSequenceNumberNegotiation(
1690 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1691 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1692 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1693}
1694TEST_F(MediaSessionDescriptionFactoryTest,
1695 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1696 TestTransportSequenceNumberNegotiation(
1697 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1698 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1699 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1700}
1701TEST_F(MediaSessionDescriptionFactoryTest,
1702 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1703 TestTransportSequenceNumberNegotiation(
1704 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1705 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1706 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1707}
1708
jbauch5869f502017-06-29 12:31:36 -07001709TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001710 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1711 MediaSessionOptions opts;
1712 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1713
Markus Handell755c65d2020-06-24 01:06:10 +02001714 SetAudioVideoRtpHeaderExtensions(
1715 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1716 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001717 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001718 SetAudioVideoRtpHeaderExtensions(
1719 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1720 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001721 std::unique_ptr<SessionDescription> answer =
1722 f2_.CreateAnswer(offer.get(), opts, nullptr);
1723 EXPECT_THAT(
1724 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001725 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001726 EXPECT_THAT(
1727 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001728 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001729}
1730
1731TEST_F(MediaSessionDescriptionFactoryTest,
1732 TestNegotiateFrameDescriptorWhenExposedLocally) {
1733 MediaSessionOptions opts;
1734 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1735
Markus Handell755c65d2020-06-24 01:06:10 +02001736 SetAudioVideoRtpHeaderExtensions(
1737 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1738 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001739 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1740 std::unique_ptr<SessionDescription> answer =
1741 f2_.CreateAnswer(offer.get(), opts, nullptr);
1742 EXPECT_THAT(
1743 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001744 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001745 EXPECT_THAT(
1746 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001747 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001748}
1749
1750TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001751 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1752 MediaSessionOptions opts;
1753 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1754
1755 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell755c65d2020-06-24 01:06:10 +02001756 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +00001757 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001758 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1759 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001760 std::unique_ptr<SessionDescription> answer =
1761 f2_.CreateAnswer(offer.get(), opts, nullptr);
1762 EXPECT_THAT(
1763 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1764 ElementsAre(offer_dd));
1765}
1766
1767TEST_F(MediaSessionDescriptionFactoryTest,
1768 NegotiateDependencyDescriptorWhenExposedLocally) {
1769 MediaSessionOptions opts;
1770 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1771
1772 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1773 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell755c65d2020-06-24 01:06:10 +02001774 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001776 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001777 std::unique_ptr<SessionDescription> answer =
1778 f2_.CreateAnswer(offer.get(), opts, nullptr);
1779 EXPECT_THAT(
1780 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1781 ElementsAre(offer_dd));
1782}
1783
1784TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001785 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
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::kTransportSequenceNumberUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001793 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1794 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001795 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001796 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001797 std::unique_ptr<SessionDescription> answer =
1798 f2_.CreateAnswer(offer.get(), opts, nullptr);
1799 EXPECT_THAT(
1800 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1801 ElementsAreArray(offered_extensions));
1802 EXPECT_THAT(
1803 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1804 ElementsAreArray(offered_extensions));
1805}
1806
1807TEST_F(MediaSessionDescriptionFactoryTest,
1808 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1809 MediaSessionOptions opts;
1810 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1811
1812 const cricket::RtpHeaderExtensions offered_extensions = {
1813 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1814 const cricket::RtpHeaderExtensions local_extensions = {
1815 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001816 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1817 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001818 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001819 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001820 std::unique_ptr<SessionDescription> answer =
1821 f2_.CreateAnswer(offer.get(), opts, nullptr);
1822 EXPECT_THAT(
1823 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1824 ElementsAreArray(offered_extensions));
1825 EXPECT_THAT(
1826 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1827 ElementsAreArray(offered_extensions));
1828}
1829
1830TEST_F(MediaSessionDescriptionFactoryTest,
1831 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1832 MediaSessionOptions opts;
1833 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1834
1835 const cricket::RtpHeaderExtensions offered_extensions = {
1836 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1837 const cricket::RtpHeaderExtensions local_extensions = {
1838 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001839 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1840 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001841 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001842 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001843 std::unique_ptr<SessionDescription> answer =
1844 f2_.CreateAnswer(offer.get(), opts, nullptr);
1845 EXPECT_THAT(
1846 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1847 IsEmpty());
1848 EXPECT_THAT(
1849 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1850 IsEmpty());
1851}
1852
1853TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handell755c65d2020-06-24 01:06:10 +02001854 OffersUnstoppedExtensionsWithAudioVideoExtensionStopped) {
1855 MediaSessionOptions opts;
1856 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1857 RtpTransceiverDirection::kSendRecv, kActive,
1858 &opts);
1859 opts.media_description_options.back().header_extensions = {
1860 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1861 RtpTransceiverDirection::kStopped),
1862 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1863 RtpTransceiverDirection::kSendOnly)};
1864 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1865 RtpTransceiverDirection::kSendRecv, kActive,
1866 &opts);
1867 opts.media_description_options.back().header_extensions = {
1868 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1869 RtpTransceiverDirection::kStopped),
1870 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1871 RtpTransceiverDirection::kSendOnly)};
1872 auto offer = f1_.CreateOffer(opts, nullptr);
1873 EXPECT_THAT(
1874 offer->contents(),
1875 ElementsAre(
1876 Property(&ContentInfo::media_description,
1877 Pointee(Property(
1878 &MediaContentDescription::rtp_header_extensions,
1879 ElementsAre(Field(&RtpExtension::uri, "uri2"))))),
1880 Property(&ContentInfo::media_description,
1881 Pointee(Property(
1882 &MediaContentDescription::rtp_header_extensions,
1883 ElementsAre(Field(&RtpExtension::uri, "uri3")))))));
1884}
1885
1886TEST_F(MediaSessionDescriptionFactoryTest,
1887 OffersUnstoppedExtensionsWithAudioExtensionStopped) {
1888 MediaSessionOptions opts;
1889 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1890 RtpTransceiverDirection::kSendRecv, kActive,
1891 &opts);
1892 opts.media_description_options.back().header_extensions = {
1893 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1894 RtpTransceiverDirection::kSendOnly),
1895 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1896 RtpTransceiverDirection::kStopped)};
1897 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1898 RtpTransceiverDirection::kSendRecv, kActive,
1899 &opts);
1900 opts.media_description_options.back().header_extensions = {
1901 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1902 RtpTransceiverDirection::kSendRecv),
1903 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1904 RtpTransceiverDirection::kSendOnly)};
1905 auto offer = f1_.CreateOffer(opts, nullptr);
1906 EXPECT_THAT(
1907 offer->contents(),
1908 ElementsAre(
1909 Property(&ContentInfo::media_description,
1910 Pointee(Property(
1911 &MediaContentDescription::rtp_header_extensions,
1912 ElementsAre(Field(&RtpExtension::uri, "uri1"))))),
1913 Property(
1914 &ContentInfo::media_description,
1915 Pointee(Property(
1916 &MediaContentDescription::rtp_header_extensions,
1917 UnorderedElementsAre(Field(&RtpExtension::uri, "uri3"),
1918 Field(&RtpExtension::uri, "uri42")))))));
1919}
1920
1921TEST_F(MediaSessionDescriptionFactoryTest,
1922 OffersUnstoppedExtensionsWithVideoExtensionStopped) {
1923 MediaSessionOptions opts;
1924 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1925 RtpTransceiverDirection::kSendRecv, kActive,
1926 &opts);
1927 opts.media_description_options.back().header_extensions = {
1928 webrtc::RtpHeaderExtensionCapability("uri1", 5,
1929 RtpTransceiverDirection::kSendOnly),
1930 webrtc::RtpHeaderExtensionCapability("uri2", 7,
1931 RtpTransceiverDirection::kSendRecv)};
1932 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1933 RtpTransceiverDirection::kSendRecv, kActive,
1934 &opts);
1935 opts.media_description_options.back().header_extensions = {
1936 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1937 RtpTransceiverDirection::kSendRecv),
1938 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1939 RtpTransceiverDirection::kStopped)};
1940 auto offer = f1_.CreateOffer(opts, nullptr);
1941 EXPECT_THAT(
1942 offer->contents(),
1943 ElementsAre(
1944 Property(
1945 &ContentInfo::media_description,
1946 Pointee(Property(
1947 &MediaContentDescription::rtp_header_extensions,
1948 UnorderedElementsAre(Field(&RtpExtension::uri, "uri1"),
1949 Field(&RtpExtension::uri, "uri2"))))),
1950 Property(&ContentInfo::media_description,
1951 Pointee(Property(
1952 &MediaContentDescription::rtp_header_extensions,
1953 ElementsAre(Field(&RtpExtension::uri, "uri42")))))));
1954}
1955
1956TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1957 MediaSessionOptions opts;
1958 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1959 RtpTransceiverDirection::kSendRecv, kActive,
1960 &opts);
1961 opts.media_description_options.back().header_extensions = {
1962 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1963 RtpTransceiverDirection::kStopped),
1964 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1965 RtpTransceiverDirection::kSendOnly),
1966 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1967 RtpTransceiverDirection::kRecvOnly),
1968 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1969 RtpTransceiverDirection::kSendRecv)};
1970 auto offer = f1_.CreateOffer(opts, nullptr);
1971 opts.media_description_options.back().header_extensions = {
1972 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1973 RtpTransceiverDirection::kSendOnly),
1974 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1975 RtpTransceiverDirection::kRecvOnly),
1976 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1977 RtpTransceiverDirection::kStopped),
1978 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1979 RtpTransceiverDirection::kSendRecv)};
1980 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1981 EXPECT_THAT(
1982 answer->contents(),
1983 ElementsAre(Property(
1984 &ContentInfo::media_description,
1985 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1986 ElementsAre(Field(&RtpExtension::uri, "uri2"),
1987 Field(&RtpExtension::uri, "uri4")))))));
1988}
1989
1990TEST_F(MediaSessionDescriptionFactoryTest,
1991 AppendsUnstoppedExtensionsToCurrentDescription) {
1992 MediaSessionOptions opts;
1993 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1994 RtpTransceiverDirection::kSendRecv, kActive,
1995 &opts);
1996 opts.media_description_options.back().header_extensions = {
1997 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1998 RtpTransceiverDirection::kSendRecv)};
1999 auto offer = f1_.CreateOffer(opts, nullptr);
2000 opts.media_description_options.back().header_extensions = {
2001 webrtc::RtpHeaderExtensionCapability("uri1", 2,
2002 RtpTransceiverDirection::kSendRecv),
2003 webrtc::RtpHeaderExtensionCapability("uri2", 3,
2004 RtpTransceiverDirection::kRecvOnly),
2005 webrtc::RtpHeaderExtensionCapability("uri3", 5,
2006 RtpTransceiverDirection::kStopped),
2007 webrtc::RtpHeaderExtensionCapability("uri4", 6,
2008 RtpTransceiverDirection::kSendRecv)};
2009 auto offer2 = f1_.CreateOffer(opts, offer.get());
2010 EXPECT_THAT(
2011 offer2->contents(),
2012 ElementsAre(Property(
2013 &ContentInfo::media_description,
2014 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2015 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2016 Field(&RtpExtension::uri, "uri2"),
2017 Field(&RtpExtension::uri, "uri4")))))));
2018}
2019
2020TEST_F(MediaSessionDescriptionFactoryTest,
Philipp Hanckebe03c092023-02-01 10:10:06 +01002021 AllowsStoppedExtensionsToBeRemovedFromSubsequentOffer) {
Markus Handell755c65d2020-06-24 01:06:10 +02002022 MediaSessionOptions opts;
2023 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2024 RtpTransceiverDirection::kSendRecv, kActive,
2025 &opts);
2026 opts.media_description_options.back().header_extensions = {
2027 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2028 RtpTransceiverDirection::kSendRecv),
2029 webrtc::RtpHeaderExtensionCapability("uri2", 1,
2030 RtpTransceiverDirection::kSendRecv)};
2031 auto offer = f1_.CreateOffer(opts, nullptr);
2032
2033 // Now add "uri2" as stopped to the options verify that the offer contains
2034 // uri2 since it's already present since before.
2035 opts.media_description_options.back().header_extensions = {
2036 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2037 RtpTransceiverDirection::kSendRecv),
2038 webrtc::RtpHeaderExtensionCapability("uri2", 2,
2039 RtpTransceiverDirection::kStopped)};
2040 auto offer2 = f1_.CreateOffer(opts, offer.get());
2041 EXPECT_THAT(
2042 offer2->contents(),
2043 ElementsAre(Property(
2044 &ContentInfo::media_description,
2045 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
Philipp Hanckebe03c092023-02-01 10:10:06 +01002046 ElementsAre(Field(&RtpExtension::uri, "uri1")))))));
Markus Handell755c65d2020-06-24 01:06:10 +02002047}
2048
2049TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002050 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07002051 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002052 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002053
2054 f1_.set_enable_encrypted_rtp_header_extensions(true);
2055 f2_.set_enable_encrypted_rtp_header_extensions(true);
2056
Markus Handell755c65d2020-06-24 01:06:10 +02002057 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2058 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002059 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002060 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002061 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2062 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002063 std::unique_ptr<SessionDescription> answer =
2064 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002065
Yves Gerey665174f2018-06-19 15:03:05 +02002066 EXPECT_EQ(
2067 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2068 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2069 EXPECT_EQ(
2070 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2071 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2072 EXPECT_EQ(
2073 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
2074 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2075 EXPECT_EQ(
2076 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
2077 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002078}
2079
2080TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002081 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07002082 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002083 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002084
2085 f1_.set_enable_encrypted_rtp_header_extensions(true);
2086
Markus Handell755c65d2020-06-24 01:06:10 +02002087 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2088 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002089 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002090 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002091 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2092 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002093 std::unique_ptr<SessionDescription> answer =
2094 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002095
Yves Gerey665174f2018-06-19 15:03:05 +02002096 EXPECT_EQ(
2097 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2098 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2099 EXPECT_EQ(
2100 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2101 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2102 EXPECT_EQ(
2103 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2104 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2105 EXPECT_EQ(
2106 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2107 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002108}
2109
2110TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002111 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07002112 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002113 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002114
2115 f2_.set_enable_encrypted_rtp_header_extensions(true);
2116
Markus Handell755c65d2020-06-24 01:06:10 +02002117 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2118 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002119 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002120 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002121 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2122 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002123 std::unique_ptr<SessionDescription> answer =
2124 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002125
Yves Gerey665174f2018-06-19 15:03:05 +02002126 EXPECT_EQ(
2127 MAKE_VECTOR(kAudioRtpExtension1),
2128 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2129 EXPECT_EQ(
2130 MAKE_VECTOR(kVideoRtpExtension1),
2131 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2132 EXPECT_EQ(
2133 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2134 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2135 EXPECT_EQ(
2136 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2137 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002138}
2139
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002140// Create an audio, video, data answer without legacy StreamParams.
2141TEST_F(MediaSessionDescriptionFactoryTest,
2142 TestCreateAnswerWithoutLegacyStreams) {
2143 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002144 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002145 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002146 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002147 std::unique_ptr<SessionDescription> answer =
2148 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002149 const ContentInfo* ac = answer->GetContentByName("audio");
2150 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151 ASSERT_TRUE(ac != NULL);
2152 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002153 const AudioContentDescription* acd = ac->media_description()->as_audio();
2154 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155
2156 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2157 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002158}
2159
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002160// Create a typical video answer, and ensure it matches what we expect.
2161TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2162 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002163 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002164
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002165 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002166 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002167
kwiberg31022942016-03-11 14:18:21 -08002168 std::unique_ptr<SessionDescription> offer;
2169 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002170
2171 offer_opts.rtcp_mux_enabled = true;
2172 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002173 offer = f1_.CreateOffer(offer_opts, NULL);
2174 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002175 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2176 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002177 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2178 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2180 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002181 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2182 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002183
2184 offer_opts.rtcp_mux_enabled = true;
2185 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002186 offer = f1_.CreateOffer(offer_opts, NULL);
2187 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2189 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002190 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2191 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002192 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2193 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002194 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2195 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002196
2197 offer_opts.rtcp_mux_enabled = false;
2198 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002199 offer = f1_.CreateOffer(offer_opts, NULL);
2200 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002201 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2202 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002203 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2204 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002205 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2206 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002207 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2208 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209
2210 offer_opts.rtcp_mux_enabled = false;
2211 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002212 offer = f1_.CreateOffer(offer_opts, NULL);
2213 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002214 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2215 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002216 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2217 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002218 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2219 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002220 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2221 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002222}
2223
2224// Create an audio-only answer to a video offer.
2225TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2226 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002227 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2228 RtpTransceiverDirection::kRecvOnly, kActive,
2229 &opts);
2230 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2231 RtpTransceiverDirection::kRecvOnly, kActive,
2232 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002233 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002234 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002235
2236 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002237 std::unique_ptr<SessionDescription> answer =
2238 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239 const ContentInfo* ac = answer->GetContentByName("audio");
2240 const ContentInfo* vc = answer->GetContentByName("video");
2241 ASSERT_TRUE(ac != NULL);
2242 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002243 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244 EXPECT_TRUE(vc->rejected);
2245}
2246
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002247// Create an answer that rejects the contents which are rejected in the offer.
2248TEST_F(MediaSessionDescriptionFactoryTest,
2249 CreateAnswerToOfferWithRejectedMedia) {
2250 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002251 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002252 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002253 ASSERT_TRUE(offer.get() != NULL);
2254 ContentInfo* ac = offer->GetContentByName("audio");
2255 ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002256 ASSERT_TRUE(ac != NULL);
2257 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002258 ac->rejected = true;
2259 vc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002260 std::unique_ptr<SessionDescription> answer =
2261 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002262 ac = answer->GetContentByName("audio");
2263 vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002264 ASSERT_TRUE(ac != NULL);
2265 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002266 EXPECT_TRUE(ac->rejected);
2267 EXPECT_TRUE(vc->rejected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002268}
2269
Johannes Kron0854eb62018-10-10 22:33:20 +02002270TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002271 OfferAndAnswerDoesNotHaveMixedByteSessionAttribute) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002272 MediaSessionOptions opts;
Emil Lundmark801c9992021-01-19 13:06:32 +01002273 std::unique_ptr<SessionDescription> offer =
2274 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002275 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002276
Emil Lundmark801c9992021-01-19 13:06:32 +01002277 std::unique_ptr<SessionDescription> answer(
2278 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2279
2280 EXPECT_FALSE(answer->extmap_allow_mixed());
2281}
2282
2283TEST_F(MediaSessionDescriptionFactoryTest,
2284 OfferAndAnswerHaveMixedByteSessionAttribute) {
2285 MediaSessionOptions opts;
2286 std::unique_ptr<SessionDescription> offer =
2287 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002288 offer->set_extmap_allow_mixed(true);
Emil Lundmark801c9992021-01-19 13:06:32 +01002289
Johannes Kron0854eb62018-10-10 22:33:20 +02002290 std::unique_ptr<SessionDescription> answer_support(
Emil Lundmark801c9992021-01-19 13:06:32 +01002291 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2292
Johannes Kron9581bc42018-10-23 10:17:39 +02002293 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002294}
2295
2296TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002297 OfferAndAnswerDoesNotHaveMixedByteMediaAttributes) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002298 MediaSessionOptions opts;
2299 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Emil Lundmark801c9992021-01-19 13:06:32 +01002300 std::unique_ptr<SessionDescription> offer =
2301 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2302 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002303 MediaContentDescription* audio_offer =
2304 offer->GetContentDescriptionByName("audio");
Emil Lundmark801c9992021-01-19 13:06:32 +01002305 MediaContentDescription* video_offer =
2306 offer->GetContentDescriptionByName("video");
2307 ASSERT_EQ(MediaContentDescription::kNo,
2308 audio_offer->extmap_allow_mixed_enum());
2309 ASSERT_EQ(MediaContentDescription::kNo,
2310 video_offer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002311
Emil Lundmark801c9992021-01-19 13:06:32 +01002312 std::unique_ptr<SessionDescription> answer(
2313 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
Johannes Kron0854eb62018-10-10 22:33:20 +02002314
Johannes Kron0854eb62018-10-10 22:33:20 +02002315 MediaContentDescription* audio_answer =
Emil Lundmark801c9992021-01-19 13:06:32 +01002316 answer->GetContentDescriptionByName("audio");
2317 MediaContentDescription* video_answer =
2318 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002319 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002320 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002321 EXPECT_EQ(MediaContentDescription::kNo,
2322 video_answer->extmap_allow_mixed_enum());
2323}
Johannes Kron0854eb62018-10-10 22:33:20 +02002324
Emil Lundmark801c9992021-01-19 13:06:32 +01002325TEST_F(MediaSessionDescriptionFactoryTest,
2326 OfferAndAnswerHaveSameMixedByteMediaAttributes) {
2327 MediaSessionOptions opts;
2328 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2329 std::unique_ptr<SessionDescription> offer =
2330 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2331 offer->set_extmap_allow_mixed(false);
2332 MediaContentDescription* audio_offer =
2333 offer->GetContentDescriptionByName("audio");
Johannes Kron9581bc42018-10-23 10:17:39 +02002334 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Emil Lundmark801c9992021-01-19 13:06:32 +01002335 MediaContentDescription* video_offer =
2336 offer->GetContentDescriptionByName("video");
2337 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2338
2339 std::unique_ptr<SessionDescription> answer(
2340 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2341
2342 MediaContentDescription* audio_answer =
2343 answer->GetContentDescriptionByName("audio");
2344 MediaContentDescription* video_answer =
2345 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002346 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002347 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002348 EXPECT_EQ(MediaContentDescription::kMedia,
2349 video_answer->extmap_allow_mixed_enum());
2350}
2351
2352TEST_F(MediaSessionDescriptionFactoryTest,
2353 OfferAndAnswerHaveDifferentMixedByteMediaAttributes) {
2354 MediaSessionOptions opts;
2355 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2356 std::unique_ptr<SessionDescription> offer =
2357 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2358 offer->set_extmap_allow_mixed(false);
2359 MediaContentDescription* audio_offer =
2360 offer->GetContentDescriptionByName("audio");
2361 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2362 MediaContentDescription* video_offer =
2363 offer->GetContentDescriptionByName("video");
2364 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2365
2366 std::unique_ptr<SessionDescription> answer(
2367 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2368
2369 MediaContentDescription* audio_answer =
2370 answer->GetContentDescriptionByName("audio");
2371 MediaContentDescription* video_answer =
2372 answer->GetContentDescriptionByName("video");
2373 EXPECT_EQ(MediaContentDescription::kNo,
2374 audio_answer->extmap_allow_mixed_enum());
2375 EXPECT_EQ(MediaContentDescription::kMedia,
2376 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002377}
2378
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002379// Create an audio and video offer with:
2380// - one video track
2381// - two audio tracks
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382// and ensure it matches what we expect. Also updates the initial offer by
2383// adding a new video track and replaces one of the audio tracks.
2384TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2385 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002386 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002387 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2388 {kMediaStream1}, 1, &opts);
2389 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2390 {kMediaStream1}, 1, &opts);
2391 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2392 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002393
Harald Alvestrand0d018412021-11-04 13:52:31 +00002394 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002395 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002396
2397 ASSERT_TRUE(offer.get() != NULL);
2398 const ContentInfo* ac = offer->GetContentByName("audio");
2399 const ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002400 ASSERT_TRUE(ac != NULL);
2401 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002402 const AudioContentDescription* acd = ac->media_description()->as_audio();
2403 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002404 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002405 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002406
2407 const StreamParamsVec& audio_streams = acd->streams();
2408 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002409 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002410 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2411 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2412 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2413 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2414 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2415 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2416
2417 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2418 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +00002419 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002420
2421 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002422 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002423 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002424
2425 const StreamParamsVec& video_streams = vcd->streams();
2426 ASSERT_EQ(1U, video_streams.size());
2427 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2428 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2429 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2430 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2431
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432 // Update the offer. Add a new video track that is not synched to the
2433 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002434 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2435 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002436 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002437 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2438 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002439 std::unique_ptr<SessionDescription> updated_offer(
2440 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002441
2442 ASSERT_TRUE(updated_offer.get() != NULL);
2443 ac = updated_offer->GetContentByName("audio");
2444 vc = updated_offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002445 ASSERT_TRUE(ac != NULL);
2446 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002447 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002448 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002449 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002450 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002451
2452 EXPECT_EQ(acd->type(), updated_acd->type());
2453 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2454 EXPECT_EQ(vcd->type(), updated_vcd->type());
2455 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002456 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2457 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2458 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2459 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002460
2461 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2462 ASSERT_EQ(2U, updated_audio_streams.size());
2463 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2464 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2465 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2466 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2467 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2468
2469 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2470 ASSERT_EQ(2U, updated_video_streams.size());
2471 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2472 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002473 // All the media streams in one PeerConnection share one RTCP CNAME.
2474 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002475}
2476
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002477// Create an offer with simulcast video stream.
2478TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2479 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002480 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2481 RtpTransceiverDirection::kRecvOnly, kActive,
2482 &opts);
2483 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2484 RtpTransceiverDirection::kSendRecv, kActive,
2485 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002486 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002487 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2488 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002489 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002490
2491 ASSERT_TRUE(offer.get() != NULL);
2492 const ContentInfo* vc = offer->GetContentByName("video");
2493 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002494 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002495
2496 const StreamParamsVec& video_streams = vcd->streams();
2497 ASSERT_EQ(1U, video_streams.size());
2498 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2499 const SsrcGroup* sim_ssrc_group =
2500 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2501 ASSERT_TRUE(sim_ssrc_group != NULL);
2502 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2503}
2504
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002505MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2506 const RidDescription& rid1 = ::testing::get<0>(arg);
2507 const RidDescription& rid2 = ::testing::get<1>(arg);
2508 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2509}
2510
2511static void CheckSimulcastInSessionDescription(
2512 const SessionDescription* description,
2513 const std::string& content_name,
2514 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002515 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002516 ASSERT_NE(description, nullptr);
2517 const ContentInfo* content = description->GetContentByName(content_name);
2518 ASSERT_NE(content, nullptr);
2519 const MediaContentDescription* cd = content->media_description();
2520 ASSERT_NE(cd, nullptr);
2521 const StreamParamsVec& streams = cd->streams();
2522 ASSERT_THAT(streams, SizeIs(1));
2523 const StreamParams& stream = streams[0];
2524 ASSERT_THAT(stream.ssrcs, IsEmpty());
2525 EXPECT_TRUE(stream.has_rids());
2526 const std::vector<RidDescription> rids = stream.rids();
2527
2528 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2529
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002530 EXPECT_TRUE(cd->HasSimulcast());
2531 const SimulcastDescription& simulcast = cd->simulcast_description();
2532 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2533 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2534
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002535 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002536}
2537
2538// Create an offer with spec-compliant simulcast video stream.
2539TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2540 MediaSessionOptions opts;
2541 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2542 RtpTransceiverDirection::kSendRecv, kActive,
2543 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002544 std::vector<RidDescription> send_rids;
2545 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2546 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2547 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2548 SimulcastLayerList simulcast_layers;
2549 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2550 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2551 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2552 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2553 {kMediaStream1}, send_rids,
2554 simulcast_layers, 0, &opts);
2555 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2556
2557 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002558 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002559}
2560
2561// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2562// In this scenario, RIDs do not need to be negotiated (there is only one).
2563TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2564 MediaSessionOptions opts;
2565 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2566 RtpTransceiverDirection::kSendRecv, kActive,
2567 &opts);
2568 RidDescription rid("f", RidDirection::kSend);
2569 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2570 {kMediaStream1}, {rid},
2571 SimulcastLayerList(), 0, &opts);
2572 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2573
2574 ASSERT_NE(offer.get(), nullptr);
2575 const ContentInfo* content = offer->GetContentByName("video");
2576 ASSERT_NE(content, nullptr);
2577 const MediaContentDescription* cd = content->media_description();
2578 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002579 const StreamParamsVec& streams = cd->streams();
2580 ASSERT_THAT(streams, SizeIs(1));
2581 const StreamParams& stream = streams[0];
2582 ASSERT_THAT(stream.ssrcs, IsEmpty());
2583 EXPECT_FALSE(stream.has_rids());
2584 EXPECT_FALSE(cd->HasSimulcast());
2585}
2586
2587// Create an answer with spec-compliant simulcast video stream.
2588// In this scenario, the SFU is the caller requesting that we send Simulcast.
2589TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2590 MediaSessionOptions offer_opts;
2591 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2592 RtpTransceiverDirection::kSendRecv, kActive,
2593 &offer_opts);
2594 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2595 {kMediaStream1}, 1, &offer_opts);
2596 std::unique_ptr<SessionDescription> offer =
2597 f1_.CreateOffer(offer_opts, nullptr);
2598
2599 MediaSessionOptions answer_opts;
2600 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2601 RtpTransceiverDirection::kSendRecv, kActive,
2602 &answer_opts);
2603
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002604 std::vector<RidDescription> rid_descriptions{
2605 RidDescription("f", RidDirection::kSend),
2606 RidDescription("h", RidDirection::kSend),
2607 RidDescription("q", RidDirection::kSend),
2608 };
2609 SimulcastLayerList simulcast_layers;
2610 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2611 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2612 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2613 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2614 {kMediaStream1}, rid_descriptions,
2615 simulcast_layers, 0, &answer_opts);
2616 std::unique_ptr<SessionDescription> answer =
2617 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2618
2619 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002620 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002621}
2622
2623// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2624// In this scenario, RIDs do not need to be negotiated (there is only one).
2625// Note that RID Direction is not the same as the transceiver direction.
2626TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2627 MediaSessionOptions offer_opts;
2628 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2629 RtpTransceiverDirection::kSendRecv, kActive,
2630 &offer_opts);
2631 RidDescription rid_offer("f", RidDirection::kSend);
2632 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2633 {kMediaStream1}, {rid_offer},
2634 SimulcastLayerList(), 0, &offer_opts);
2635 std::unique_ptr<SessionDescription> offer =
2636 f1_.CreateOffer(offer_opts, nullptr);
2637
2638 MediaSessionOptions answer_opts;
2639 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2640 RtpTransceiverDirection::kSendRecv, kActive,
2641 &answer_opts);
2642
2643 RidDescription rid_answer("f", RidDirection::kReceive);
2644 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2645 {kMediaStream1}, {rid_answer},
2646 SimulcastLayerList(), 0, &answer_opts);
2647 std::unique_ptr<SessionDescription> answer =
2648 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2649
2650 ASSERT_NE(answer.get(), nullptr);
2651 const ContentInfo* content = offer->GetContentByName("video");
2652 ASSERT_NE(content, nullptr);
2653 const MediaContentDescription* cd = content->media_description();
2654 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002655 const StreamParamsVec& streams = cd->streams();
2656 ASSERT_THAT(streams, SizeIs(1));
2657 const StreamParams& stream = streams[0];
2658 ASSERT_THAT(stream.ssrcs, IsEmpty());
2659 EXPECT_FALSE(stream.has_rids());
2660 EXPECT_FALSE(cd->HasSimulcast());
2661}
2662
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002663// Create an audio and video answer to a standard video offer with:
2664// - one video track
2665// - two audio tracks
2666// - two data tracks
2667// and ensure it matches what we expect. Also updates the initial answer by
2668// adding a new video track and removes one of the audio tracks.
2669TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2670 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002671 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2672 RtpTransceiverDirection::kRecvOnly, kActive,
2673 &offer_opts);
2674 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2675 RtpTransceiverDirection::kRecvOnly, kActive,
2676 &offer_opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00002677 f1_.set_secure(SEC_ENABLED);
2678 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002679 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680
zhihuang1c378ed2017-08-17 14:10:50 -07002681 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002682 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2683 RtpTransceiverDirection::kSendRecv, kActive,
2684 &answer_opts);
2685 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2686 RtpTransceiverDirection::kSendRecv, kActive,
2687 &answer_opts);
2688 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2689 {kMediaStream1}, 1, &answer_opts);
2690 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2691 {kMediaStream1}, 1, &answer_opts);
2692 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2693 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002694
Steve Anton6fe1fba2018-12-11 10:15:23 -08002695 std::unique_ptr<SessionDescription> answer =
2696 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002697
2698 ASSERT_TRUE(answer.get() != NULL);
2699 const ContentInfo* ac = answer->GetContentByName("audio");
2700 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002701 ASSERT_TRUE(ac != NULL);
2702 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002703 const AudioContentDescription* acd = ac->media_description()->as_audio();
2704 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand0d018412021-11-04 13:52:31 +00002705 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2706 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707
2708 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002709 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002710
2711 const StreamParamsVec& audio_streams = acd->streams();
2712 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002713 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2715 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2716 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2717 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2718 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2719 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2720
2721 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2722 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2723
2724 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002725 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002726
2727 const StreamParamsVec& video_streams = vcd->streams();
2728 ASSERT_EQ(1U, video_streams.size());
2729 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2730 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2731 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2732 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2733
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002734 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002735 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002736 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2737 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002738 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002739 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002740 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002741
2742 ASSERT_TRUE(updated_answer.get() != NULL);
2743 ac = updated_answer->GetContentByName("audio");
2744 vc = updated_answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002745 ASSERT_TRUE(ac != NULL);
2746 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002747 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002748 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002749 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002750 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002751
Harald Alvestrand0d018412021-11-04 13:52:31 +00002752 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2753 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2754 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2755 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
2756
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002757 EXPECT_EQ(acd->type(), updated_acd->type());
2758 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2759 EXPECT_EQ(vcd->type(), updated_vcd->type());
2760 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002761
2762 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2763 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002764 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765
2766 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2767 ASSERT_EQ(2U, updated_video_streams.size());
2768 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2769 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002770 // All media streams in one PeerConnection share one CNAME.
2771 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002772}
2773
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002774// Create an updated offer after creating an answer to the original offer and
2775// verify that the codecs that were part of the original answer are not changed
2776// in the updated offer.
2777TEST_F(MediaSessionDescriptionFactoryTest,
2778 RespondentCreatesOfferAfterCreatingAnswer) {
2779 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002780 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002781
Steve Anton6fe1fba2018-12-11 10:15:23 -08002782 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2783 std::unique_ptr<SessionDescription> answer =
2784 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002785
2786 const AudioContentDescription* acd =
2787 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002788 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002789
2790 const VideoContentDescription* vcd =
2791 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002792 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793
kwiberg31022942016-03-11 14:18:21 -08002794 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002795 f2_.CreateOffer(opts, answer.get()));
2796
2797 // The expected audio codecs are the common audio codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002798 // offer/answer exchange plus the audio codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002799 // preference order.
Artem Titov880fa812021-07-30 22:30:23 +02002800 // TODO(wu): `updated_offer` should not include the codec
Artem Titovcfea2182021-08-10 01:22:31 +02002801 // (i.e. `kAudioCodecs2[0]`) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002802 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002803 kAudioCodecsAnswer[0],
2804 kAudioCodecsAnswer[1],
2805 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002806 };
2807
2808 // The expected video codecs are the common video codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002809 // offer/answer exchange plus the video codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002810 // preference order.
2811 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002812 kVideoCodecsAnswer[0],
2813 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814 };
2815
2816 const AudioContentDescription* updated_acd =
2817 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002818 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002819
2820 const VideoContentDescription* updated_vcd =
2821 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002822 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002823}
2824
Steve Anton5c72e712018-12-10 14:25:30 -08002825// Test that a reoffer does not reuse audio codecs from a previous media section
2826// that is being recycled.
2827TEST_F(MediaSessionDescriptionFactoryTest,
2828 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002829 f1_.set_video_codecs({}, {});
2830 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002831
2832 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002833 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2834 RtpTransceiverDirection::kSendRecv, kActive,
2835 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002836 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2837 std::unique_ptr<SessionDescription> answer =
2838 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002839
2840 // Recycle the media section by changing its mid.
2841 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002842 std::unique_ptr<SessionDescription> reoffer =
2843 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002844
2845 // Expect that the results of the first negotiation are ignored. If the m=
2846 // section was not recycled the payload types would match the initial offerer.
2847 const AudioContentDescription* acd =
2848 GetFirstAudioContentDescription(reoffer.get());
2849 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2850}
2851
2852// Test that a reoffer does not reuse video codecs from a previous media section
2853// that is being recycled.
2854TEST_F(MediaSessionDescriptionFactoryTest,
2855 ReOfferDoesNotReUseRecycledVideoCodecs) {
2856 f1_.set_audio_codecs({}, {});
2857 f2_.set_audio_codecs({}, {});
2858
2859 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002860 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2861 RtpTransceiverDirection::kSendRecv, kActive,
2862 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002863 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2864 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002865
2866 // Recycle the media section by changing its mid.
2867 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002868 std::unique_ptr<SessionDescription> reoffer =
2869 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002870
2871 // Expect that the results of the first negotiation are ignored. If the m=
2872 // section was not recycled the payload types would match the initial offerer.
2873 const VideoContentDescription* vcd =
2874 GetFirstVideoContentDescription(reoffer.get());
2875 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2876}
2877
2878// Test that a reanswer does not reuse audio codecs from a previous media
2879// section that is being recycled.
2880TEST_F(MediaSessionDescriptionFactoryTest,
2881 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002882 f1_.set_video_codecs({}, {});
2883 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002884
Artem Titov880fa812021-07-30 22:30:23 +02002885 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2886 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002887 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002888 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2889 RtpTransceiverDirection::kSendRecv, kActive,
2890 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002891 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2892 std::unique_ptr<SessionDescription> answer =
2893 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002894
2895 // Recycle the media section by changing its mid.
2896 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002897 std::unique_ptr<SessionDescription> reoffer =
2898 f1_.CreateOffer(opts, answer.get());
2899 std::unique_ptr<SessionDescription> reanswer =
2900 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002901
2902 // Expect that the results of the first negotiation are ignored. If the m=
2903 // section was not recycled the payload types would match the initial offerer.
2904 const AudioContentDescription* acd =
2905 GetFirstAudioContentDescription(reanswer.get());
2906 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2907}
2908
2909// Test that a reanswer does not reuse video codecs from a previous media
2910// section that is being recycled.
2911TEST_F(MediaSessionDescriptionFactoryTest,
2912 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2913 f1_.set_audio_codecs({}, {});
2914 f2_.set_audio_codecs({}, {});
2915
Artem Titov880fa812021-07-30 22:30:23 +02002916 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2917 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002918 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002919 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2920 RtpTransceiverDirection::kSendRecv, kActive,
2921 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002922 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2923 std::unique_ptr<SessionDescription> answer =
2924 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002925
2926 // Recycle the media section by changing its mid.
2927 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002928 std::unique_ptr<SessionDescription> reoffer =
2929 f1_.CreateOffer(opts, answer.get());
2930 std::unique_ptr<SessionDescription> reanswer =
2931 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002932
2933 // Expect that the results of the first negotiation are ignored. If the m=
2934 // section was not recycled the payload types would match the initial offerer.
2935 const VideoContentDescription* vcd =
2936 GetFirstVideoContentDescription(reanswer.get());
2937 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2938}
2939
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002940// Create an updated offer after creating an answer to the original offer and
2941// verify that the codecs that were part of the original answer are not changed
2942// in the updated offer. In this test Rtx is enabled.
2943TEST_F(MediaSessionDescriptionFactoryTest,
2944 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2945 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002946 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2947 RtpTransceiverDirection::kRecvOnly, kActive,
2948 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002949 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02002950 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002951 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002952 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002953
2954 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02002955 // This creates rtx for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002956 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002957 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002958
Steve Anton6fe1fba2018-12-11 10:15:23 -08002959 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002960 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002961 std::unique_ptr<SessionDescription> answer =
2962 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002963
2964 const VideoContentDescription* vcd =
2965 GetFirstVideoContentDescription(answer.get());
2966
2967 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002968 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2969 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002970
2971 EXPECT_EQ(expected_codecs, vcd->codecs());
2972
Artem Titov880fa812021-07-30 22:30:23 +02002973 // Now, make sure we get same result (except for the order) if `f2_` creates
2974 // an updated offer even though the default payload types between `f1_` and
2975 // `f2_` are different.
kwiberg31022942016-03-11 14:18:21 -08002976 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002977 f2_.CreateOffer(opts, answer.get()));
2978 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002979 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2981
2982 const VideoContentDescription* updated_vcd =
2983 GetFirstVideoContentDescription(updated_answer.get());
2984
2985 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2986}
2987
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002988// Regression test for:
2989// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2990// Existing codecs should always appear before new codecs in re-offers. But
2991// under a specific set of circumstances, the existing RTX codec was ending up
2992// added to the end of the list.
2993TEST_F(MediaSessionDescriptionFactoryTest,
2994 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2995 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002996 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2997 RtpTransceiverDirection::kRecvOnly, kActive,
2998 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002999 // We specifically choose different preferred payload types for VP8 to
3000 // trigger the issue.
3001 cricket::VideoCodec vp8_offerer(100, "VP8");
3002 cricket::VideoCodec vp8_offerer_rtx =
3003 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
3004 cricket::VideoCodec vp8_answerer(110, "VP8");
3005 cricket::VideoCodec vp8_answerer_rtx =
3006 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
3007 cricket::VideoCodec vp9(120, "VP9");
3008 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
3009
3010 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
3011 // We also specifically cause the answerer to prefer VP9, such that if it
3012 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
3013 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
3014 vp8_answerer_rtx};
3015
Johannes Kron3e983682020-03-29 22:17:00 +02003016 f1_.set_video_codecs(f1_codecs, f1_codecs);
3017 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003018 std::vector<AudioCodec> audio_codecs;
3019 f1_.set_audio_codecs(audio_codecs, audio_codecs);
3020 f2_.set_audio_codecs(audio_codecs, audio_codecs);
3021
3022 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003023 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003024 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003025 std::unique_ptr<SessionDescription> answer =
3026 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003027
3028 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
3029 // But if the bug is triggered, RTX for VP8 ends up last.
3030 std::unique_ptr<SessionDescription> updated_offer(
3031 f2_.CreateOffer(opts, answer.get()));
3032
3033 const VideoContentDescription* vcd =
3034 GetFirstVideoContentDescription(updated_offer.get());
3035 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
3036 ASSERT_EQ(4u, codecs.size());
3037 EXPECT_EQ(vp8_offerer, codecs[0]);
3038 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
3039 EXPECT_EQ(vp9, codecs[2]);
3040 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003041}
3042
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003043// Create an updated offer that adds video after creating an audio only answer
3044// to the original offer. This test verifies that if a video codec and the RTX
3045// codec have the same default payload type as an audio codec that is already in
3046// use, the added codecs payload types are changed.
3047TEST_F(MediaSessionDescriptionFactoryTest,
3048 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
3049 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02003050 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003051 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003052 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003053
3054 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003055 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3056 RtpTransceiverDirection::kRecvOnly, kActive,
3057 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003058
Steve Anton6fe1fba2018-12-11 10:15:23 -08003059 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3060 std::unique_ptr<SessionDescription> answer =
3061 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003062
3063 const AudioContentDescription* acd =
3064 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003065 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003066
Artem Titov880fa812021-07-30 22:30:23 +02003067 // Now - let `f2_` add video with RTX and let the payload type the RTX codec
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003068 // reference be the same as an audio codec that was negotiated in the
3069 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07003070 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08003071 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003072
3073 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3074 int used_pl_type = acd->codecs()[0].id;
3075 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003076 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003077 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003078
kwiberg31022942016-03-11 14:18:21 -08003079 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003080 f2_.CreateOffer(opts, answer.get()));
3081 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003082 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003083 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3084
3085 const AudioContentDescription* updated_acd =
3086 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003087 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003088
3089 const VideoContentDescription* updated_vcd =
3090 GetFirstVideoContentDescription(updated_answer.get());
3091
3092 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003093 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003094 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003095 EXPECT_NE(used_pl_type, new_h264_pl_type);
3096 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003097 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003098 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3099 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3100}
3101
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003102// Create an updated offer with RTX after creating an answer to an offer
3103// without RTX, and with different default payload types.
3104// Verify that the added RTX codec references the correct payload type.
3105TEST_F(MediaSessionDescriptionFactoryTest,
3106 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3107 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003108 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003109
3110 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003111 // This creates rtx for H264 with the payload type `f2_` uses.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003112 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003113 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003114
Steve Anton6fe1fba2018-12-11 10:15:23 -08003115 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003116 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003117 std::unique_ptr<SessionDescription> answer =
3118 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003119
3120 const VideoContentDescription* vcd =
3121 GetFirstVideoContentDescription(answer.get());
3122
3123 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3124 EXPECT_EQ(expected_codecs, vcd->codecs());
3125
Artem Titov880fa812021-07-30 22:30:23 +02003126 // Now, ensure that the RTX codec is created correctly when `f2_` creates an
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003127 // updated offer, even though the default payload types are different from
Artem Titov880fa812021-07-30 22:30:23 +02003128 // those of `f1_`.
kwiberg31022942016-03-11 14:18:21 -08003129 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003130 f2_.CreateOffer(opts, answer.get()));
3131 ASSERT_TRUE(updated_offer);
3132
3133 const VideoContentDescription* updated_vcd =
3134 GetFirstVideoContentDescription(updated_offer.get());
3135
3136 // New offer should attempt to add H263, and RTX for H264.
3137 expected_codecs.push_back(kVideoCodecs2[1]);
3138 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3139 &expected_codecs);
3140 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3141}
3142
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003143// Test that RTX is ignored when there is no associated payload type parameter.
3144TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3145 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003146 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3147 RtpTransceiverDirection::kRecvOnly, kActive,
3148 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003149 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003150 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003151 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003152 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003153
3154 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003155 // This creates RTX for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003156 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003157 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003158
Steve Anton6fe1fba2018-12-11 10:15:23 -08003159 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003160 ASSERT_TRUE(offer.get() != NULL);
3161 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3162 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3163 // is possible to test that that RTX is dropped when
3164 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003165 MediaContentDescription* media_desc =
3166 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3167 ASSERT_TRUE(media_desc);
3168 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003169 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003170 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003171 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003172 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003173 }
3174 }
3175 desc->set_codecs(codecs);
3176
Steve Anton6fe1fba2018-12-11 10:15:23 -08003177 std::unique_ptr<SessionDescription> answer =
3178 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003179
Steve Anton64b626b2019-01-28 17:25:26 -08003180 EXPECT_THAT(
3181 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3182 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003183}
3184
3185// Test that RTX will be filtered out in the answer if its associated payload
3186// type doesn't match the local value.
3187TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3188 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003189 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3190 RtpTransceiverDirection::kRecvOnly, kActive,
3191 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003192 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3193 // This creates RTX for H264 in sender.
3194 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003195 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003196
3197 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3198 // This creates RTX for H263 in receiver.
3199 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003200 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003201
Steve Anton6fe1fba2018-12-11 10:15:23 -08003202 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003203 ASSERT_TRUE(offer.get() != NULL);
3204 // Associated payload type doesn't match, therefore, RTX codec is removed in
3205 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003206 std::unique_ptr<SessionDescription> answer =
3207 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003208
Steve Anton64b626b2019-01-28 17:25:26 -08003209 EXPECT_THAT(
3210 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3211 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003212}
3213
3214// Test that when multiple RTX codecs are offered, only the matched RTX codec
3215// is added in the answer, and the unsupported RTX codec is filtered out.
3216TEST_F(MediaSessionDescriptionFactoryTest,
3217 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3218 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003219 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3220 RtpTransceiverDirection::kRecvOnly, kActive,
3221 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003222 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3223 // This creates RTX for H264-SVC in sender.
3224 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003225 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003226
3227 // This creates RTX for H264 in sender.
3228 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003229 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003230
3231 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3232 // This creates RTX for H264 in receiver.
3233 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003234 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003235
3236 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3237 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003238 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003239 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003240 std::unique_ptr<SessionDescription> answer =
3241 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003242 const VideoContentDescription* vcd =
3243 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003244 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3245 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3246 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003247
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003248 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003249}
3250
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003251// Test that after one RTX codec has been negotiated, a new offer can attempt
3252// to add another.
3253TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3254 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003255 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3256 RtpTransceiverDirection::kRecvOnly, kActive,
3257 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003258 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3259 // This creates RTX for H264 for the offerer.
3260 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003261 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003262
Steve Anton6fe1fba2018-12-11 10:15:23 -08003263 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003264 ASSERT_TRUE(offer);
3265 const VideoContentDescription* vcd =
3266 GetFirstVideoContentDescription(offer.get());
3267
3268 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3269 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3270 &expected_codecs);
3271 EXPECT_EQ(expected_codecs, vcd->codecs());
3272
3273 // Now, attempt to add RTX for H264-SVC.
3274 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003275 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003276
kwiberg31022942016-03-11 14:18:21 -08003277 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003278 f1_.CreateOffer(opts, offer.get()));
3279 ASSERT_TRUE(updated_offer);
3280 vcd = GetFirstVideoContentDescription(updated_offer.get());
3281
3282 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3283 &expected_codecs);
3284 EXPECT_EQ(expected_codecs, vcd->codecs());
3285}
3286
Noah Richards2e7a0982015-05-18 14:02:54 -07003287// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3288// generated for each simulcast ssrc and correctly grouped.
3289TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3290 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003291 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3292 RtpTransceiverDirection::kSendRecv, kActive,
3293 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003294 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003295 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3296 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003297
3298 // Use a single real codec, and then add RTX for it.
3299 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003300 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003301 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003302 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003303
3304 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3305 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003306 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003307 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003308 MediaContentDescription* media_desc =
3309 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3310 ASSERT_TRUE(media_desc);
3311 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003312 const StreamParamsVec& streams = desc->streams();
3313 // Single stream.
3314 ASSERT_EQ(1u, streams.size());
3315 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3316 EXPECT_EQ(6u, streams[0].ssrcs.size());
3317 // And should have a SIM group for the simulcast.
3318 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3319 // And a FID group for RTX.
3320 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003321 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003322 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3323 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003324 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003325 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3326 EXPECT_EQ(3u, fid_ssrcs.size());
3327}
3328
brandtr03d5fb12016-11-22 03:37:59 -08003329// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003330// together with a FEC-FR grouping. Guarded by WebRTC-FlexFEC-03 trial.
brandtr03d5fb12016-11-22 03:37:59 -08003331TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01003332 webrtc::test::ScopedKeyValueConfig override_field_trials(
3333 field_trials, "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003334 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003335 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3336 RtpTransceiverDirection::kSendRecv, kActive,
3337 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003338 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003339 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3340 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003341
3342 // Use a single real codec, and then add FlexFEC for it.
3343 std::vector<VideoCodec> f1_codecs;
3344 f1_codecs.push_back(VideoCodec(97, "H264"));
3345 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003346 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003347
3348 // Ensure that the offer has a single FlexFEC ssrc and that
3349 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003350 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003351 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003352 MediaContentDescription* media_desc =
3353 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3354 ASSERT_TRUE(media_desc);
3355 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003356 const StreamParamsVec& streams = desc->streams();
3357 // Single stream.
3358 ASSERT_EQ(1u, streams.size());
3359 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3360 EXPECT_EQ(2u, streams[0].ssrcs.size());
3361 // And should have a FEC-FR group for FlexFEC.
3362 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3363 std::vector<uint32_t> primary_ssrcs;
3364 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3365 ASSERT_EQ(1u, primary_ssrcs.size());
3366 uint32_t flexfec_ssrc;
3367 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3368 EXPECT_NE(flexfec_ssrc, 0u);
3369}
3370
3371// Test that FlexFEC is disabled for simulcast.
3372// TODO(brandtr): Remove this test when we support simulcast, either through
3373// multiple FlexfecSenders, or through multistream protection.
3374TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01003375 webrtc::test::ScopedKeyValueConfig override_field_trials(
3376 field_trials, "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003377 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003378 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3379 RtpTransceiverDirection::kSendRecv, kActive,
3380 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003381 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003382 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3383 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003384
3385 // Use a single real codec, and then add FlexFEC for it.
3386 std::vector<VideoCodec> f1_codecs;
3387 f1_codecs.push_back(VideoCodec(97, "H264"));
3388 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003389 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003390
3391 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3392 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003393 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003394 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003395 MediaContentDescription* media_desc =
3396 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3397 ASSERT_TRUE(media_desc);
3398 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003399 const StreamParamsVec& streams = desc->streams();
3400 // Single stream.
3401 ASSERT_EQ(1u, streams.size());
3402 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3403 EXPECT_EQ(3u, streams[0].ssrcs.size());
3404 // And should have a SIM group for the simulcast.
3405 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3406 // And not a FEC-FR group for FlexFEC.
3407 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3408 std::vector<uint32_t> primary_ssrcs;
3409 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3410 EXPECT_EQ(3u, primary_ssrcs.size());
3411 for (uint32_t primary_ssrc : primary_ssrcs) {
3412 uint32_t flexfec_ssrc;
3413 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3414 }
3415}
3416
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003417// Create an updated offer after creating an answer to the original offer and
3418// verify that the RTP header extensions that were part of the original answer
3419// are not changed in the updated offer.
3420TEST_F(MediaSessionDescriptionFactoryTest,
3421 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3422 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003423 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003424
Markus Handell755c65d2020-06-24 01:06:10 +02003425 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3426 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003427 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02003428 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3429 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003430 std::unique_ptr<SessionDescription> answer =
3431 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003432
Yves Gerey665174f2018-06-19 15:03:05 +02003433 EXPECT_EQ(
3434 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3435 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3436 EXPECT_EQ(
3437 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3438 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003439
kwiberg31022942016-03-11 14:18:21 -08003440 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003441 f2_.CreateOffer(opts, answer.get()));
3442
3443 // The expected RTP header extensions in the new offer are the resulting
3444 // extensions from the first offer/answer exchange plus the extensions only
Artem Titov880fa812021-07-30 22:30:23 +02003445 // `f2_` offer.
3446 // Since the default local extension id `f2_` uses has already been used by
3447 // `f1_` for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003448 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003449 kAudioRtpExtensionAnswer[0],
3450 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003451 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003452 };
3453
Artem Titov880fa812021-07-30 22:30:23 +02003454 // Since the default local extension id `f2_` uses has already been used by
3455 // `f1_` for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003456 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003457 kVideoRtpExtensionAnswer[0],
3458 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003459 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003460 };
3461
3462 const AudioContentDescription* updated_acd =
3463 GetFirstAudioContentDescription(updated_offer.get());
3464 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3465 updated_acd->rtp_header_extensions());
3466
3467 const VideoContentDescription* updated_vcd =
3468 GetFirstVideoContentDescription(updated_offer.get());
3469 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3470 updated_vcd->rtp_header_extensions());
3471}
3472
deadbeefa5b273a2015-08-20 17:30:13 -07003473// Verify that if the same RTP extension URI is used for audio and video, the
3474// same ID is used. Also verify that the ID isn't changed when creating an
3475// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003476TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003477 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003478 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003479
Markus Handell755c65d2020-06-24 01:06:10 +02003480 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3481 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003482 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003483
3484 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3485 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003486 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003487 kVideoRtpExtension3[0],
3488 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003489 };
3490
Yves Gerey665174f2018-06-19 15:03:05 +02003491 EXPECT_EQ(
3492 MAKE_VECTOR(kAudioRtpExtension3),
3493 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3494 EXPECT_EQ(
3495 MAKE_VECTOR(kExpectedVideoRtpExtension),
3496 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003497
3498 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003499 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003500 f1_.CreateOffer(opts, offer.get()));
3501
3502 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003503 GetFirstAudioContentDescription(updated_offer.get())
3504 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003505 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003506 GetFirstVideoContentDescription(updated_offer.get())
3507 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003508}
3509
jbauch5869f502017-06-29 12:31:36 -07003510// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3511TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3512 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003513 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003514
3515 f1_.set_enable_encrypted_rtp_header_extensions(true);
3516 f2_.set_enable_encrypted_rtp_header_extensions(true);
3517
Markus Handell755c65d2020-06-24 01:06:10 +02003518 SetAudioVideoRtpHeaderExtensions(
3519 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3520 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003521 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003522
Yves Gerey665174f2018-06-19 15:03:05 +02003523 EXPECT_EQ(
3524 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3525 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3526 EXPECT_EQ(
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003527 MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003528 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003529
3530 // Nothing should change when creating a new offer
3531 std::unique_ptr<SessionDescription> updated_offer(
3532 f1_.CreateOffer(opts, offer.get()));
3533
3534 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003535 GetFirstAudioContentDescription(updated_offer.get())
3536 ->rtp_header_extensions());
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003537 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003538 GetFirstVideoContentDescription(updated_offer.get())
3539 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003540}
3541
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003542TEST(MediaSessionDescription, CopySessionDescription) {
3543 SessionDescription source;
3544 cricket::ContentGroup group(cricket::CN_AUDIO);
3545 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003546 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003547 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003548 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3549 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003550 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003551 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003552 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003553 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3554 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003555 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003556
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003557 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003558 ASSERT_TRUE(copy.get() != NULL);
3559 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3560 const ContentInfo* ac = copy->GetContentByName("audio");
3561 const ContentInfo* vc = copy->GetContentByName("video");
3562 ASSERT_TRUE(ac != NULL);
3563 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003564 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003565 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003566 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3567 EXPECT_EQ(1u, acd->first_ssrc());
3568
Steve Anton5adfafd2017-12-20 16:34:00 -08003569 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003570 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003571 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3572 EXPECT_EQ(2u, vcd->first_ssrc());
3573}
3574
3575// The below TestTransportInfoXXX tests create different offers/answers, and
3576// ensure the TransportInfo in the SessionDescription matches what we expect.
3577TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3578 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003579 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3580 RtpTransceiverDirection::kRecvOnly, kActive,
3581 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003582 TestTransportInfo(true, options, false);
3583}
3584
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003585TEST_F(MediaSessionDescriptionFactoryTest,
3586 TestTransportInfoOfferIceRenomination) {
3587 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003588 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3589 RtpTransceiverDirection::kRecvOnly, kActive,
3590 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003591 options.media_description_options[0]
3592 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003593 TestTransportInfo(true, options, false);
3594}
3595
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003596TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3597 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003598 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3599 RtpTransceiverDirection::kRecvOnly, kActive,
3600 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003601 TestTransportInfo(true, options, true);
3602}
3603
3604TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3605 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003607 TestTransportInfo(true, options, false);
3608}
3609
3610TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003611 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003612 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003613 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003614 TestTransportInfo(true, options, true);
3615}
3616
3617TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3618 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003619 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003620 options.bundle_enabled = true;
3621 TestTransportInfo(true, options, false);
3622}
3623
3624TEST_F(MediaSessionDescriptionFactoryTest,
3625 TestTransportInfoOfferBundleCurrent) {
3626 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003627 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003628 options.bundle_enabled = true;
3629 TestTransportInfo(true, options, true);
3630}
3631
3632TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3633 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003634 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3635 RtpTransceiverDirection::kRecvOnly, kActive,
3636 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003637 TestTransportInfo(false, options, false);
3638}
3639
3640TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003641 TestTransportInfoAnswerIceRenomination) {
3642 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003643 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3644 RtpTransceiverDirection::kRecvOnly, kActive,
3645 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003646 options.media_description_options[0]
3647 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003648 TestTransportInfo(false, options, false);
3649}
3650
3651TEST_F(MediaSessionDescriptionFactoryTest,
3652 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003653 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003654 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3655 RtpTransceiverDirection::kRecvOnly, kActive,
3656 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003657 TestTransportInfo(false, options, true);
3658}
3659
3660TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3661 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003662 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003663 TestTransportInfo(false, options, false);
3664}
3665
3666TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003667 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003668 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003669 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003670 TestTransportInfo(false, options, true);
3671}
3672
3673TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3674 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003675 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003676 options.bundle_enabled = true;
3677 TestTransportInfo(false, options, false);
3678}
3679
3680TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003681 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003682 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003683 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003684 options.bundle_enabled = true;
3685 TestTransportInfo(false, options, true);
3686}
3687
Harald Alvestrand0d018412021-11-04 13:52:31 +00003688// Create an offer with bundle enabled and verify the crypto parameters are
3689// the common set of the available cryptos.
3690TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3691 TestCryptoWithBundle(true);
3692}
3693
3694// Create an answer with bundle enabled and verify the crypto parameters are
3695// the common set of the available cryptos.
3696TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3697 TestCryptoWithBundle(false);
3698}
3699
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003700// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3701// DTLS is not enabled locally.
3702TEST_F(MediaSessionDescriptionFactoryTest,
3703 TestOfferDtlsSavpfWithoutDtlsFailed) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003704 f1_.set_secure(SEC_ENABLED);
3705 f2_.set_secure(SEC_ENABLED);
3706 tdf1_.set_secure(SEC_DISABLED);
3707 tdf2_.set_secure(SEC_DISABLED);
3708
Steve Anton6fe1fba2018-12-11 10:15:23 -08003709 std::unique_ptr<SessionDescription> offer =
3710 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003711 ASSERT_TRUE(offer.get() != NULL);
3712 ContentInfo* offer_content = offer->GetContentByName("audio");
3713 ASSERT_TRUE(offer_content != NULL);
3714 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003715 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003716 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3717
Steve Anton6fe1fba2018-12-11 10:15:23 -08003718 std::unique_ptr<SessionDescription> answer =
3719 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003720 ASSERT_TRUE(answer != NULL);
3721 ContentInfo* answer_content = answer->GetContentByName("audio");
3722 ASSERT_TRUE(answer_content != NULL);
3723
3724 ASSERT_TRUE(answer_content->rejected);
3725}
3726
3727// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3728// UDP/TLS/RTP/SAVPF.
3729TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003730 f1_.set_secure(SEC_ENABLED);
3731 f2_.set_secure(SEC_ENABLED);
3732 tdf1_.set_secure(SEC_ENABLED);
3733 tdf2_.set_secure(SEC_ENABLED);
3734
Steve Anton6fe1fba2018-12-11 10:15:23 -08003735 std::unique_ptr<SessionDescription> offer =
3736 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003737 ASSERT_TRUE(offer.get() != NULL);
3738 ContentInfo* offer_content = offer->GetContentByName("audio");
3739 ASSERT_TRUE(offer_content != NULL);
3740 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003741 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003742 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3743
Steve Anton6fe1fba2018-12-11 10:15:23 -08003744 std::unique_ptr<SessionDescription> answer =
3745 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003746 ASSERT_TRUE(answer != NULL);
3747
3748 const ContentInfo* answer_content = answer->GetContentByName("audio");
3749 ASSERT_TRUE(answer_content != NULL);
3750 ASSERT_FALSE(answer_content->rejected);
3751
3752 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003753 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003754 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003755}
3756
Harald Alvestrand0d018412021-11-04 13:52:31 +00003757// Test that we include both SDES and DTLS in the offer, but only include SDES
3758// in the answer if DTLS isn't negotiated.
3759TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3760 f1_.set_secure(SEC_ENABLED);
3761 f2_.set_secure(SEC_ENABLED);
3762 tdf1_.set_secure(SEC_ENABLED);
3763 tdf2_.set_secure(SEC_DISABLED);
3764 MediaSessionOptions options;
3765 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3766 std::unique_ptr<SessionDescription> offer, answer;
3767 const cricket::MediaContentDescription* audio_media_desc;
3768 const cricket::MediaContentDescription* video_media_desc;
3769 const cricket::TransportDescription* audio_trans_desc;
3770 const cricket::TransportDescription* video_trans_desc;
3771
3772 // Generate an offer with SDES and DTLS support.
3773 offer = f1_.CreateOffer(options, NULL);
3774 ASSERT_TRUE(offer.get() != NULL);
3775
3776 audio_media_desc = offer->GetContentDescriptionByName("audio");
3777 ASSERT_TRUE(audio_media_desc != NULL);
3778 video_media_desc = offer->GetContentDescriptionByName("video");
3779 ASSERT_TRUE(video_media_desc != NULL);
3780 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3781 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3782
3783 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3784 ASSERT_TRUE(audio_trans_desc != NULL);
3785 video_trans_desc = offer->GetTransportDescriptionByName("video");
3786 ASSERT_TRUE(video_trans_desc != NULL);
3787 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3788 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3789
3790 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
3791 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3792 ASSERT_TRUE(answer.get() != NULL);
3793
3794 audio_media_desc = answer->GetContentDescriptionByName("audio");
3795 ASSERT_TRUE(audio_media_desc != NULL);
3796 video_media_desc = answer->GetContentDescriptionByName("video");
3797 ASSERT_TRUE(video_media_desc != NULL);
3798 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3799 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3800
3801 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3802 ASSERT_TRUE(audio_trans_desc != NULL);
3803 video_trans_desc = answer->GetTransportDescriptionByName("video");
3804 ASSERT_TRUE(video_trans_desc != NULL);
3805 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3806 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3807
3808 // Enable DTLS; the answer should now only have DTLS support.
3809 tdf2_.set_secure(SEC_ENABLED);
3810 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3811 ASSERT_TRUE(answer.get() != NULL);
3812
3813 audio_media_desc = answer->GetContentDescriptionByName("audio");
3814 ASSERT_TRUE(audio_media_desc != NULL);
3815 video_media_desc = answer->GetContentDescriptionByName("video");
3816 ASSERT_TRUE(video_media_desc != NULL);
3817 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3818 EXPECT_TRUE(video_media_desc->cryptos().empty());
3819 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3820 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
3821
3822 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3823 ASSERT_TRUE(audio_trans_desc != NULL);
3824 video_trans_desc = answer->GetTransportDescriptionByName("video");
3825 ASSERT_TRUE(video_trans_desc != NULL);
3826 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3827 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3828
3829 // Try creating offer again. DTLS enabled now, crypto's should be empty
3830 // in new offer.
3831 offer = f1_.CreateOffer(options, offer.get());
3832 ASSERT_TRUE(offer.get() != NULL);
3833 audio_media_desc = offer->GetContentDescriptionByName("audio");
3834 ASSERT_TRUE(audio_media_desc != NULL);
3835 video_media_desc = offer->GetContentDescriptionByName("video");
3836 ASSERT_TRUE(video_media_desc != NULL);
3837 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3838 EXPECT_TRUE(video_media_desc->cryptos().empty());
3839
3840 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3841 ASSERT_TRUE(audio_trans_desc != NULL);
3842 video_trans_desc = offer->GetTransportDescriptionByName("video");
3843 ASSERT_TRUE(video_trans_desc != NULL);
3844 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3845 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3846}
3847
3848// Test that an answer can't be created if cryptos are required but the offer is
3849// unsecure.
3850TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
3851 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
3852 f1_.set_secure(SEC_DISABLED);
3853 tdf1_.set_secure(SEC_DISABLED);
3854 f2_.set_secure(SEC_REQUIRED);
3855 tdf1_.set_secure(SEC_ENABLED);
3856
3857 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
3858 ASSERT_TRUE(offer.get() != NULL);
3859 std::unique_ptr<SessionDescription> answer =
3860 f2_.CreateAnswer(offer.get(), options, NULL);
3861 EXPECT_TRUE(answer.get() == NULL);
3862}
3863
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003864// Test that we accept a DTLS offer without SDES and create an appropriate
3865// answer.
3866TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003867 f1_.set_secure(SEC_DISABLED);
3868 f2_.set_secure(SEC_ENABLED);
3869 tdf1_.set_secure(SEC_ENABLED);
3870 tdf2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003871 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003872 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003873
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003874 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003875 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003876 ASSERT_TRUE(offer.get() != NULL);
3877
Harald Alvestrand0d018412021-11-04 13:52:31 +00003878 const AudioContentDescription* audio_offer =
3879 GetFirstAudioContentDescription(offer.get());
3880 ASSERT_TRUE(audio_offer->cryptos().empty());
3881 const VideoContentDescription* video_offer =
3882 GetFirstVideoContentDescription(offer.get());
3883 ASSERT_TRUE(video_offer->cryptos().empty());
3884
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003885 const cricket::TransportDescription* audio_offer_trans_desc =
3886 offer->GetTransportDescriptionByName("audio");
3887 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3888 const cricket::TransportDescription* video_offer_trans_desc =
3889 offer->GetTransportDescriptionByName("video");
3890 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003891
3892 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003893 std::unique_ptr<SessionDescription> answer =
3894 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003895 ASSERT_TRUE(answer.get() != NULL);
3896
3897 const cricket::TransportDescription* audio_answer_trans_desc =
3898 answer->GetTransportDescriptionByName("audio");
3899 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3900 const cricket::TransportDescription* video_answer_trans_desc =
3901 answer->GetTransportDescriptionByName("video");
3902 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003903}
3904
3905// Verifies if vad_enabled option is set to false, CN codecs are not present in
3906// offer or answer.
3907TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3908 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003909 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003910 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003911 ASSERT_TRUE(offer.get() != NULL);
3912 const ContentInfo* audio_content = offer->GetContentByName("audio");
3913 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3914
3915 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003916 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003917 ASSERT_TRUE(offer.get() != NULL);
3918 audio_content = offer->GetContentByName("audio");
3919 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003920 std::unique_ptr<SessionDescription> answer =
3921 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003922 ASSERT_TRUE(answer.get() != NULL);
3923 audio_content = answer->GetContentByName("audio");
3924 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3925}
deadbeef44f08192015-12-15 16:20:09 -08003926
zhihuang1c378ed2017-08-17 14:10:50 -07003927// Test that the generated MIDs match the existing offer.
3928TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003929 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003930 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3931 RtpTransceiverDirection::kRecvOnly, kActive,
3932 &opts);
3933 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3934 RtpTransceiverDirection::kRecvOnly, kActive,
3935 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003936 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3937 RtpTransceiverDirection::kSendRecv, kActive,
3938 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003939 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003941 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003942 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003943
deadbeef44f08192015-12-15 16:20:09 -08003944 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3945 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3946 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3947 ASSERT_TRUE(audio_content != nullptr);
3948 ASSERT_TRUE(video_content != nullptr);
3949 ASSERT_TRUE(data_content != nullptr);
3950 EXPECT_EQ("audio_modified", audio_content->name);
3951 EXPECT_EQ("video_modified", video_content->name);
3952 EXPECT_EQ("data_modified", data_content->name);
3953}
zhihuangcf5b37c2016-05-05 11:44:35 -07003954
zhihuang1c378ed2017-08-17 14:10:50 -07003955// The following tests verify that the unified plan SDP is supported.
3956// Test that we can create an offer with multiple media sections of same media
3957// type.
3958TEST_F(MediaSessionDescriptionFactoryTest,
3959 CreateOfferWithMultipleAVMediaSections) {
3960 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003961 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3962 RtpTransceiverDirection::kSendRecv, kActive,
3963 &opts);
3964 AttachSenderToMediaDescriptionOptions(
3965 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003966
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003967 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3968 RtpTransceiverDirection::kSendRecv, kActive,
3969 &opts);
3970 AttachSenderToMediaDescriptionOptions(
3971 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003972
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003973 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3974 RtpTransceiverDirection::kSendRecv, kActive,
3975 &opts);
3976 AttachSenderToMediaDescriptionOptions(
3977 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003978
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003979 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3980 RtpTransceiverDirection::kSendRecv, kActive,
3981 &opts);
3982 AttachSenderToMediaDescriptionOptions(
3983 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003984 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003985 ASSERT_TRUE(offer);
3986
3987 ASSERT_EQ(4u, offer->contents().size());
3988 EXPECT_FALSE(offer->contents()[0].rejected);
3989 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003990 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003991 ASSERT_EQ(1u, acd->streams().size());
3992 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003993 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003994
3995 EXPECT_FALSE(offer->contents()[1].rejected);
3996 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003997 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003998 ASSERT_EQ(1u, vcd->streams().size());
3999 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004000 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004001
4002 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004003 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004004 ASSERT_EQ(1u, acd->streams().size());
4005 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004006 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004007
4008 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004009 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004010 ASSERT_EQ(1u, vcd->streams().size());
4011 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004012 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004013}
4014
4015// Test that we can create an answer with multiple media sections of same media
4016// type.
4017TEST_F(MediaSessionDescriptionFactoryTest,
4018 CreateAnswerWithMultipleAVMediaSections) {
4019 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004020 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4021 RtpTransceiverDirection::kSendRecv, kActive,
4022 &opts);
4023 AttachSenderToMediaDescriptionOptions(
4024 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004025
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004026 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4027 RtpTransceiverDirection::kSendRecv, kActive,
4028 &opts);
4029 AttachSenderToMediaDescriptionOptions(
4030 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004031
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004032 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4033 RtpTransceiverDirection::kSendRecv, kActive,
4034 &opts);
4035 AttachSenderToMediaDescriptionOptions(
4036 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004037
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004038 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4039 RtpTransceiverDirection::kSendRecv, kActive,
4040 &opts);
4041 AttachSenderToMediaDescriptionOptions(
4042 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004043
Steve Anton6fe1fba2018-12-11 10:15:23 -08004044 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004045 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004046 std::unique_ptr<SessionDescription> answer =
4047 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004048
4049 ASSERT_EQ(4u, answer->contents().size());
4050 EXPECT_FALSE(answer->contents()[0].rejected);
4051 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004052 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004053 ASSERT_EQ(1u, acd->streams().size());
4054 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004055 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004056
4057 EXPECT_FALSE(answer->contents()[1].rejected);
4058 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004059 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004060 ASSERT_EQ(1u, vcd->streams().size());
4061 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004062 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004063
4064 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004065 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004066 ASSERT_EQ(1u, acd->streams().size());
4067 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004068 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004069
4070 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004071 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004072 ASSERT_EQ(1u, vcd->streams().size());
4073 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004074 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004075}
4076
4077// Test that the media section will be rejected in offer if the corresponding
4078// MediaDescriptionOptions is stopped by the offerer.
4079TEST_F(MediaSessionDescriptionFactoryTest,
4080 CreateOfferWithMediaSectionStoppedByOfferer) {
4081 // Create an offer with two audio sections and one of them is stopped.
4082 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004083 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4084 RtpTransceiverDirection::kSendRecv, kActive,
4085 &offer_opts);
4086 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4087 RtpTransceiverDirection::kInactive, kStopped,
4088 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004089 std::unique_ptr<SessionDescription> offer =
4090 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004091 ASSERT_TRUE(offer);
4092 ASSERT_EQ(2u, offer->contents().size());
4093 EXPECT_FALSE(offer->contents()[0].rejected);
4094 EXPECT_TRUE(offer->contents()[1].rejected);
4095}
4096
4097// Test that the media section will be rejected in answer if the corresponding
4098// MediaDescriptionOptions is stopped by the offerer.
4099TEST_F(MediaSessionDescriptionFactoryTest,
4100 CreateAnswerWithMediaSectionStoppedByOfferer) {
4101 // Create an offer with two audio sections and one of them is stopped.
4102 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004103 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4104 RtpTransceiverDirection::kSendRecv, kActive,
4105 &offer_opts);
4106 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4107 RtpTransceiverDirection::kInactive, kStopped,
4108 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004109 std::unique_ptr<SessionDescription> offer =
4110 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004111 ASSERT_TRUE(offer);
4112 ASSERT_EQ(2u, offer->contents().size());
4113 EXPECT_FALSE(offer->contents()[0].rejected);
4114 EXPECT_TRUE(offer->contents()[1].rejected);
4115
4116 // Create an answer based on the offer.
4117 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004118 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4119 RtpTransceiverDirection::kSendRecv, kActive,
4120 &answer_opts);
4121 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4122 RtpTransceiverDirection::kSendRecv, kActive,
4123 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004124 std::unique_ptr<SessionDescription> answer =
4125 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004126 ASSERT_EQ(2u, answer->contents().size());
4127 EXPECT_FALSE(answer->contents()[0].rejected);
4128 EXPECT_TRUE(answer->contents()[1].rejected);
4129}
4130
4131// Test that the media section will be rejected in answer if the corresponding
4132// MediaDescriptionOptions is stopped by the answerer.
4133TEST_F(MediaSessionDescriptionFactoryTest,
4134 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4135 // Create an offer with two audio sections.
4136 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004137 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4138 RtpTransceiverDirection::kSendRecv, kActive,
4139 &offer_opts);
4140 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4141 RtpTransceiverDirection::kSendRecv, kActive,
4142 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004143 std::unique_ptr<SessionDescription> offer =
4144 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004145 ASSERT_TRUE(offer);
4146 ASSERT_EQ(2u, offer->contents().size());
4147 ASSERT_FALSE(offer->contents()[0].rejected);
4148 ASSERT_FALSE(offer->contents()[1].rejected);
4149
4150 // The answerer rejects one of the audio sections.
4151 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004152 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4153 RtpTransceiverDirection::kSendRecv, kActive,
4154 &answer_opts);
4155 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4156 RtpTransceiverDirection::kInactive, kStopped,
4157 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004158 std::unique_ptr<SessionDescription> answer =
4159 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004160 ASSERT_EQ(2u, answer->contents().size());
4161 EXPECT_FALSE(answer->contents()[0].rejected);
4162 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004163
4164 // The TransportInfo of the rejected m= section is expected to be added in the
4165 // answer.
4166 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004167}
4168
4169// Test the generated media sections has the same order of the
4170// corresponding MediaDescriptionOptions.
4171TEST_F(MediaSessionDescriptionFactoryTest,
4172 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4173 MediaSessionOptions opts;
4174 // This tests put video section first because normally audio comes first by
4175 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004176 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4177 RtpTransceiverDirection::kSendRecv, kActive,
4178 &opts);
4179 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4180 RtpTransceiverDirection::kSendRecv, kActive,
4181 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004182 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004183
4184 ASSERT_TRUE(offer);
4185 ASSERT_EQ(2u, offer->contents().size());
4186 EXPECT_EQ("video", offer->contents()[0].name);
4187 EXPECT_EQ("audio", offer->contents()[1].name);
4188}
4189
4190// Test that different media sections using the same codec have same payload
4191// type.
4192TEST_F(MediaSessionDescriptionFactoryTest,
4193 PayloadTypesSharedByMediaSectionsOfSameType) {
4194 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004195 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4196 RtpTransceiverDirection::kSendRecv, kActive,
4197 &opts);
4198 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4199 RtpTransceiverDirection::kSendRecv, kActive,
4200 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004201 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004202 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004203 ASSERT_TRUE(offer);
4204 ASSERT_EQ(2u, offer->contents().size());
4205 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004206 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004207 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004208 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004209 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4210 ASSERT_EQ(2u, vcd1->codecs().size());
4211 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4212 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4213 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4214 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4215
4216 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004217 std::unique_ptr<SessionDescription> answer =
4218 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004219 ASSERT_TRUE(answer);
4220 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004221 vcd1 = answer->contents()[0].media_description()->as_video();
4222 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004223 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4224 ASSERT_EQ(1u, vcd1->codecs().size());
4225 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4226 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4227}
4228
4229// Test that the codec preference order per media section is respected in
4230// subsequent offer.
4231TEST_F(MediaSessionDescriptionFactoryTest,
4232 CreateOfferRespectsCodecPreferenceOrder) {
4233 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004234 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4235 RtpTransceiverDirection::kSendRecv, kActive,
4236 &opts);
4237 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4238 RtpTransceiverDirection::kSendRecv, kActive,
4239 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004240 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004241 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004242 ASSERT_TRUE(offer);
4243 ASSERT_EQ(2u, offer->contents().size());
4244 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004245 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004246 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004247 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004248 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4249 EXPECT_EQ(video_codecs, vcd1->codecs());
4250 EXPECT_EQ(video_codecs, vcd2->codecs());
4251
4252 // Change the codec preference of the first video section and create a
4253 // follow-up offer.
4254 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4255 vcd1->set_codecs(video_codecs_reverse);
4256 std::unique_ptr<SessionDescription> updated_offer(
4257 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004258 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4259 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004260 // The video codec preference order should be respected.
4261 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4262 EXPECT_EQ(video_codecs, vcd2->codecs());
4263}
4264
4265// Test that the codec preference order per media section is respected in
4266// the answer.
4267TEST_F(MediaSessionDescriptionFactoryTest,
4268 CreateAnswerRespectsCodecPreferenceOrder) {
4269 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004270 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4271 RtpTransceiverDirection::kSendRecv, kActive,
4272 &opts);
4273 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4274 RtpTransceiverDirection::kSendRecv, kActive,
4275 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004276 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004277 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004278 ASSERT_TRUE(offer);
4279 ASSERT_EQ(2u, offer->contents().size());
4280 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004281 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004282 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004283 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004284 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4285 EXPECT_EQ(video_codecs, vcd1->codecs());
4286 EXPECT_EQ(video_codecs, vcd2->codecs());
4287
4288 // Change the codec preference of the first video section and create an
4289 // answer.
4290 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4291 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004292 std::unique_ptr<SessionDescription> answer =
4293 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004294 vcd1 = answer->contents()[0].media_description()->as_video();
4295 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004296 // The video codec preference order should be respected.
4297 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4298 EXPECT_EQ(video_codecs, vcd2->codecs());
4299}
4300
Zhi Huang6f367472017-11-22 13:20:02 -08004301// Test that when creating an answer, the codecs use local parameters instead of
4302// the remote ones.
4303TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4304 const std::string audio_param_name = "audio_param";
4305 const std::string audio_value1 = "audio_v1";
4306 const std::string audio_value2 = "audio_v2";
4307 const std::string video_param_name = "video_param";
4308 const std::string video_value1 = "video_v1";
4309 const std::string video_value2 = "video_v2";
4310
4311 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4312 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4313 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4314 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4315
4316 // Set the parameters for codecs.
4317 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4318 video_codecs1[0].SetParam(video_param_name, video_value1);
4319 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4320 video_codecs2[0].SetParam(video_param_name, video_value2);
4321
4322 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004323 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004324 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004325 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004326
4327 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004328 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4329 RtpTransceiverDirection::kSendRecv, kActive,
4330 &opts);
4331 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4332 RtpTransceiverDirection::kSendRecv, kActive,
4333 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004334
Steve Anton6fe1fba2018-12-11 10:15:23 -08004335 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004336 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004337 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4338 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004339 std::string value;
4340 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4341 EXPECT_EQ(audio_value1, value);
4342 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4343 EXPECT_EQ(video_value1, value);
4344
Steve Anton6fe1fba2018-12-11 10:15:23 -08004345 std::unique_ptr<SessionDescription> answer =
4346 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004347 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004348 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4349 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004350 // Use the parameters from the local codecs.
4351 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4352 EXPECT_EQ(audio_value2, value);
4353 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4354 EXPECT_EQ(video_value2, value);
4355}
4356
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004357// Test that matching packetization-mode is part of the criteria for matching
4358// H264 codecs (in addition to profile-level-id). Previously, this was not the
4359// case, so the first H264 codec with the same profile-level-id would match and
4360// the payload type in the answer would be incorrect.
4361// This is a regression test for bugs.webrtc.org/8808
4362TEST_F(MediaSessionDescriptionFactoryTest,
4363 H264MatchCriteriaIncludesPacketizationMode) {
4364 // Create two H264 codecs with the same profile level ID and different
4365 // packetization modes.
4366 VideoCodec h264_pm0(96, "H264");
4367 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4368 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4369 VideoCodec h264_pm1(97, "H264");
4370 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4371 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4372
4373 // Offerer will send both codecs, answerer should choose the one with matching
4374 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004375 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4376 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004377
4378 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004379 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4380 RtpTransceiverDirection::kSendRecv, kActive,
4381 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004382
Steve Anton6fe1fba2018-12-11 10:15:23 -08004383 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004384 ASSERT_TRUE(offer);
4385
Steve Anton6fe1fba2018-12-11 10:15:23 -08004386 std::unique_ptr<SessionDescription> answer =
4387 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004388 ASSERT_TRUE(answer);
4389
4390 // Answer should have one negotiated codec with packetization-mode=1 using the
4391 // offered payload type.
4392 ASSERT_EQ(1u, answer->contents().size());
4393 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4394 ASSERT_EQ(1u, answer_vcd->codecs().size());
4395 auto answer_codec = answer_vcd->codecs()[0];
4396 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4397}
4398
zhihuangcf5b37c2016-05-05 11:44:35 -07004399class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4400 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004401 MediaProtocolTest()
Jonas Orelanded99dae2022-03-09 09:28:10 +01004402 : tdf1_(field_trials_),
4403 tdf2_(field_trials_),
4404 f1_(&tdf1_, &ssrc_generator1),
4405 f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004406 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4407 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004408 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4409 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -07004410 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4411 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004412 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4413 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004414 f1_.set_secure(SEC_ENABLED);
4415 f2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004416 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004417 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004418 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004419 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004420 tdf1_.set_secure(SEC_ENABLED);
4421 tdf2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004422 }
4423
4424 protected:
Jonas Orelanded99dae2022-03-09 09:28:10 +01004425 webrtc::test::ScopedKeyValueConfig field_trials_;
zhihuangcf5b37c2016-05-05 11:44:35 -07004426 TransportDescriptionFactory tdf1_;
4427 TransportDescriptionFactory tdf2_;
Jonas Orelanded99dae2022-03-09 09:28:10 +01004428 MediaSessionDescriptionFactory f1_;
4429 MediaSessionDescriptionFactory f2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004430 UniqueRandomIdGenerator ssrc_generator1;
4431 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004432};
4433
4434TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4435 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004436 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004437 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004438 ASSERT_TRUE(offer.get() != nullptr);
4439 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004440 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004441 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004442 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004443 std::unique_ptr<SessionDescription> answer =
4444 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004445 const ContentInfo* ac = answer->GetContentByName("audio");
4446 const ContentInfo* vc = answer->GetContentByName("video");
4447 ASSERT_TRUE(ac != nullptr);
4448 ASSERT_TRUE(vc != nullptr);
4449 EXPECT_FALSE(ac->rejected); // the offer is accepted
4450 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004451 const AudioContentDescription* acd = ac->media_description()->as_audio();
4452 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004453 EXPECT_EQ(GetParam(), acd->protocol());
4454 EXPECT_EQ(GetParam(), vcd->protocol());
4455}
4456
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004457INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4458 MediaProtocolTest,
4459 ::testing::ValuesIn(kMediaProtocols));
4460INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4461 MediaProtocolTest,
4462 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004463
4464TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004465 webrtc::test::ScopedKeyValueConfig field_trials;
4466 TransportDescriptionFactory tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004467 UniqueRandomIdGenerator ssrc_generator;
4468 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004469 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4470 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4471
4472 // The merged list of codecs should contain any send codecs that are also
Niels Möllerbe74b802022-03-18 14:10:15 +01004473 // nominally in the receive codecs list. Payload types should be picked from
ossu075af922016-06-14 03:29:38 -07004474 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4475 // (set to 1). This equals what happens when the send codecs are used in an
4476 // offer and the receive codecs are used in the following answer.
4477 const std::vector<AudioCodec> sendrecv_codecs =
4478 MAKE_VECTOR(kAudioCodecsAnswer);
4479 const std::vector<AudioCodec> no_codecs;
4480
4481 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4482 << "Please don't change shared test data!";
4483 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4484 << "Please don't change shared test data!";
4485 // Alter iLBC send codec to have zero channels, to test that that is handled
4486 // properly.
4487 send_codecs[1].channels = 0;
4488
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004489 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004490 // are handled properly.
4491 recv_codecs[2].name = "ilbc";
4492
4493 // Test proper merge
4494 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004495 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4496 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4497 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004498
4499 // Test empty send codecs list
4500 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004501 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4502 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4503 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004504
4505 // Test empty recv codecs list
4506 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004507 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4508 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4509 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004510
4511 // Test all empty codec lists
4512 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004513 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4514 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4515 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004516}
4517
4518namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004519// Compare the two vectors of codecs ignoring the payload type.
4520template <class Codec>
4521bool CodecsMatch(const std::vector<Codec>& codecs1,
Jonas Oreland4476b822022-03-10 15:21:28 +01004522 const std::vector<Codec>& codecs2,
Jonas Orelande62c2f22022-03-29 11:04:48 +02004523 const webrtc::FieldTrialsView* field_trials) {
zhihuang1c378ed2017-08-17 14:10:50 -07004524 if (codecs1.size() != codecs2.size()) {
4525 return false;
4526 }
4527
4528 for (size_t i = 0; i < codecs1.size(); ++i) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004529 if (!codecs1[i].Matches(codecs2[i], field_trials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07004530 return false;
4531 }
4532 }
4533 return true;
4534}
4535
Steve Anton4e70a722017-11-28 14:57:10 -08004536void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004537 webrtc::test::ScopedKeyValueConfig field_trials;
4538 TransportDescriptionFactory tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004539 UniqueRandomIdGenerator ssrc_generator;
4540 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004541 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4542 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4543 const std::vector<AudioCodec> sendrecv_codecs =
4544 MAKE_VECTOR(kAudioCodecsAnswer);
4545 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004546
4547 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004548 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4549 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004550
Steve Anton4e70a722017-11-28 14:57:10 -08004551 if (direction == RtpTransceiverDirection::kSendRecv ||
4552 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004553 AttachSenderToMediaDescriptionOptions(
4554 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004555 }
ossu075af922016-06-14 03:29:38 -07004556
Steve Anton6fe1fba2018-12-11 10:15:23 -08004557 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004558 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004559 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004560
4561 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004562 // that the codecs put in are right. This happens when we neither want to
4563 // send nor receive audio. The checks are still in place if at some point
4564 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004565 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004566 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004567 // sendrecv and inactive should both present lists as if the channel was
4568 // to be used for sending and receiving. Inactive essentially means it
4569 // might eventually be used anything, but we don't know more at this
4570 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004571 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004572 EXPECT_TRUE(
4573 CodecsMatch<AudioCodec>(send_codecs, acd->codecs(), &field_trials));
Steve Anton4e70a722017-11-28 14:57:10 -08004574 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004575 EXPECT_TRUE(
4576 CodecsMatch<AudioCodec>(recv_codecs, acd->codecs(), &field_trials));
ossu075af922016-06-14 03:29:38 -07004577 } else {
Jonas Oreland4476b822022-03-10 15:21:28 +01004578 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs(),
4579 &field_trials));
ossu075af922016-06-14 03:29:38 -07004580 }
4581 }
4582}
4583
4584static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004585 AudioCodec(0, "codec0", 16000, -1, 1),
4586 AudioCodec(1, "codec1", 8000, 13300, 1),
4587 AudioCodec(2, "codec2", 8000, 64000, 1),
4588 AudioCodec(3, "codec3", 8000, 64000, 1),
4589 AudioCodec(4, "codec4", 8000, 0, 2),
4590 AudioCodec(5, "codec5", 32000, 0, 1),
4591 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004592
zhihuang1c378ed2017-08-17 14:10:50 -07004593/* The codecs groups below are chosen as per the matrix below. The objective
4594 * is to have different sets of codecs in the inputs, to get unique sets of
4595 * codecs after negotiation, depending on offer and answer communication
4596 * directions. One-way directions in the offer should either result in the
4597 * opposite direction in the answer, or an inactive answer. Regardless, the
4598 * choice of codecs should be as if the answer contained the opposite
4599 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004600 *
4601 * | Offer | Answer | Result
4602 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4603 * 0 | x - - | - x - | x - - - -
4604 * 1 | x x x | - x - | x - - x -
4605 * 2 | - x - | x - - | - x - - -
4606 * 3 | x x x | x - - | - x x - -
4607 * 4 | - x - | x x x | - x - - -
4608 * 5 | x - - | x x x | x - - - -
4609 * 6 | x x x | x x x | x x x x x
4610 */
4611// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004612static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4613static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004614// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4615// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004616static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4617static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004618// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004619static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4620static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4621static const int kResultSendrecv_SendCodecs[] = {3, 6};
4622static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4623static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004624
4625template <typename T, int IDXS>
4626std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4627 std::vector<T> out;
4628 out.reserve(IDXS);
4629 for (int idx : indices)
4630 out.push_back(array[idx]);
4631
4632 return out;
4633}
4634
Steve Anton4e70a722017-11-28 14:57:10 -08004635void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4636 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004637 bool add_legacy_stream) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004638 webrtc::test::ScopedKeyValueConfig field_trials;
4639 TransportDescriptionFactory offer_tdf(field_trials);
4640 TransportDescriptionFactory answer_tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004641 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4642 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4643 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
Jonas Orelanded99dae2022-03-09 09:28:10 +01004644
ossu075af922016-06-14 03:29:38 -07004645 offer_factory.set_audio_codecs(
4646 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4647 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4648 answer_factory.set_audio_codecs(
4649 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4650 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4651
ossu075af922016-06-14 03:29:38 -07004652 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004653 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4654 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004655
Steve Anton4e70a722017-11-28 14:57:10 -08004656 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004657 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4658 kAudioTrack1, {kMediaStream1}, 1,
4659 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004660 }
4661
Steve Anton6fe1fba2018-12-11 10:15:23 -08004662 std::unique_ptr<SessionDescription> offer =
4663 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004664 ASSERT_TRUE(offer.get() != NULL);
4665
4666 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004667 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4668 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004669
Steve Anton4e70a722017-11-28 14:57:10 -08004670 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004671 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4672 kAudioTrack1, {kMediaStream1}, 1,
4673 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004674 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004675 std::unique_ptr<SessionDescription> answer =
4676 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004677 const ContentInfo* ac = answer->GetContentByName("audio");
4678
zhihuang1c378ed2017-08-17 14:10:50 -07004679 // If the factory didn't add any audio content to the answer, we cannot
4680 // check that the codecs put in are right. This happens when we neither want
4681 // to send nor receive audio. The checks are still in place if at some point
4682 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004683 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004684 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4685 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004686
ossu075af922016-06-14 03:29:38 -07004687 std::vector<AudioCodec> target_codecs;
4688 // For offers with sendrecv or inactive, we should never reply with more
4689 // codecs than offered, with these codec sets.
4690 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004691 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004692 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4693 kResultSendrecv_SendrecvCodecs);
4694 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004695 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004696 target_codecs =
4697 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004698 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004699 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004700 target_codecs =
4701 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004702 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004703 case RtpTransceiverDirection::kSendRecv:
4704 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004705 target_codecs =
4706 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004707 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004708 target_codecs =
4709 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004710 } else {
4711 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4712 kResultSendrecv_SendrecvCodecs);
4713 }
4714 break;
Harald Alvestrand6060df52020-08-11 09:54:02 +02004715 case RtpTransceiverDirection::kStopped:
4716 // This does not happen in any current test.
Artem Titovd3251962021-11-15 16:57:07 +01004717 RTC_DCHECK_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004718 }
4719
zhihuang1c378ed2017-08-17 14:10:50 -07004720 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004721 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004722 bool first = true;
4723 os << "{";
4724 for (const auto& c : codecs) {
4725 os << (first ? " " : ", ") << c.id;
4726 first = false;
4727 }
4728 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004729 return os.Release();
ossu075af922016-06-14 03:29:38 -07004730 };
4731
4732 EXPECT_TRUE(acd->codecs() == target_codecs)
4733 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004734 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4735 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004736 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004737 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4738 << "; got: "
4739 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004740 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004741 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004742 << "Only inactive offers are allowed to not generate any audio "
4743 "content";
ossu075af922016-06-14 03:29:38 -07004744 }
4745}
brandtr03d5fb12016-11-22 03:37:59 -08004746
4747} // namespace
ossu075af922016-06-14 03:29:38 -07004748
4749class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004750 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004751
4752TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004753 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004754}
4755
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004756INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4757 AudioCodecsOfferTest,
4758 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4759 RtpTransceiverDirection::kRecvOnly,
4760 RtpTransceiverDirection::kSendRecv,
4761 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004762
4763class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004764 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4765 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004766 bool>> {};
ossu075af922016-06-14 03:29:38 -07004767
4768TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004769 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4770 ::testing::get<1>(GetParam()),
4771 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004772}
4773
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004774INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004775 MediaSessionDescriptionFactoryTest,
4776 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004777 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4778 RtpTransceiverDirection::kRecvOnly,
4779 RtpTransceiverDirection::kSendRecv,
4780 RtpTransceiverDirection::kInactive),
4781 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4782 RtpTransceiverDirection::kRecvOnly,
4783 RtpTransceiverDirection::kSendRecv,
4784 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004785 ::testing::Bool()));