blob: 6bc842d22252fbf0f14657b78dcee3b2fc346640 [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"
Philipp Hanckefedc7ab2020-11-17 21:59:12 +010046#include "test/field_trial.h"
Steve Antone38a5a12018-11-21 16:05:15 -080047#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000048#include "test/gtest.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()
434 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700435 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
436 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200437 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
438 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -0700439 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
440 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200441 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
442 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000443 tdf1_.set_certificate(rtc::RTCCertificate::Create(
444 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
445 tdf2_.set_certificate(rtc::RTCCertificate::Create(
446 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000447 }
448
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000449 // Create a video StreamParamsVec object with:
450 // - one video stream with 3 simulcast streams and FEC,
451 StreamParamsVec CreateComplexVideoStreamParamsVec() {
452 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
453 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
454 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
455 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
456
457 std::vector<SsrcGroup> ssrc_groups;
458 ssrc_groups.push_back(sim_group);
459 ssrc_groups.push_back(fec_group1);
460 ssrc_groups.push_back(fec_group2);
461 ssrc_groups.push_back(fec_group3);
462
463 StreamParams simulcast_params;
464 simulcast_params.id = kVideoTrack1;
465 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
466 simulcast_params.ssrc_groups = ssrc_groups;
467 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800468 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000469
470 StreamParamsVec video_streams;
471 video_streams.push_back(simulcast_params);
472
473 return video_streams;
474 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475
Harald Alvestrand0d018412021-11-04 13:52:31 +0000476 bool CompareCryptoParams(const CryptoParamsVec& c1,
477 const CryptoParamsVec& c2) {
478 if (c1.size() != c2.size())
479 return false;
480 for (size_t i = 0; i < c1.size(); ++i)
481 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
482 c1[i].key_params != c2[i].key_params ||
483 c1[i].session_params != c2[i].session_params)
484 return false;
485 return true;
486 }
487
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700488 // Returns true if the transport info contains "renomination" as an
489 // ICE option.
490 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800491 return absl::c_linear_search(transport_info->description.transport_options,
492 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700493 }
494
zhihuang1c378ed2017-08-17 14:10:50 -0700495 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700496 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497 bool has_current_desc) {
498 const std::string current_audio_ufrag = "current_audio_ufrag";
499 const std::string current_audio_pwd = "current_audio_pwd";
500 const std::string current_video_ufrag = "current_video_ufrag";
501 const std::string current_video_pwd = "current_video_pwd";
502 const std::string current_data_ufrag = "current_data_ufrag";
503 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800504 std::unique_ptr<SessionDescription> current_desc;
505 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200507 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800508 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200509 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800510 TransportDescription(current_audio_ufrag, current_audio_pwd)));
511 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200512 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800513 TransportDescription(current_video_ufrag, current_video_pwd)));
514 current_desc->AddTransportInfo(TransportInfo(
515 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000516 }
517 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800518 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 } else {
kwiberg31022942016-03-11 14:18:21 -0800520 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800521 offer = f1_.CreateOffer(options, NULL);
522 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000523 }
524 ASSERT_TRUE(desc.get() != NULL);
525 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000526 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000527 EXPECT_TRUE(ti_audio != NULL);
528 if (has_current_desc) {
529 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
530 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
531 } else {
532 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
533 ti_audio->description.ice_ufrag.size());
534 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
535 ti_audio->description.ice_pwd.size());
536 }
zhihuang1c378ed2017-08-17 14:10:50 -0700537 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700538 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700539 EXPECT_EQ(
540 media_desc_options_it->transport_options.enable_ice_renomination,
541 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000542 } else {
543 EXPECT_TRUE(ti_audio == NULL);
544 }
545 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000546 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700548 auto media_desc_options_it =
549 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 if (options.bundle_enabled) {
551 EXPECT_EQ(ti_audio->description.ice_ufrag,
552 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200553 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 } else {
555 if (has_current_desc) {
556 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
557 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
558 } else {
559 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
560 ti_video->description.ice_ufrag.size());
561 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
562 ti_video->description.ice_pwd.size());
563 }
564 }
zhihuang1c378ed2017-08-17 14:10:50 -0700565 EXPECT_EQ(
566 media_desc_options_it->transport_options.enable_ice_renomination,
567 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 } else {
569 EXPECT_TRUE(ti_video == NULL);
570 }
571 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
572 if (options.has_data()) {
573 EXPECT_TRUE(ti_data != NULL);
574 if (options.bundle_enabled) {
575 EXPECT_EQ(ti_audio->description.ice_ufrag,
576 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200577 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578 } else {
579 if (has_current_desc) {
580 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
581 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
582 } else {
583 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
584 ti_data->description.ice_ufrag.size());
585 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
586 ti_data->description.ice_pwd.size());
587 }
588 }
zhihuang1c378ed2017-08-17 14:10:50 -0700589 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700590 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700591 EXPECT_EQ(
592 media_desc_options_it->transport_options.enable_ice_renomination,
593 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700594
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700596 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 }
598 }
599
Harald Alvestrand0d018412021-11-04 13:52:31 +0000600 void TestCryptoWithBundle(bool offer) {
601 f1_.set_secure(SEC_ENABLED);
602 MediaSessionOptions options;
603 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
604 std::unique_ptr<SessionDescription> ref_desc;
605 std::unique_ptr<SessionDescription> desc;
606 if (offer) {
607 options.bundle_enabled = false;
608 ref_desc = f1_.CreateOffer(options, NULL);
609 options.bundle_enabled = true;
610 desc = f1_.CreateOffer(options, ref_desc.get());
611 } else {
612 options.bundle_enabled = true;
613 ref_desc = f1_.CreateOffer(options, NULL);
614 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
615 }
616 ASSERT_TRUE(desc);
617 const cricket::MediaContentDescription* audio_media_desc =
618 desc->GetContentDescriptionByName("audio");
619 ASSERT_TRUE(audio_media_desc);
620 const cricket::MediaContentDescription* video_media_desc =
621 desc->GetContentDescriptionByName("video");
622 ASSERT_TRUE(video_media_desc);
623 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
624 video_media_desc->cryptos()));
625 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
626 EXPECT_EQ(kDefaultSrtpCryptoSuite,
627 audio_media_desc->cryptos()[0].cipher_suite);
628
629 // Verify the selected crypto is one from the reference audio
630 // media content.
631 const cricket::MediaContentDescription* ref_audio_media_desc =
632 ref_desc->GetContentDescriptionByName("audio");
633 bool found = false;
634 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
635 if (ref_audio_media_desc->cryptos()[i].Matches(
636 audio_media_desc->cryptos()[0])) {
637 found = true;
638 break;
639 }
640 }
641 EXPECT_TRUE(found);
642 }
643
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 // This test that the audio and video media direction is set to
Artem Titov880fa812021-07-30 22:30:23 +0200645 // `expected_direction_in_answer` in an answer if the offer direction is set
646 // to `direction_in_offer` and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800648 RtpTransceiverDirection direction_in_offer,
649 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700650 MediaSessionOptions offer_opts;
651 AddAudioVideoSections(direction_in_offer, &offer_opts);
652
Steve Anton6fe1fba2018-12-11 10:15:23 -0800653 std::unique_ptr<SessionDescription> offer =
654 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700656 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700658 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660
zhihuang1c378ed2017-08-17 14:10:50 -0700661 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800662 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800663 std::unique_ptr<SessionDescription> answer =
664 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 const AudioContentDescription* acd_answer =
666 GetFirstAudioContentDescription(answer.get());
667 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
668 const VideoContentDescription* vcd_answer =
669 GetFirstVideoContentDescription(answer.get());
670 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
671 }
672
673 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800674 RTC_DCHECK(content);
675 RTC_CHECK(content->media_description());
676 const cricket::AudioContentDescription* audio_desc =
677 content->media_description()->as_audio();
678 RTC_CHECK(audio_desc);
679 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
680 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000681 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800682 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683 }
684 return true;
685 }
686
Harald Alvestrand0d018412021-11-04 13:52:31 +0000687 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
688 MediaSessionOptions offer_opts;
689 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
690 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
691
692 MediaSessionOptions answer_opts;
693 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
694 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
695
696 f1_.set_secure(SEC_ENABLED);
697 f2_.set_secure(SEC_ENABLED);
698 std::unique_ptr<SessionDescription> offer =
699 f1_.CreateOffer(offer_opts, NULL);
700 ASSERT_TRUE(offer.get() != NULL);
701 if (gcm_offer && gcm_answer) {
702 for (cricket::ContentInfo& content : offer->contents()) {
703 auto cryptos = content.media_description()->cryptos();
704 PreferGcmCryptoParameters(&cryptos);
705 content.media_description()->set_cryptos(cryptos);
706 }
707 }
708 std::unique_ptr<SessionDescription> answer =
709 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
710 const ContentInfo* ac = answer->GetContentByName("audio");
711 const ContentInfo* vc = answer->GetContentByName("video");
712 ASSERT_TRUE(ac != NULL);
713 ASSERT_TRUE(vc != NULL);
714 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
715 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
716 const AudioContentDescription* acd = ac->media_description()->as_audio();
717 const VideoContentDescription* vcd = vc->media_description()->as_video();
718 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
719 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
720 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
721 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
722 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
723 if (gcm_offer && gcm_answer) {
724 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
725 } else {
726 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
727 }
728 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
729 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
730 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
731 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
732 if (gcm_offer && gcm_answer) {
733 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
734 } else {
735 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
736 }
737 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
738 }
739
Johannes Kronce8e8672019-02-22 13:06:44 +0100740 void TestTransportSequenceNumberNegotiation(
741 const cricket::RtpHeaderExtensions& local,
742 const cricket::RtpHeaderExtensions& offered,
743 const cricket::RtpHeaderExtensions& expectedAnswer) {
744 MediaSessionOptions opts;
745 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +0200746 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100747 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
748 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +0200749 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100750 std::unique_ptr<SessionDescription> answer =
751 f2_.CreateAnswer(offer.get(), opts, NULL);
752
753 EXPECT_EQ(
754 expectedAnswer,
755 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
756 EXPECT_EQ(
757 expectedAnswer,
758 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
759 }
760
Markus Handell755c65d2020-06-24 01:06:10 +0200761 std::vector<webrtc::RtpHeaderExtensionCapability>
762 HeaderExtensionCapabilitiesFromRtpExtensions(
763 cricket::RtpHeaderExtensions extensions) {
764 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
765 for (const auto& extension : extensions) {
766 webrtc::RtpHeaderExtensionCapability capability(
767 extension.uri, extension.id,
768 webrtc::RtpTransceiverDirection::kSendRecv);
769 capabilities.push_back(capability);
770 }
771 return capabilities;
772 }
773
774 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
775 cricket::RtpHeaderExtensions video_exts,
776 MediaSessionOptions* opts) {
777 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
778 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
779 for (auto& entry : opts->media_description_options) {
780 switch (entry.type) {
781 case MEDIA_TYPE_AUDIO:
782 entry.header_extensions = audio_caps;
783 break;
784 case MEDIA_TYPE_VIDEO:
785 entry.header_extensions = video_caps;
786 break;
787 default:
788 break;
789 }
790 }
791 }
792
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800794 UniqueRandomIdGenerator ssrc_generator1;
795 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 MediaSessionDescriptionFactory f1_;
797 MediaSessionDescriptionFactory f2_;
798 TransportDescriptionFactory tdf1_;
799 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800};
801
802// Create a typical audio offer, and ensure it matches what we expect.
803TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000804 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800805 std::unique_ptr<SessionDescription> offer =
806 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 ASSERT_TRUE(offer.get() != NULL);
808 const ContentInfo* ac = offer->GetContentByName("audio");
809 const ContentInfo* vc = offer->GetContentByName("video");
810 ASSERT_TRUE(ac != NULL);
811 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800812 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800813 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700815 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700816 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000817 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
818 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000819 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
820 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821}
822
823// Create a typical video offer, and ensure it matches what we expect.
824TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
825 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800826 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000827 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800828 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829 ASSERT_TRUE(offer.get() != NULL);
830 const ContentInfo* ac = offer->GetContentByName("audio");
831 const ContentInfo* vc = offer->GetContentByName("video");
832 ASSERT_TRUE(ac != NULL);
833 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800834 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
835 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800836 const AudioContentDescription* acd = ac->media_description()->as_audio();
837 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700839 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700840 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000841 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
842 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000843 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
844 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200846 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700847 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
849 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000850 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
851 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852}
853
854// Test creating an offer with bundle where the Codecs have the same dynamic
855// RTP playlod type. The test verifies that the offer don't contain the
856// duplicate RTP payload types.
857TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200858 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700859 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861
862 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800863 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800865 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 const VideoContentDescription* vcd =
867 GetFirstVideoContentDescription(offer.get());
868 const AudioContentDescription* acd =
869 GetFirstAudioContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 ASSERT_TRUE(NULL != vcd);
871 ASSERT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
874 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000875}
876
zhihuang1c378ed2017-08-17 14:10:50 -0700877// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000878// after an audio only session has been negotiated.
879TEST_F(MediaSessionDescriptionFactoryTest,
880 TestCreateUpdatedVideoOfferWithBundle) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000881 f1_.set_secure(SEC_ENABLED);
882 f2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800884 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
885 RtpTransceiverDirection::kRecvOnly, kActive,
886 &opts);
887 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
888 RtpTransceiverDirection::kInactive, kStopped,
889 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000890 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800891 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
892 std::unique_ptr<SessionDescription> answer =
893 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894
895 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800896 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800898 std::unique_ptr<SessionDescription> updated_offer(
899 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900
901 const AudioContentDescription* acd =
902 GetFirstAudioContentDescription(updated_offer.get());
903 const VideoContentDescription* vcd =
904 GetFirstVideoContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905 EXPECT_TRUE(NULL != vcd);
906 EXPECT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907
Harald Alvestrand0d018412021-11-04 13:52:31 +0000908 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
909 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
910 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
911 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000912}
913
wu@webrtc.org78187522013-10-07 23:32:02 +0000914// Create an SCTP data offer with bundle without error.
915TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
916 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000917 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200918 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000919 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800920 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000921 EXPECT_TRUE(offer.get() != NULL);
922 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000923 auto dcd = GetFirstSctpDataContentDescription(offer.get());
924 ASSERT_TRUE(dcd);
925 // Since this transport is insecure, the protocol should be "SCTP".
926 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
927}
928
929// Create an SCTP data offer with bundle without error.
930TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
931 MediaSessionOptions opts;
932 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200933 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000934 f1_.set_secure(SEC_ENABLED);
935 tdf1_.set_secure(SEC_ENABLED);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000936 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
937 EXPECT_TRUE(offer.get() != NULL);
938 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
939 auto dcd = GetFirstSctpDataContentDescription(offer.get());
940 ASSERT_TRUE(dcd);
941 // The protocol should now be "UDP/DTLS/SCTP"
942 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000943}
944
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000945// Test creating an sctp data channel from an already generated offer.
946TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
947 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000948 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200949 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000950 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800951 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000952 ASSERT_TRUE(offer1.get() != NULL);
953 const ContentInfo* data = offer1->GetContentByName("data");
954 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800955 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000956
kwiberg31022942016-03-11 14:18:21 -0800957 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000958 f1_.CreateOffer(opts, offer1.get()));
959 data = offer2->GetContentByName("data");
960 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800961 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000962}
963
Steve Anton2bed3972019-01-04 17:04:30 -0800964// Test that if BUNDLE is enabled and all media sections are rejected then the
965// BUNDLE group is not present in the re-offer.
966TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
967 MediaSessionOptions opts;
968 opts.bundle_enabled = true;
969 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
970 RtpTransceiverDirection::kSendRecv, kActive,
971 &opts);
972 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
973
974 opts.media_description_options[0].stopped = true;
975 std::unique_ptr<SessionDescription> reoffer =
976 f1_.CreateOffer(opts, offer.get());
977
978 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
979}
980
981// Test that if BUNDLE is enabled and the remote re-offer does not include a
982// BUNDLE group since all media sections are rejected, then the re-answer also
983// does not include a BUNDLE group.
984TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
985 MediaSessionOptions opts;
986 opts.bundle_enabled = true;
987 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
988 RtpTransceiverDirection::kSendRecv, kActive,
989 &opts);
990 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
991 std::unique_ptr<SessionDescription> answer =
992 f2_.CreateAnswer(offer.get(), opts, nullptr);
993
994 opts.media_description_options[0].stopped = true;
995 std::unique_ptr<SessionDescription> reoffer =
996 f1_.CreateOffer(opts, offer.get());
997 std::unique_ptr<SessionDescription> reanswer =
998 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
999
1000 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1001}
1002
1003// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1004// was rejected then the new offerer-tagged media section is the non-rejected
1005// media section.
1006TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1007 MediaSessionOptions opts;
1008 opts.bundle_enabled = true;
1009 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1010 RtpTransceiverDirection::kSendRecv, kActive,
1011 &opts);
1012 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1013
1014 // Reject the audio m= section and add a video m= section.
1015 opts.media_description_options[0].stopped = true;
1016 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1017 RtpTransceiverDirection::kSendRecv, kActive,
1018 &opts);
1019 std::unique_ptr<SessionDescription> reoffer =
1020 f1_.CreateOffer(opts, offer.get());
1021
1022 const cricket::ContentGroup* bundle_group =
1023 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1024 ASSERT_TRUE(bundle_group);
1025 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1026 EXPECT_TRUE(bundle_group->HasContentName("video"));
1027}
1028
1029// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1030// was rejected and a new media section is added, then the re-answer BUNDLE
1031// group will contain only the non-rejected media section.
1032TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1033 MediaSessionOptions opts;
1034 opts.bundle_enabled = true;
1035 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1036 RtpTransceiverDirection::kSendRecv, kActive,
1037 &opts);
1038 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1039 std::unique_ptr<SessionDescription> answer =
1040 f2_.CreateAnswer(offer.get(), opts, nullptr);
1041
1042 // Reject the audio m= section and add a video m= section.
1043 opts.media_description_options[0].stopped = true;
1044 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1045 RtpTransceiverDirection::kSendRecv, kActive,
1046 &opts);
1047 std::unique_ptr<SessionDescription> reoffer =
1048 f1_.CreateOffer(opts, offer.get());
1049 std::unique_ptr<SessionDescription> reanswer =
1050 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1051
1052 const cricket::ContentGroup* bundle_group =
1053 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1054 ASSERT_TRUE(bundle_group);
1055 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1056 EXPECT_TRUE(bundle_group->HasContentName("video"));
1057}
1058
Henrik Boströmf8187e02021-04-26 21:04:26 +02001059TEST_F(MediaSessionDescriptionFactoryTest,
1060 CreateAnswerForOfferWithMultipleBundleGroups) {
1061 // Create an offer with 4 m= sections, initially without BUNDLE groups.
1062 MediaSessionOptions opts;
1063 opts.bundle_enabled = false;
1064 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "1",
1065 RtpTransceiverDirection::kSendRecv, kActive,
1066 &opts);
1067 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "2",
1068 RtpTransceiverDirection::kSendRecv, kActive,
1069 &opts);
1070 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "3",
1071 RtpTransceiverDirection::kSendRecv, kActive,
1072 &opts);
1073 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "4",
1074 RtpTransceiverDirection::kSendRecv, kActive,
1075 &opts);
1076 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1077 ASSERT_TRUE(offer->groups().empty());
1078
1079 // Munge the offer to have two groups. Offers like these cannot be generated
1080 // without munging, but it is valid to receive such offers from remote
1081 // endpoints.
1082 cricket::ContentGroup bundle_group1(cricket::GROUP_TYPE_BUNDLE);
1083 bundle_group1.AddContentName("1");
1084 bundle_group1.AddContentName("2");
1085 cricket::ContentGroup bundle_group2(cricket::GROUP_TYPE_BUNDLE);
1086 bundle_group2.AddContentName("3");
1087 bundle_group2.AddContentName("4");
1088 offer->AddGroup(bundle_group1);
1089 offer->AddGroup(bundle_group2);
1090
1091 // If BUNDLE is enabled, the answer to this offer should accept both BUNDLE
1092 // groups.
1093 opts.bundle_enabled = true;
1094 std::unique_ptr<SessionDescription> answer =
1095 f2_.CreateAnswer(offer.get(), opts, nullptr);
1096
1097 std::vector<const cricket::ContentGroup*> answer_groups =
1098 answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1099 ASSERT_EQ(answer_groups.size(), 2u);
1100 EXPECT_EQ(answer_groups[0]->content_names().size(), 2u);
1101 EXPECT_TRUE(answer_groups[0]->HasContentName("1"));
1102 EXPECT_TRUE(answer_groups[0]->HasContentName("2"));
1103 EXPECT_EQ(answer_groups[1]->content_names().size(), 2u);
1104 EXPECT_TRUE(answer_groups[1]->HasContentName("3"));
1105 EXPECT_TRUE(answer_groups[1]->HasContentName("4"));
1106
1107 // If BUNDLE is disabled, the answer to this offer should reject both BUNDLE
1108 // groups.
1109 opts.bundle_enabled = false;
1110 answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1111
1112 answer_groups = answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1113 // Rejected groups are still listed, but they are empty.
1114 ASSERT_EQ(answer_groups.size(), 2u);
1115 EXPECT_TRUE(answer_groups[0]->content_names().empty());
1116 EXPECT_TRUE(answer_groups[1]->content_names().empty());
1117}
1118
Steve Anton2bed3972019-01-04 17:04:30 -08001119// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1120// and there is still a non-rejected media section that was in the initial
1121// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1122// media section.
1123TEST_F(MediaSessionDescriptionFactoryTest,
1124 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1125 MediaSessionOptions opts;
1126 opts.bundle_enabled = true;
1127 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1128 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1129 std::unique_ptr<SessionDescription> answer =
1130 f2_.CreateAnswer(offer.get(), opts, nullptr);
1131
1132 // Reject the audio m= section.
1133 opts.media_description_options[0].stopped = true;
1134 std::unique_ptr<SessionDescription> reoffer =
1135 f1_.CreateOffer(opts, offer.get());
1136
1137 const TransportDescription* offer_tagged =
1138 offer->GetTransportDescriptionByName("audio");
1139 ASSERT_TRUE(offer_tagged);
1140 const TransportDescription* reoffer_tagged =
1141 reoffer->GetTransportDescriptionByName("video");
1142 ASSERT_TRUE(reoffer_tagged);
1143 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1144 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1145}
1146
1147// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1148// and there is still a non-rejected media section that was in the initial
1149// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1150// media section.
1151TEST_F(MediaSessionDescriptionFactoryTest,
1152 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1153 MediaSessionOptions opts;
1154 opts.bundle_enabled = true;
1155 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1156 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1157 std::unique_ptr<SessionDescription> answer =
1158 f2_.CreateAnswer(offer.get(), opts, nullptr);
1159
1160 // Reject the audio m= section.
1161 opts.media_description_options[0].stopped = true;
1162 std::unique_ptr<SessionDescription> reoffer =
1163 f1_.CreateOffer(opts, offer.get());
1164 std::unique_ptr<SessionDescription> reanswer =
1165 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1166
1167 const TransportDescription* answer_tagged =
1168 answer->GetTransportDescriptionByName("audio");
1169 ASSERT_TRUE(answer_tagged);
1170 const TransportDescription* reanswer_tagged =
1171 reanswer->GetTransportDescriptionByName("video");
1172 ASSERT_TRUE(reanswer_tagged);
1173 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1174 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1175}
1176
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177// Create an audio, video offer without legacy StreamParams.
1178TEST_F(MediaSessionDescriptionFactoryTest,
1179 TestCreateOfferWithoutLegacyStreams) {
1180 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001181 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001182 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 ASSERT_TRUE(offer.get() != NULL);
1184 const ContentInfo* ac = offer->GetContentByName("audio");
1185 const ContentInfo* vc = offer->GetContentByName("video");
1186 ASSERT_TRUE(ac != NULL);
1187 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001188 const AudioContentDescription* acd = ac->media_description()->as_audio();
1189 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190
Yves Gerey665174f2018-06-19 15:03:05 +02001191 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1192 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001193}
1194
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001195// Creates an audio+video sendonly offer.
1196TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001197 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001198 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001199 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1200 {kMediaStream1}, 1, &opts);
1201 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1202 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001203
Steve Anton6fe1fba2018-12-11 10:15:23 -08001204 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001205 ASSERT_TRUE(offer.get() != NULL);
1206 EXPECT_EQ(2u, offer->contents().size());
1207 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1208 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1209
Steve Anton4e70a722017-11-28 14:57:10 -08001210 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1211 GetMediaDirection(&offer->contents()[0]));
1212 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1213 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001214}
1215
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001216// Verifies that the order of the media contents in the current
1217// SessionDescription is preserved in the new SessionDescription.
1218TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1219 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001220 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001221
kwiberg31022942016-03-11 14:18:21 -08001222 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001223 ASSERT_TRUE(offer1.get() != NULL);
1224 EXPECT_EQ(1u, offer1->contents().size());
1225 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1226
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001227 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1228 RtpTransceiverDirection::kRecvOnly, kActive,
1229 &opts);
kwiberg31022942016-03-11 14:18:21 -08001230 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001231 f1_.CreateOffer(opts, offer1.get()));
1232 ASSERT_TRUE(offer2.get() != NULL);
1233 EXPECT_EQ(2u, offer2->contents().size());
1234 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1235 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1236
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001237 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1238 RtpTransceiverDirection::kRecvOnly, kActive,
1239 &opts);
kwiberg31022942016-03-11 14:18:21 -08001240 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001241 f1_.CreateOffer(opts, offer2.get()));
1242 ASSERT_TRUE(offer3.get() != NULL);
1243 EXPECT_EQ(3u, offer3->contents().size());
1244 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1245 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1246 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001247}
1248
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001249// Create a typical audio answer, and ensure it matches what we expect.
1250TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001251 f1_.set_secure(SEC_ENABLED);
1252 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001253 std::unique_ptr<SessionDescription> offer =
1254 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001255 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001256 std::unique_ptr<SessionDescription> answer =
1257 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 const ContentInfo* ac = answer->GetContentByName("audio");
1259 const ContentInfo* vc = answer->GetContentByName("video");
1260 ASSERT_TRUE(ac != NULL);
1261 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001262 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001263 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001265 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001266 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1268 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001269 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1270 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
1271}
1272
1273// Create a typical audio answer with GCM ciphers enabled, and ensure it
1274// matches what we expect.
1275TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1276 f1_.set_secure(SEC_ENABLED);
1277 f2_.set_secure(SEC_ENABLED);
1278 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1279 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
1280 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1281 ASSERT_TRUE(offer.get() != NULL);
1282 for (cricket::ContentInfo& content : offer->contents()) {
1283 auto cryptos = content.media_description()->cryptos();
1284 PreferGcmCryptoParameters(&cryptos);
1285 content.media_description()->set_cryptos(cryptos);
1286 }
1287 std::unique_ptr<SessionDescription> answer =
1288 f2_.CreateAnswer(offer.get(), opts, NULL);
1289 const ContentInfo* ac = answer->GetContentByName("audio");
1290 const ContentInfo* vc = answer->GetContentByName("video");
1291 ASSERT_TRUE(ac != NULL);
1292 ASSERT_TRUE(vc == NULL);
1293 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1294 const AudioContentDescription* acd = ac->media_description()->as_audio();
1295 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1296 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
1297 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
1298 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1299 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1300 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
1301 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001302}
1303
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001304// Create a typical video answer, and ensure it matches what we expect.
1305TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1306 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001307 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00001308 f1_.set_secure(SEC_ENABLED);
1309 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001310 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001312 std::unique_ptr<SessionDescription> answer =
1313 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001314 const ContentInfo* ac = answer->GetContentByName("audio");
1315 const ContentInfo* vc = answer->GetContentByName("video");
1316 ASSERT_TRUE(ac != NULL);
1317 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001318 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1319 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001320 const AudioContentDescription* acd = ac->media_description()->as_audio();
1321 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001322 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001323 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001324 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001325 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001326 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001327 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001329 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001330 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1331 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001332 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1333 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
1334}
1335
1336// Create a typical video answer with GCM ciphers enabled, and ensure it
1337// matches what we expect.
1338TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1339 TestVideoGcmCipher(true, true);
1340}
1341
1342// Create a typical video answer with GCM ciphers enabled for the offer only,
1343// and ensure it matches what we expect.
1344TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1345 TestVideoGcmCipher(true, false);
1346}
1347
1348// Create a typical video answer with GCM ciphers enabled for the answer only,
1349// and ensure it matches what we expect.
1350TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1351 TestVideoGcmCipher(false, true);
jbauchcb560652016-08-04 05:20:32 -07001352}
1353
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001354// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1355// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001356TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1357 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001358 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001359 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001360 ASSERT_TRUE(offer.get() != NULL);
1361 ContentInfo* dc_offer = offer->GetContentByName("data");
1362 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001363 SctpDataContentDescription* dcd_offer =
1364 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001365 EXPECT_TRUE(dcd_offer->use_sctpmap());
1366
Steve Anton6fe1fba2018-12-11 10:15:23 -08001367 std::unique_ptr<SessionDescription> answer =
1368 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001369 const ContentInfo* dc_answer = answer->GetContentByName("data");
1370 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001371 const SctpDataContentDescription* dcd_answer =
1372 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001373 EXPECT_TRUE(dcd_answer->use_sctpmap());
1374}
1375
1376// The answer's use_sctpmap flag should match the offer's.
1377TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1378 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001379 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001380 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001381 ASSERT_TRUE(offer.get() != NULL);
1382 ContentInfo* dc_offer = offer->GetContentByName("data");
1383 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001384 SctpDataContentDescription* dcd_offer =
1385 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001386 dcd_offer->set_use_sctpmap(false);
1387
Steve Anton6fe1fba2018-12-11 10:15:23 -08001388 std::unique_ptr<SessionDescription> answer =
1389 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001390 const ContentInfo* dc_answer = answer->GetContentByName("data");
1391 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001392 const SctpDataContentDescription* dcd_answer =
1393 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001394 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001395}
1396
deadbeef8b7e9ad2017-05-25 09:38:55 -07001397// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1398// and "TCP/DTLS/SCTP" offers.
1399TEST_F(MediaSessionDescriptionFactoryTest,
1400 TestCreateDataAnswerToDifferentOfferedProtos) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001401 // Need to enable DTLS offer/answer generation (disabled by default in this
1402 // test).
1403 f1_.set_secure(SEC_ENABLED);
1404 f2_.set_secure(SEC_ENABLED);
1405 tdf1_.set_secure(SEC_ENABLED);
1406 tdf2_.set_secure(SEC_ENABLED);
1407
deadbeef8b7e9ad2017-05-25 09:38:55 -07001408 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001409 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001410 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001411 ASSERT_TRUE(offer.get() != nullptr);
1412 ContentInfo* dc_offer = offer->GetContentByName("data");
1413 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001414 SctpDataContentDescription* dcd_offer =
1415 dc_offer->media_description()->as_sctp();
1416 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001417
1418 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1419 "TCP/DTLS/SCTP"};
1420 for (const std::string& proto : protos) {
1421 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001422 std::unique_ptr<SessionDescription> answer =
1423 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001424 const ContentInfo* dc_answer = answer->GetContentByName("data");
1425 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001426 const SctpDataContentDescription* dcd_answer =
1427 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001428 EXPECT_FALSE(dc_answer->rejected);
1429 EXPECT_EQ(proto, dcd_answer->protocol());
1430 }
1431}
1432
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001433TEST_F(MediaSessionDescriptionFactoryTest,
1434 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001435 // Need to enable DTLS offer/answer generation (disabled by default in this
1436 // test).
1437 f1_.set_secure(SEC_ENABLED);
1438 f2_.set_secure(SEC_ENABLED);
1439 tdf1_.set_secure(SEC_ENABLED);
1440 tdf2_.set_secure(SEC_ENABLED);
1441
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001442 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001443 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001444 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1445 ASSERT_TRUE(offer.get() != nullptr);
1446 ContentInfo* dc_offer = offer->GetContentByName("data");
1447 ASSERT_TRUE(dc_offer != nullptr);
1448 SctpDataContentDescription* dcd_offer =
1449 dc_offer->media_description()->as_sctp();
1450 ASSERT_TRUE(dcd_offer);
1451 dcd_offer->set_max_message_size(1234);
1452 std::unique_ptr<SessionDescription> answer =
1453 f2_.CreateAnswer(offer.get(), opts, nullptr);
1454 const ContentInfo* dc_answer = answer->GetContentByName("data");
1455 ASSERT_TRUE(dc_answer != nullptr);
1456 const SctpDataContentDescription* dcd_answer =
1457 dc_answer->media_description()->as_sctp();
1458 EXPECT_FALSE(dc_answer->rejected);
1459 EXPECT_EQ(1234, dcd_answer->max_message_size());
1460}
1461
1462TEST_F(MediaSessionDescriptionFactoryTest,
1463 TestCreateDataAnswerToOfferWithZeroMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001464 // Need to enable DTLS offer/answer generation (disabled by default in this
1465 // test).
1466 f1_.set_secure(SEC_ENABLED);
1467 f2_.set_secure(SEC_ENABLED);
1468 tdf1_.set_secure(SEC_ENABLED);
1469 tdf2_.set_secure(SEC_ENABLED);
1470
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001471 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001472 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001473 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1474 ASSERT_TRUE(offer.get() != nullptr);
1475 ContentInfo* dc_offer = offer->GetContentByName("data");
1476 ASSERT_TRUE(dc_offer != nullptr);
1477 SctpDataContentDescription* dcd_offer =
1478 dc_offer->media_description()->as_sctp();
1479 ASSERT_TRUE(dcd_offer);
1480 dcd_offer->set_max_message_size(0);
1481 std::unique_ptr<SessionDescription> answer =
1482 f2_.CreateAnswer(offer.get(), opts, nullptr);
1483 const ContentInfo* dc_answer = answer->GetContentByName("data");
1484 ASSERT_TRUE(dc_answer != nullptr);
1485 const SctpDataContentDescription* dcd_answer =
1486 dc_answer->media_description()->as_sctp();
1487 EXPECT_FALSE(dc_answer->rejected);
1488 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1489}
1490
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001491// Verifies that the order of the media contents in the offer is preserved in
1492// the answer.
1493TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1494 MediaSessionOptions opts;
1495
1496 // Creates a data only offer.
Florent Castelli516e2842021-04-19 15:29:50 +02001497 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001498 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001499 ASSERT_TRUE(offer1.get() != NULL);
1500
1501 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001502 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1503 RtpTransceiverDirection::kRecvOnly, kActive,
1504 &opts);
kwiberg31022942016-03-11 14:18:21 -08001505 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001506 f1_.CreateOffer(opts, offer1.get()));
1507 ASSERT_TRUE(offer2.get() != NULL);
1508
1509 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001510 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1511 RtpTransceiverDirection::kRecvOnly, kActive,
1512 &opts);
kwiberg31022942016-03-11 14:18:21 -08001513 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001514 f1_.CreateOffer(opts, offer2.get()));
1515 ASSERT_TRUE(offer3.get() != NULL);
1516
Steve Anton6fe1fba2018-12-11 10:15:23 -08001517 std::unique_ptr<SessionDescription> answer =
1518 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001519 ASSERT_TRUE(answer.get() != NULL);
1520 EXPECT_EQ(3u, answer->contents().size());
1521 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1522 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1523 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1524}
1525
ossu075af922016-06-14 03:29:38 -07001526// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1527// answerer settings.
1528
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001529// This test that the media direction is set to send/receive in an answer if
1530// the offer is send receive.
1531TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001532 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1533 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001534}
1535
1536// This test that the media direction is set to receive only in an answer if
1537// the offer is send only.
1538TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001539 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1540 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001541}
1542
1543// This test that the media direction is set to send only in an answer if
1544// the offer is recv only.
1545TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001546 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1547 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001548}
1549
1550// This test that the media direction is set to inactive in an answer if
1551// the offer is inactive.
1552TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001553 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1554 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001555}
1556
Harald Alvestrand0d018412021-11-04 13:52:31 +00001557// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001558TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001559 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Harald Alvestrand0d018412021-11-04 13:52:31 +00001560 f1_.set_secure(SEC_DISABLED);
1561 f2_.set_secure(SEC_DISABLED);
1562 tdf1_.set_secure(SEC_DISABLED);
1563 tdf2_.set_secure(SEC_DISABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001564
Steve Anton6fe1fba2018-12-11 10:15:23 -08001565 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001566 const AudioContentDescription* offer_acd =
1567 GetFirstAudioContentDescription(offer.get());
1568 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001569 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001570
Steve Anton6fe1fba2018-12-11 10:15:23 -08001571 std::unique_ptr<SessionDescription> answer =
1572 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001573
1574 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1575 ASSERT_TRUE(ac_answer != NULL);
1576 EXPECT_FALSE(ac_answer->rejected);
1577
1578 const AudioContentDescription* answer_acd =
1579 GetFirstAudioContentDescription(answer.get());
1580 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001581 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582}
1583
1584// Create a video offer and answer and ensure the RTP header extensions
1585// matches what we expect.
1586TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1587 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001588 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +02001589 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1590 MAKE_VECTOR(kVideoRtpExtension1), &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001591
Steve Anton6fe1fba2018-12-11 10:15:23 -08001592 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001593 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001594 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1595 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001596 std::unique_ptr<SessionDescription> answer =
1597 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001598
Yves Gerey665174f2018-06-19 15:03:05 +02001599 EXPECT_EQ(
1600 MAKE_VECTOR(kAudioRtpExtension1),
1601 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1602 EXPECT_EQ(
1603 MAKE_VECTOR(kVideoRtpExtension1),
1604 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1605 EXPECT_EQ(
1606 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1607 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1608 EXPECT_EQ(
1609 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1610 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611}
1612
Johannes Kronce8e8672019-02-22 13:06:44 +01001613// Create a audio/video offer and answer and ensure that the
1614// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1615// supported and should take precedence even though not listed among locally
1616// supported extensions.
1617TEST_F(MediaSessionDescriptionFactoryTest,
1618 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1619 TestTransportSequenceNumberNegotiation(
1620 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1621 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1622 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1623}
1624TEST_F(MediaSessionDescriptionFactoryTest,
1625 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1626 TestTransportSequenceNumberNegotiation(
1627 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1628 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1629 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1630}
1631TEST_F(MediaSessionDescriptionFactoryTest,
1632 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1633 TestTransportSequenceNumberNegotiation(
1634 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1635 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1636 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1637}
1638
jbauch5869f502017-06-29 12:31:36 -07001639TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001640 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1641 MediaSessionOptions opts;
1642 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1643
Markus Handell755c65d2020-06-24 01:06:10 +02001644 SetAudioVideoRtpHeaderExtensions(
1645 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1646 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001647 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001648 SetAudioVideoRtpHeaderExtensions(
1649 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1650 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001651 std::unique_ptr<SessionDescription> answer =
1652 f2_.CreateAnswer(offer.get(), opts, nullptr);
1653 EXPECT_THAT(
1654 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001655 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001656 EXPECT_THAT(
1657 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001658 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001659}
1660
1661TEST_F(MediaSessionDescriptionFactoryTest,
1662 TestNegotiateFrameDescriptorWhenExposedLocally) {
1663 MediaSessionOptions opts;
1664 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1665
Markus Handell755c65d2020-06-24 01:06:10 +02001666 SetAudioVideoRtpHeaderExtensions(
1667 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1668 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001669 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1670 std::unique_ptr<SessionDescription> answer =
1671 f2_.CreateAnswer(offer.get(), opts, nullptr);
1672 EXPECT_THAT(
1673 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001674 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001675 EXPECT_THAT(
1676 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001677 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001678}
1679
1680TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001681 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1682 MediaSessionOptions opts;
1683 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1684
1685 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell755c65d2020-06-24 01:06:10 +02001686 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +00001687 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001688 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1689 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001690 std::unique_ptr<SessionDescription> answer =
1691 f2_.CreateAnswer(offer.get(), opts, nullptr);
1692 EXPECT_THAT(
1693 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1694 ElementsAre(offer_dd));
1695}
1696
1697TEST_F(MediaSessionDescriptionFactoryTest,
1698 NegotiateDependencyDescriptorWhenExposedLocally) {
1699 MediaSessionOptions opts;
1700 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1701
1702 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1703 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell755c65d2020-06-24 01:06:10 +02001704 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001705 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001706 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001707 std::unique_ptr<SessionDescription> answer =
1708 f2_.CreateAnswer(offer.get(), opts, nullptr);
1709 EXPECT_THAT(
1710 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1711 ElementsAre(offer_dd));
1712}
1713
1714TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001715 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1716 MediaSessionOptions opts;
1717 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1718
1719 const cricket::RtpHeaderExtensions offered_extensions = {
1720 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1721 const cricket::RtpHeaderExtensions local_extensions = {
1722 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001723 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1724 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001725 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001726 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001727 std::unique_ptr<SessionDescription> answer =
1728 f2_.CreateAnswer(offer.get(), opts, nullptr);
1729 EXPECT_THAT(
1730 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1731 ElementsAreArray(offered_extensions));
1732 EXPECT_THAT(
1733 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1734 ElementsAreArray(offered_extensions));
1735}
1736
1737TEST_F(MediaSessionDescriptionFactoryTest,
1738 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1739 MediaSessionOptions opts;
1740 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1741
1742 const cricket::RtpHeaderExtensions offered_extensions = {
1743 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1744 const cricket::RtpHeaderExtensions local_extensions = {
1745 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001746 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1747 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001748 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001749 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001750 std::unique_ptr<SessionDescription> answer =
1751 f2_.CreateAnswer(offer.get(), opts, nullptr);
1752 EXPECT_THAT(
1753 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1754 ElementsAreArray(offered_extensions));
1755 EXPECT_THAT(
1756 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1757 ElementsAreArray(offered_extensions));
1758}
1759
1760TEST_F(MediaSessionDescriptionFactoryTest,
1761 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1762 MediaSessionOptions opts;
1763 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1764
1765 const cricket::RtpHeaderExtensions offered_extensions = {
1766 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1767 const cricket::RtpHeaderExtensions local_extensions = {
1768 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001769 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1770 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001771 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001772 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001773 std::unique_ptr<SessionDescription> answer =
1774 f2_.CreateAnswer(offer.get(), opts, nullptr);
1775 EXPECT_THAT(
1776 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1777 IsEmpty());
1778 EXPECT_THAT(
1779 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1780 IsEmpty());
1781}
1782
1783TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handell755c65d2020-06-24 01:06:10 +02001784 OffersUnstoppedExtensionsWithAudioVideoExtensionStopped) {
1785 MediaSessionOptions opts;
1786 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1787 RtpTransceiverDirection::kSendRecv, kActive,
1788 &opts);
1789 opts.media_description_options.back().header_extensions = {
1790 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1791 RtpTransceiverDirection::kStopped),
1792 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1793 RtpTransceiverDirection::kSendOnly)};
1794 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1795 RtpTransceiverDirection::kSendRecv, kActive,
1796 &opts);
1797 opts.media_description_options.back().header_extensions = {
1798 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1799 RtpTransceiverDirection::kStopped),
1800 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1801 RtpTransceiverDirection::kSendOnly)};
1802 auto offer = f1_.CreateOffer(opts, nullptr);
1803 EXPECT_THAT(
1804 offer->contents(),
1805 ElementsAre(
1806 Property(&ContentInfo::media_description,
1807 Pointee(Property(
1808 &MediaContentDescription::rtp_header_extensions,
1809 ElementsAre(Field(&RtpExtension::uri, "uri2"))))),
1810 Property(&ContentInfo::media_description,
1811 Pointee(Property(
1812 &MediaContentDescription::rtp_header_extensions,
1813 ElementsAre(Field(&RtpExtension::uri, "uri3")))))));
1814}
1815
1816TEST_F(MediaSessionDescriptionFactoryTest,
1817 OffersUnstoppedExtensionsWithAudioExtensionStopped) {
1818 MediaSessionOptions opts;
1819 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1820 RtpTransceiverDirection::kSendRecv, kActive,
1821 &opts);
1822 opts.media_description_options.back().header_extensions = {
1823 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1824 RtpTransceiverDirection::kSendOnly),
1825 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1826 RtpTransceiverDirection::kStopped)};
1827 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1828 RtpTransceiverDirection::kSendRecv, kActive,
1829 &opts);
1830 opts.media_description_options.back().header_extensions = {
1831 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1832 RtpTransceiverDirection::kSendRecv),
1833 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1834 RtpTransceiverDirection::kSendOnly)};
1835 auto offer = f1_.CreateOffer(opts, nullptr);
1836 EXPECT_THAT(
1837 offer->contents(),
1838 ElementsAre(
1839 Property(&ContentInfo::media_description,
1840 Pointee(Property(
1841 &MediaContentDescription::rtp_header_extensions,
1842 ElementsAre(Field(&RtpExtension::uri, "uri1"))))),
1843 Property(
1844 &ContentInfo::media_description,
1845 Pointee(Property(
1846 &MediaContentDescription::rtp_header_extensions,
1847 UnorderedElementsAre(Field(&RtpExtension::uri, "uri3"),
1848 Field(&RtpExtension::uri, "uri42")))))));
1849}
1850
1851TEST_F(MediaSessionDescriptionFactoryTest,
1852 OffersUnstoppedExtensionsWithVideoExtensionStopped) {
1853 MediaSessionOptions opts;
1854 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1855 RtpTransceiverDirection::kSendRecv, kActive,
1856 &opts);
1857 opts.media_description_options.back().header_extensions = {
1858 webrtc::RtpHeaderExtensionCapability("uri1", 5,
1859 RtpTransceiverDirection::kSendOnly),
1860 webrtc::RtpHeaderExtensionCapability("uri2", 7,
1861 RtpTransceiverDirection::kSendRecv)};
1862 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1863 RtpTransceiverDirection::kSendRecv, kActive,
1864 &opts);
1865 opts.media_description_options.back().header_extensions = {
1866 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1867 RtpTransceiverDirection::kSendRecv),
1868 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1869 RtpTransceiverDirection::kStopped)};
1870 auto offer = f1_.CreateOffer(opts, nullptr);
1871 EXPECT_THAT(
1872 offer->contents(),
1873 ElementsAre(
1874 Property(
1875 &ContentInfo::media_description,
1876 Pointee(Property(
1877 &MediaContentDescription::rtp_header_extensions,
1878 UnorderedElementsAre(Field(&RtpExtension::uri, "uri1"),
1879 Field(&RtpExtension::uri, "uri2"))))),
1880 Property(&ContentInfo::media_description,
1881 Pointee(Property(
1882 &MediaContentDescription::rtp_header_extensions,
1883 ElementsAre(Field(&RtpExtension::uri, "uri42")))))));
1884}
1885
1886TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1887 MediaSessionOptions opts;
1888 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1889 RtpTransceiverDirection::kSendRecv, kActive,
1890 &opts);
1891 opts.media_description_options.back().header_extensions = {
1892 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1893 RtpTransceiverDirection::kStopped),
1894 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1895 RtpTransceiverDirection::kSendOnly),
1896 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1897 RtpTransceiverDirection::kRecvOnly),
1898 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1899 RtpTransceiverDirection::kSendRecv)};
1900 auto offer = f1_.CreateOffer(opts, nullptr);
1901 opts.media_description_options.back().header_extensions = {
1902 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1903 RtpTransceiverDirection::kSendOnly),
1904 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1905 RtpTransceiverDirection::kRecvOnly),
1906 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1907 RtpTransceiverDirection::kStopped),
1908 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1909 RtpTransceiverDirection::kSendRecv)};
1910 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1911 EXPECT_THAT(
1912 answer->contents(),
1913 ElementsAre(Property(
1914 &ContentInfo::media_description,
1915 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1916 ElementsAre(Field(&RtpExtension::uri, "uri2"),
1917 Field(&RtpExtension::uri, "uri4")))))));
1918}
1919
1920TEST_F(MediaSessionDescriptionFactoryTest,
1921 AppendsUnstoppedExtensionsToCurrentDescription) {
1922 MediaSessionOptions opts;
1923 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1924 RtpTransceiverDirection::kSendRecv, kActive,
1925 &opts);
1926 opts.media_description_options.back().header_extensions = {
1927 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1928 RtpTransceiverDirection::kSendRecv)};
1929 auto offer = f1_.CreateOffer(opts, nullptr);
1930 opts.media_description_options.back().header_extensions = {
1931 webrtc::RtpHeaderExtensionCapability("uri1", 2,
1932 RtpTransceiverDirection::kSendRecv),
1933 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1934 RtpTransceiverDirection::kRecvOnly),
1935 webrtc::RtpHeaderExtensionCapability("uri3", 5,
1936 RtpTransceiverDirection::kStopped),
1937 webrtc::RtpHeaderExtensionCapability("uri4", 6,
1938 RtpTransceiverDirection::kSendRecv)};
1939 auto offer2 = f1_.CreateOffer(opts, offer.get());
1940 EXPECT_THAT(
1941 offer2->contents(),
1942 ElementsAre(Property(
1943 &ContentInfo::media_description,
1944 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1945 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1946 Field(&RtpExtension::uri, "uri2"),
1947 Field(&RtpExtension::uri, "uri4")))))));
1948}
1949
1950TEST_F(MediaSessionDescriptionFactoryTest,
1951 AppendsStoppedExtensionIfKnownAndPresentInTheOffer) {
1952 MediaSessionOptions opts;
1953 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1954 RtpTransceiverDirection::kSendRecv, kActive,
1955 &opts);
1956 opts.media_description_options.back().header_extensions = {
1957 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1958 RtpTransceiverDirection::kSendRecv),
1959 webrtc::RtpHeaderExtensionCapability("uri2", 1,
1960 RtpTransceiverDirection::kSendRecv)};
1961 auto offer = f1_.CreateOffer(opts, nullptr);
1962
1963 // Now add "uri2" as stopped to the options verify that the offer contains
1964 // uri2 since it's already present since before.
1965 opts.media_description_options.back().header_extensions = {
1966 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1967 RtpTransceiverDirection::kSendRecv),
1968 webrtc::RtpHeaderExtensionCapability("uri2", 2,
1969 RtpTransceiverDirection::kStopped)};
1970 auto offer2 = f1_.CreateOffer(opts, offer.get());
1971 EXPECT_THAT(
1972 offer2->contents(),
1973 ElementsAre(Property(
1974 &ContentInfo::media_description,
1975 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1976 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1977 Field(&RtpExtension::uri, "uri2")))))));
1978}
1979
1980TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001981 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001982 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001983 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001984
1985 f1_.set_enable_encrypted_rtp_header_extensions(true);
1986 f2_.set_enable_encrypted_rtp_header_extensions(true);
1987
Markus Handell755c65d2020-06-24 01:06:10 +02001988 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1989 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001990 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001991 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001992 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1993 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001994 std::unique_ptr<SessionDescription> answer =
1995 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001996
Yves Gerey665174f2018-06-19 15:03:05 +02001997 EXPECT_EQ(
1998 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1999 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2000 EXPECT_EQ(
2001 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2002 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2003 EXPECT_EQ(
2004 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
2005 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2006 EXPECT_EQ(
2007 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
2008 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002009}
2010
2011TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002012 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07002013 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002014 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002015
2016 f1_.set_enable_encrypted_rtp_header_extensions(true);
2017
Markus Handell755c65d2020-06-24 01:06:10 +02002018 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2019 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002020 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002021 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002022 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2023 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002024 std::unique_ptr<SessionDescription> answer =
2025 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002026
Yves Gerey665174f2018-06-19 15:03:05 +02002027 EXPECT_EQ(
2028 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2029 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2030 EXPECT_EQ(
2031 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2032 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2033 EXPECT_EQ(
2034 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2035 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2036 EXPECT_EQ(
2037 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2038 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002039}
2040
2041TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002042 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07002043 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002044 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002045
2046 f2_.set_enable_encrypted_rtp_header_extensions(true);
2047
Markus Handell755c65d2020-06-24 01:06:10 +02002048 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2049 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002050 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002051 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002052 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2053 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002054 std::unique_ptr<SessionDescription> answer =
2055 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002056
Yves Gerey665174f2018-06-19 15:03:05 +02002057 EXPECT_EQ(
2058 MAKE_VECTOR(kAudioRtpExtension1),
2059 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2060 EXPECT_EQ(
2061 MAKE_VECTOR(kVideoRtpExtension1),
2062 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2063 EXPECT_EQ(
2064 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2065 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2066 EXPECT_EQ(
2067 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2068 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002069}
2070
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002071// Create an audio, video, data answer without legacy StreamParams.
2072TEST_F(MediaSessionDescriptionFactoryTest,
2073 TestCreateAnswerWithoutLegacyStreams) {
2074 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002075 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002076 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002077 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002078 std::unique_ptr<SessionDescription> answer =
2079 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002080 const ContentInfo* ac = answer->GetContentByName("audio");
2081 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002082 ASSERT_TRUE(ac != NULL);
2083 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002084 const AudioContentDescription* acd = ac->media_description()->as_audio();
2085 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002086
2087 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2088 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002089}
2090
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002091// Create a typical video answer, and ensure it matches what we expect.
2092TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2093 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002094 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002095
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002096 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002097 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002098
kwiberg31022942016-03-11 14:18:21 -08002099 std::unique_ptr<SessionDescription> offer;
2100 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002101
2102 offer_opts.rtcp_mux_enabled = true;
2103 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002104 offer = f1_.CreateOffer(offer_opts, NULL);
2105 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002106 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2107 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002108 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2109 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002110 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2111 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002112 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2113 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002114
2115 offer_opts.rtcp_mux_enabled = true;
2116 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002117 offer = f1_.CreateOffer(offer_opts, NULL);
2118 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002119 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2120 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002121 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2122 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002123 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2124 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002125 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2126 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002127
2128 offer_opts.rtcp_mux_enabled = false;
2129 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002130 offer = f1_.CreateOffer(offer_opts, NULL);
2131 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002132 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2133 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002134 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2135 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002136 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2137 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002138 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2139 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002140
2141 offer_opts.rtcp_mux_enabled = false;
2142 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002143 offer = f1_.CreateOffer(offer_opts, NULL);
2144 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002145 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2146 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002147 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2148 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002149 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2150 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2152 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002153}
2154
2155// Create an audio-only answer to a video offer.
2156TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2157 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002158 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2159 RtpTransceiverDirection::kRecvOnly, kActive,
2160 &opts);
2161 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2162 RtpTransceiverDirection::kRecvOnly, kActive,
2163 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002164 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002165 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002166
2167 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002168 std::unique_ptr<SessionDescription> answer =
2169 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002170 const ContentInfo* ac = answer->GetContentByName("audio");
2171 const ContentInfo* vc = answer->GetContentByName("video");
2172 ASSERT_TRUE(ac != NULL);
2173 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002174 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002175 EXPECT_TRUE(vc->rejected);
2176}
2177
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178// Create an answer that rejects the contents which are rejected in the offer.
2179TEST_F(MediaSessionDescriptionFactoryTest,
2180 CreateAnswerToOfferWithRejectedMedia) {
2181 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002182 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002183 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002184 ASSERT_TRUE(offer.get() != NULL);
2185 ContentInfo* ac = offer->GetContentByName("audio");
2186 ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002187 ASSERT_TRUE(ac != NULL);
2188 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002189 ac->rejected = true;
2190 vc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002191 std::unique_ptr<SessionDescription> answer =
2192 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002193 ac = answer->GetContentByName("audio");
2194 vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002195 ASSERT_TRUE(ac != NULL);
2196 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197 EXPECT_TRUE(ac->rejected);
2198 EXPECT_TRUE(vc->rejected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002199}
2200
Johannes Kron0854eb62018-10-10 22:33:20 +02002201TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002202 OfferAndAnswerDoesNotHaveMixedByteSessionAttribute) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002203 MediaSessionOptions opts;
Emil Lundmark801c9992021-01-19 13:06:32 +01002204 std::unique_ptr<SessionDescription> offer =
2205 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002206 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002207
Emil Lundmark801c9992021-01-19 13:06:32 +01002208 std::unique_ptr<SessionDescription> answer(
2209 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2210
2211 EXPECT_FALSE(answer->extmap_allow_mixed());
2212}
2213
2214TEST_F(MediaSessionDescriptionFactoryTest,
2215 OfferAndAnswerHaveMixedByteSessionAttribute) {
2216 MediaSessionOptions opts;
2217 std::unique_ptr<SessionDescription> offer =
2218 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002219 offer->set_extmap_allow_mixed(true);
Emil Lundmark801c9992021-01-19 13:06:32 +01002220
Johannes Kron0854eb62018-10-10 22:33:20 +02002221 std::unique_ptr<SessionDescription> answer_support(
Emil Lundmark801c9992021-01-19 13:06:32 +01002222 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2223
Johannes Kron9581bc42018-10-23 10:17:39 +02002224 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002225}
2226
2227TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002228 OfferAndAnswerDoesNotHaveMixedByteMediaAttributes) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002229 MediaSessionOptions opts;
2230 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Emil Lundmark801c9992021-01-19 13:06:32 +01002231 std::unique_ptr<SessionDescription> offer =
2232 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2233 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002234 MediaContentDescription* audio_offer =
2235 offer->GetContentDescriptionByName("audio");
Emil Lundmark801c9992021-01-19 13:06:32 +01002236 MediaContentDescription* video_offer =
2237 offer->GetContentDescriptionByName("video");
2238 ASSERT_EQ(MediaContentDescription::kNo,
2239 audio_offer->extmap_allow_mixed_enum());
2240 ASSERT_EQ(MediaContentDescription::kNo,
2241 video_offer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002242
Emil Lundmark801c9992021-01-19 13:06:32 +01002243 std::unique_ptr<SessionDescription> answer(
2244 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
Johannes Kron0854eb62018-10-10 22:33:20 +02002245
Johannes Kron0854eb62018-10-10 22:33:20 +02002246 MediaContentDescription* audio_answer =
Emil Lundmark801c9992021-01-19 13:06:32 +01002247 answer->GetContentDescriptionByName("audio");
2248 MediaContentDescription* video_answer =
2249 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002250 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002251 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002252 EXPECT_EQ(MediaContentDescription::kNo,
2253 video_answer->extmap_allow_mixed_enum());
2254}
Johannes Kron0854eb62018-10-10 22:33:20 +02002255
Emil Lundmark801c9992021-01-19 13:06:32 +01002256TEST_F(MediaSessionDescriptionFactoryTest,
2257 OfferAndAnswerHaveSameMixedByteMediaAttributes) {
2258 MediaSessionOptions opts;
2259 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2260 std::unique_ptr<SessionDescription> offer =
2261 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2262 offer->set_extmap_allow_mixed(false);
2263 MediaContentDescription* audio_offer =
2264 offer->GetContentDescriptionByName("audio");
Johannes Kron9581bc42018-10-23 10:17:39 +02002265 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Emil Lundmark801c9992021-01-19 13:06:32 +01002266 MediaContentDescription* video_offer =
2267 offer->GetContentDescriptionByName("video");
2268 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2269
2270 std::unique_ptr<SessionDescription> answer(
2271 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2272
2273 MediaContentDescription* audio_answer =
2274 answer->GetContentDescriptionByName("audio");
2275 MediaContentDescription* video_answer =
2276 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002277 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002278 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002279 EXPECT_EQ(MediaContentDescription::kMedia,
2280 video_answer->extmap_allow_mixed_enum());
2281}
2282
2283TEST_F(MediaSessionDescriptionFactoryTest,
2284 OfferAndAnswerHaveDifferentMixedByteMediaAttributes) {
2285 MediaSessionOptions opts;
2286 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2287 std::unique_ptr<SessionDescription> offer =
2288 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2289 offer->set_extmap_allow_mixed(false);
2290 MediaContentDescription* audio_offer =
2291 offer->GetContentDescriptionByName("audio");
2292 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2293 MediaContentDescription* video_offer =
2294 offer->GetContentDescriptionByName("video");
2295 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2296
2297 std::unique_ptr<SessionDescription> answer(
2298 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2299
2300 MediaContentDescription* audio_answer =
2301 answer->GetContentDescriptionByName("audio");
2302 MediaContentDescription* video_answer =
2303 answer->GetContentDescriptionByName("video");
2304 EXPECT_EQ(MediaContentDescription::kNo,
2305 audio_answer->extmap_allow_mixed_enum());
2306 EXPECT_EQ(MediaContentDescription::kMedia,
2307 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002308}
2309
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310// Create an audio and video offer with:
2311// - one video track
2312// - two audio tracks
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002313// and ensure it matches what we expect. Also updates the initial offer by
2314// adding a new video track and replaces one of the audio tracks.
2315TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2316 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002317 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002318 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2319 {kMediaStream1}, 1, &opts);
2320 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2321 {kMediaStream1}, 1, &opts);
2322 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2323 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002324
Harald Alvestrand0d018412021-11-04 13:52:31 +00002325 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002326 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002327
2328 ASSERT_TRUE(offer.get() != NULL);
2329 const ContentInfo* ac = offer->GetContentByName("audio");
2330 const ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002331 ASSERT_TRUE(ac != NULL);
2332 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002333 const AudioContentDescription* acd = ac->media_description()->as_audio();
2334 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002335 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002336 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002337
2338 const StreamParamsVec& audio_streams = acd->streams();
2339 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002340 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002341 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2342 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2343 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2344 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2345 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2346 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2347
2348 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2349 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +00002350 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002351
2352 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002353 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002354 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002355
2356 const StreamParamsVec& video_streams = vcd->streams();
2357 ASSERT_EQ(1U, video_streams.size());
2358 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2359 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2360 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2361 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2362
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002363 // Update the offer. Add a new video track that is not synched to the
2364 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002365 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2366 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002367 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002368 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2369 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002370 std::unique_ptr<SessionDescription> updated_offer(
2371 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002372
2373 ASSERT_TRUE(updated_offer.get() != NULL);
2374 ac = updated_offer->GetContentByName("audio");
2375 vc = updated_offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002376 ASSERT_TRUE(ac != NULL);
2377 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002378 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002379 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002380 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002381 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382
2383 EXPECT_EQ(acd->type(), updated_acd->type());
2384 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2385 EXPECT_EQ(vcd->type(), updated_vcd->type());
2386 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002387 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2388 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2389 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2390 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002391
2392 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2393 ASSERT_EQ(2U, updated_audio_streams.size());
2394 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2395 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2396 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2397 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2398 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2399
2400 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2401 ASSERT_EQ(2U, updated_video_streams.size());
2402 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2403 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002404 // All the media streams in one PeerConnection share one RTCP CNAME.
2405 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002406}
2407
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002408// Create an offer with simulcast video stream.
2409TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2410 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002411 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2412 RtpTransceiverDirection::kRecvOnly, kActive,
2413 &opts);
2414 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2415 RtpTransceiverDirection::kSendRecv, kActive,
2416 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002417 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002418 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2419 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002420 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002421
2422 ASSERT_TRUE(offer.get() != NULL);
2423 const ContentInfo* vc = offer->GetContentByName("video");
2424 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002425 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002426
2427 const StreamParamsVec& video_streams = vcd->streams();
2428 ASSERT_EQ(1U, video_streams.size());
2429 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2430 const SsrcGroup* sim_ssrc_group =
2431 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2432 ASSERT_TRUE(sim_ssrc_group != NULL);
2433 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2434}
2435
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002436MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2437 const RidDescription& rid1 = ::testing::get<0>(arg);
2438 const RidDescription& rid2 = ::testing::get<1>(arg);
2439 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2440}
2441
2442static void CheckSimulcastInSessionDescription(
2443 const SessionDescription* description,
2444 const std::string& content_name,
2445 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002446 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002447 ASSERT_NE(description, nullptr);
2448 const ContentInfo* content = description->GetContentByName(content_name);
2449 ASSERT_NE(content, nullptr);
2450 const MediaContentDescription* cd = content->media_description();
2451 ASSERT_NE(cd, nullptr);
2452 const StreamParamsVec& streams = cd->streams();
2453 ASSERT_THAT(streams, SizeIs(1));
2454 const StreamParams& stream = streams[0];
2455 ASSERT_THAT(stream.ssrcs, IsEmpty());
2456 EXPECT_TRUE(stream.has_rids());
2457 const std::vector<RidDescription> rids = stream.rids();
2458
2459 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2460
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002461 EXPECT_TRUE(cd->HasSimulcast());
2462 const SimulcastDescription& simulcast = cd->simulcast_description();
2463 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2464 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2465
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002466 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002467}
2468
2469// Create an offer with spec-compliant simulcast video stream.
2470TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2471 MediaSessionOptions opts;
2472 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2473 RtpTransceiverDirection::kSendRecv, kActive,
2474 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002475 std::vector<RidDescription> send_rids;
2476 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2477 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2478 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2479 SimulcastLayerList simulcast_layers;
2480 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2481 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2482 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2483 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2484 {kMediaStream1}, send_rids,
2485 simulcast_layers, 0, &opts);
2486 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2487
2488 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002489 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002490}
2491
2492// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2493// In this scenario, RIDs do not need to be negotiated (there is only one).
2494TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2495 MediaSessionOptions opts;
2496 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2497 RtpTransceiverDirection::kSendRecv, kActive,
2498 &opts);
2499 RidDescription rid("f", RidDirection::kSend);
2500 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2501 {kMediaStream1}, {rid},
2502 SimulcastLayerList(), 0, &opts);
2503 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2504
2505 ASSERT_NE(offer.get(), nullptr);
2506 const ContentInfo* content = offer->GetContentByName("video");
2507 ASSERT_NE(content, nullptr);
2508 const MediaContentDescription* cd = content->media_description();
2509 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002510 const StreamParamsVec& streams = cd->streams();
2511 ASSERT_THAT(streams, SizeIs(1));
2512 const StreamParams& stream = streams[0];
2513 ASSERT_THAT(stream.ssrcs, IsEmpty());
2514 EXPECT_FALSE(stream.has_rids());
2515 EXPECT_FALSE(cd->HasSimulcast());
2516}
2517
2518// Create an answer with spec-compliant simulcast video stream.
2519// In this scenario, the SFU is the caller requesting that we send Simulcast.
2520TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2521 MediaSessionOptions offer_opts;
2522 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2523 RtpTransceiverDirection::kSendRecv, kActive,
2524 &offer_opts);
2525 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2526 {kMediaStream1}, 1, &offer_opts);
2527 std::unique_ptr<SessionDescription> offer =
2528 f1_.CreateOffer(offer_opts, nullptr);
2529
2530 MediaSessionOptions answer_opts;
2531 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2532 RtpTransceiverDirection::kSendRecv, kActive,
2533 &answer_opts);
2534
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002535 std::vector<RidDescription> rid_descriptions{
2536 RidDescription("f", RidDirection::kSend),
2537 RidDescription("h", RidDirection::kSend),
2538 RidDescription("q", RidDirection::kSend),
2539 };
2540 SimulcastLayerList simulcast_layers;
2541 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2542 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2543 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2544 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2545 {kMediaStream1}, rid_descriptions,
2546 simulcast_layers, 0, &answer_opts);
2547 std::unique_ptr<SessionDescription> answer =
2548 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2549
2550 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002551 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002552}
2553
2554// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2555// In this scenario, RIDs do not need to be negotiated (there is only one).
2556// Note that RID Direction is not the same as the transceiver direction.
2557TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2558 MediaSessionOptions offer_opts;
2559 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2560 RtpTransceiverDirection::kSendRecv, kActive,
2561 &offer_opts);
2562 RidDescription rid_offer("f", RidDirection::kSend);
2563 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2564 {kMediaStream1}, {rid_offer},
2565 SimulcastLayerList(), 0, &offer_opts);
2566 std::unique_ptr<SessionDescription> offer =
2567 f1_.CreateOffer(offer_opts, nullptr);
2568
2569 MediaSessionOptions answer_opts;
2570 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2571 RtpTransceiverDirection::kSendRecv, kActive,
2572 &answer_opts);
2573
2574 RidDescription rid_answer("f", RidDirection::kReceive);
2575 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2576 {kMediaStream1}, {rid_answer},
2577 SimulcastLayerList(), 0, &answer_opts);
2578 std::unique_ptr<SessionDescription> answer =
2579 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2580
2581 ASSERT_NE(answer.get(), nullptr);
2582 const ContentInfo* content = offer->GetContentByName("video");
2583 ASSERT_NE(content, nullptr);
2584 const MediaContentDescription* cd = content->media_description();
2585 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002586 const StreamParamsVec& streams = cd->streams();
2587 ASSERT_THAT(streams, SizeIs(1));
2588 const StreamParams& stream = streams[0];
2589 ASSERT_THAT(stream.ssrcs, IsEmpty());
2590 EXPECT_FALSE(stream.has_rids());
2591 EXPECT_FALSE(cd->HasSimulcast());
2592}
2593
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002594// Create an audio and video answer to a standard video offer with:
2595// - one video track
2596// - two audio tracks
2597// - two data tracks
2598// and ensure it matches what we expect. Also updates the initial answer by
2599// adding a new video track and removes one of the audio tracks.
2600TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2601 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002602 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2603 RtpTransceiverDirection::kRecvOnly, kActive,
2604 &offer_opts);
2605 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2606 RtpTransceiverDirection::kRecvOnly, kActive,
2607 &offer_opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00002608 f1_.set_secure(SEC_ENABLED);
2609 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002610 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002611
zhihuang1c378ed2017-08-17 14:10:50 -07002612 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002613 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2614 RtpTransceiverDirection::kSendRecv, kActive,
2615 &answer_opts);
2616 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2617 RtpTransceiverDirection::kSendRecv, kActive,
2618 &answer_opts);
2619 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2620 {kMediaStream1}, 1, &answer_opts);
2621 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2622 {kMediaStream1}, 1, &answer_opts);
2623 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2624 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002625
Steve Anton6fe1fba2018-12-11 10:15:23 -08002626 std::unique_ptr<SessionDescription> answer =
2627 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002628
2629 ASSERT_TRUE(answer.get() != NULL);
2630 const ContentInfo* ac = answer->GetContentByName("audio");
2631 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002632 ASSERT_TRUE(ac != NULL);
2633 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002634 const AudioContentDescription* acd = ac->media_description()->as_audio();
2635 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand0d018412021-11-04 13:52:31 +00002636 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2637 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002638
2639 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002640 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002641
2642 const StreamParamsVec& audio_streams = acd->streams();
2643 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002644 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002645 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2646 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2647 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2648 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2649 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2650 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2651
2652 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2653 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2654
2655 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002656 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002657
2658 const StreamParamsVec& video_streams = vcd->streams();
2659 ASSERT_EQ(1U, video_streams.size());
2660 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2661 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2662 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2663 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2664
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002665 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002666 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002667 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2668 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002669 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002670 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002671 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002672
2673 ASSERT_TRUE(updated_answer.get() != NULL);
2674 ac = updated_answer->GetContentByName("audio");
2675 vc = updated_answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002676 ASSERT_TRUE(ac != NULL);
2677 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002678 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002679 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002681 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002682
Harald Alvestrand0d018412021-11-04 13:52:31 +00002683 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2684 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2685 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2686 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
2687
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002688 EXPECT_EQ(acd->type(), updated_acd->type());
2689 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2690 EXPECT_EQ(vcd->type(), updated_vcd->type());
2691 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002692
2693 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2694 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002695 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696
2697 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2698 ASSERT_EQ(2U, updated_video_streams.size());
2699 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2700 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002701 // All media streams in one PeerConnection share one CNAME.
2702 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002703}
2704
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002705// Create an updated offer after creating an answer to the original offer and
2706// verify that the codecs that were part of the original answer are not changed
2707// in the updated offer.
2708TEST_F(MediaSessionDescriptionFactoryTest,
2709 RespondentCreatesOfferAfterCreatingAnswer) {
2710 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002711 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002712
Steve Anton6fe1fba2018-12-11 10:15:23 -08002713 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2714 std::unique_ptr<SessionDescription> answer =
2715 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716
2717 const AudioContentDescription* acd =
2718 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002719 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720
2721 const VideoContentDescription* vcd =
2722 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002723 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002724
kwiberg31022942016-03-11 14:18:21 -08002725 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002726 f2_.CreateOffer(opts, answer.get()));
2727
2728 // The expected audio codecs are the common audio codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002729 // offer/answer exchange plus the audio codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730 // preference order.
Artem Titov880fa812021-07-30 22:30:23 +02002731 // TODO(wu): `updated_offer` should not include the codec
Artem Titovcfea2182021-08-10 01:22:31 +02002732 // (i.e. `kAudioCodecs2[0]`) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002733 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002734 kAudioCodecsAnswer[0],
2735 kAudioCodecsAnswer[1],
2736 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 };
2738
2739 // The expected video codecs are the common video codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002740 // offer/answer exchange plus the video codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002741 // preference order.
2742 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002743 kVideoCodecsAnswer[0],
2744 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002745 };
2746
2747 const AudioContentDescription* updated_acd =
2748 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002749 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002750
2751 const VideoContentDescription* updated_vcd =
2752 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002753 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002754}
2755
Steve Anton5c72e712018-12-10 14:25:30 -08002756// Test that a reoffer does not reuse audio codecs from a previous media section
2757// that is being recycled.
2758TEST_F(MediaSessionDescriptionFactoryTest,
2759 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002760 f1_.set_video_codecs({}, {});
2761 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002762
2763 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002764 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2765 RtpTransceiverDirection::kSendRecv, kActive,
2766 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002767 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2768 std::unique_ptr<SessionDescription> answer =
2769 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002770
2771 // Recycle the media section by changing its mid.
2772 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002773 std::unique_ptr<SessionDescription> reoffer =
2774 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002775
2776 // Expect that the results of the first negotiation are ignored. If the m=
2777 // section was not recycled the payload types would match the initial offerer.
2778 const AudioContentDescription* acd =
2779 GetFirstAudioContentDescription(reoffer.get());
2780 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2781}
2782
2783// Test that a reoffer does not reuse video codecs from a previous media section
2784// that is being recycled.
2785TEST_F(MediaSessionDescriptionFactoryTest,
2786 ReOfferDoesNotReUseRecycledVideoCodecs) {
2787 f1_.set_audio_codecs({}, {});
2788 f2_.set_audio_codecs({}, {});
2789
2790 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002791 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2792 RtpTransceiverDirection::kSendRecv, kActive,
2793 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002794 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2795 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002796
2797 // Recycle the media section by changing its mid.
2798 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002799 std::unique_ptr<SessionDescription> reoffer =
2800 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002801
2802 // Expect that the results of the first negotiation are ignored. If the m=
2803 // section was not recycled the payload types would match the initial offerer.
2804 const VideoContentDescription* vcd =
2805 GetFirstVideoContentDescription(reoffer.get());
2806 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2807}
2808
2809// Test that a reanswer does not reuse audio codecs from a previous media
2810// section that is being recycled.
2811TEST_F(MediaSessionDescriptionFactoryTest,
2812 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002813 f1_.set_video_codecs({}, {});
2814 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002815
Artem Titov880fa812021-07-30 22:30:23 +02002816 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2817 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002818 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002819 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2820 RtpTransceiverDirection::kSendRecv, kActive,
2821 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002822 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2823 std::unique_ptr<SessionDescription> answer =
2824 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002825
2826 // Recycle the media section by changing its mid.
2827 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002828 std::unique_ptr<SessionDescription> reoffer =
2829 f1_.CreateOffer(opts, answer.get());
2830 std::unique_ptr<SessionDescription> reanswer =
2831 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002832
2833 // Expect that the results of the first negotiation are ignored. If the m=
2834 // section was not recycled the payload types would match the initial offerer.
2835 const AudioContentDescription* acd =
2836 GetFirstAudioContentDescription(reanswer.get());
2837 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2838}
2839
2840// Test that a reanswer does not reuse video codecs from a previous media
2841// section that is being recycled.
2842TEST_F(MediaSessionDescriptionFactoryTest,
2843 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2844 f1_.set_audio_codecs({}, {});
2845 f2_.set_audio_codecs({}, {});
2846
Artem Titov880fa812021-07-30 22:30:23 +02002847 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2848 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002849 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002850 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2851 RtpTransceiverDirection::kSendRecv, kActive,
2852 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002853 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2854 std::unique_ptr<SessionDescription> answer =
2855 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002856
2857 // Recycle the media section by changing its mid.
2858 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002859 std::unique_ptr<SessionDescription> reoffer =
2860 f1_.CreateOffer(opts, answer.get());
2861 std::unique_ptr<SessionDescription> reanswer =
2862 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002863
2864 // Expect that the results of the first negotiation are ignored. If the m=
2865 // section was not recycled the payload types would match the initial offerer.
2866 const VideoContentDescription* vcd =
2867 GetFirstVideoContentDescription(reanswer.get());
2868 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2869}
2870
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002871// Create an updated offer after creating an answer to the original offer and
2872// verify that the codecs that were part of the original answer are not changed
2873// in the updated offer. In this test Rtx is enabled.
2874TEST_F(MediaSessionDescriptionFactoryTest,
2875 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2876 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002877 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2878 RtpTransceiverDirection::kRecvOnly, kActive,
2879 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002880 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02002881 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002882 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002883 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002884
2885 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02002886 // This creates rtx for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002887 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002888 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002889
Steve Anton6fe1fba2018-12-11 10:15:23 -08002890 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002891 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002892 std::unique_ptr<SessionDescription> answer =
2893 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002894
2895 const VideoContentDescription* vcd =
2896 GetFirstVideoContentDescription(answer.get());
2897
2898 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002899 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2900 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002901
2902 EXPECT_EQ(expected_codecs, vcd->codecs());
2903
Artem Titov880fa812021-07-30 22:30:23 +02002904 // Now, make sure we get same result (except for the order) if `f2_` creates
2905 // an updated offer even though the default payload types between `f1_` and
2906 // `f2_` are different.
kwiberg31022942016-03-11 14:18:21 -08002907 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002908 f2_.CreateOffer(opts, answer.get()));
2909 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002910 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002911 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2912
2913 const VideoContentDescription* updated_vcd =
2914 GetFirstVideoContentDescription(updated_answer.get());
2915
2916 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2917}
2918
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002919// Regression test for:
2920// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2921// Existing codecs should always appear before new codecs in re-offers. But
2922// under a specific set of circumstances, the existing RTX codec was ending up
2923// added to the end of the list.
2924TEST_F(MediaSessionDescriptionFactoryTest,
2925 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2926 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002927 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2928 RtpTransceiverDirection::kRecvOnly, kActive,
2929 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002930 // We specifically choose different preferred payload types for VP8 to
2931 // trigger the issue.
2932 cricket::VideoCodec vp8_offerer(100, "VP8");
2933 cricket::VideoCodec vp8_offerer_rtx =
2934 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2935 cricket::VideoCodec vp8_answerer(110, "VP8");
2936 cricket::VideoCodec vp8_answerer_rtx =
2937 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2938 cricket::VideoCodec vp9(120, "VP9");
2939 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2940
2941 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2942 // We also specifically cause the answerer to prefer VP9, such that if it
2943 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2944 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2945 vp8_answerer_rtx};
2946
Johannes Kron3e983682020-03-29 22:17:00 +02002947 f1_.set_video_codecs(f1_codecs, f1_codecs);
2948 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002949 std::vector<AudioCodec> audio_codecs;
2950 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2951 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2952
2953 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002954 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002955 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002956 std::unique_ptr<SessionDescription> answer =
2957 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002958
2959 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2960 // But if the bug is triggered, RTX for VP8 ends up last.
2961 std::unique_ptr<SessionDescription> updated_offer(
2962 f2_.CreateOffer(opts, answer.get()));
2963
2964 const VideoContentDescription* vcd =
2965 GetFirstVideoContentDescription(updated_offer.get());
2966 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2967 ASSERT_EQ(4u, codecs.size());
2968 EXPECT_EQ(vp8_offerer, codecs[0]);
2969 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2970 EXPECT_EQ(vp9, codecs[2]);
2971 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002972}
2973
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974// Create an updated offer that adds video after creating an audio only answer
2975// to the original offer. This test verifies that if a video codec and the RTX
2976// codec have the same default payload type as an audio codec that is already in
2977// use, the added codecs payload types are changed.
2978TEST_F(MediaSessionDescriptionFactoryTest,
2979 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2980 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02002981 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002982 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002983 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002984
2985 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002986 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2987 RtpTransceiverDirection::kRecvOnly, kActive,
2988 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002989
Steve Anton6fe1fba2018-12-11 10:15:23 -08002990 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2991 std::unique_ptr<SessionDescription> answer =
2992 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002993
2994 const AudioContentDescription* acd =
2995 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002996 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002997
Artem Titov880fa812021-07-30 22:30:23 +02002998 // Now - let `f2_` add video with RTX and let the payload type the RTX codec
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002999 // reference be the same as an audio codec that was negotiated in the
3000 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07003001 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08003002 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003003
3004 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3005 int used_pl_type = acd->codecs()[0].id;
3006 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003007 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003008 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003009
kwiberg31022942016-03-11 14:18:21 -08003010 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003011 f2_.CreateOffer(opts, answer.get()));
3012 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003013 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003014 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3015
3016 const AudioContentDescription* updated_acd =
3017 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003018 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003019
3020 const VideoContentDescription* updated_vcd =
3021 GetFirstVideoContentDescription(updated_answer.get());
3022
3023 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003024 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003025 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003026 EXPECT_NE(used_pl_type, new_h264_pl_type);
3027 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003028 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003029 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3030 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3031}
3032
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003033// Create an updated offer with RTX after creating an answer to an offer
3034// without RTX, and with different default payload types.
3035// Verify that the added RTX codec references the correct payload type.
3036TEST_F(MediaSessionDescriptionFactoryTest,
3037 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3038 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003039 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003040
3041 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003042 // This creates rtx for H264 with the payload type `f2_` uses.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003043 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003044 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003045
Steve Anton6fe1fba2018-12-11 10:15:23 -08003046 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003047 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003048 std::unique_ptr<SessionDescription> answer =
3049 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003050
3051 const VideoContentDescription* vcd =
3052 GetFirstVideoContentDescription(answer.get());
3053
3054 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3055 EXPECT_EQ(expected_codecs, vcd->codecs());
3056
Artem Titov880fa812021-07-30 22:30:23 +02003057 // Now, ensure that the RTX codec is created correctly when `f2_` creates an
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003058 // updated offer, even though the default payload types are different from
Artem Titov880fa812021-07-30 22:30:23 +02003059 // those of `f1_`.
kwiberg31022942016-03-11 14:18:21 -08003060 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003061 f2_.CreateOffer(opts, answer.get()));
3062 ASSERT_TRUE(updated_offer);
3063
3064 const VideoContentDescription* updated_vcd =
3065 GetFirstVideoContentDescription(updated_offer.get());
3066
3067 // New offer should attempt to add H263, and RTX for H264.
3068 expected_codecs.push_back(kVideoCodecs2[1]);
3069 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3070 &expected_codecs);
3071 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3072}
3073
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003074// Test that RTX is ignored when there is no associated payload type parameter.
3075TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3076 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003077 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3078 RtpTransceiverDirection::kRecvOnly, kActive,
3079 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003080 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003081 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003082 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003083 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003084
3085 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003086 // This creates RTX for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003087 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003088 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003089
Steve Anton6fe1fba2018-12-11 10:15:23 -08003090 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003091 ASSERT_TRUE(offer.get() != NULL);
3092 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3093 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3094 // is possible to test that that RTX is dropped when
3095 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003096 MediaContentDescription* media_desc =
3097 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3098 ASSERT_TRUE(media_desc);
3099 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003100 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003101 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003102 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003103 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003104 }
3105 }
3106 desc->set_codecs(codecs);
3107
Steve Anton6fe1fba2018-12-11 10:15:23 -08003108 std::unique_ptr<SessionDescription> answer =
3109 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003110
Steve Anton64b626b2019-01-28 17:25:26 -08003111 EXPECT_THAT(
3112 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3113 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003114}
3115
3116// Test that RTX will be filtered out in the answer if its associated payload
3117// type doesn't match the local value.
3118TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3119 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003120 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3121 RtpTransceiverDirection::kRecvOnly, kActive,
3122 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003123 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3124 // This creates RTX for H264 in sender.
3125 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003126 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003127
3128 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3129 // This creates RTX for H263 in receiver.
3130 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003131 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003132
Steve Anton6fe1fba2018-12-11 10:15:23 -08003133 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003134 ASSERT_TRUE(offer.get() != NULL);
3135 // Associated payload type doesn't match, therefore, RTX codec is removed in
3136 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003137 std::unique_ptr<SessionDescription> answer =
3138 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003139
Steve Anton64b626b2019-01-28 17:25:26 -08003140 EXPECT_THAT(
3141 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3142 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003143}
3144
3145// Test that when multiple RTX codecs are offered, only the matched RTX codec
3146// is added in the answer, and the unsupported RTX codec is filtered out.
3147TEST_F(MediaSessionDescriptionFactoryTest,
3148 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3149 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003150 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3151 RtpTransceiverDirection::kRecvOnly, kActive,
3152 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003153 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3154 // This creates RTX for H264-SVC in sender.
3155 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003156 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003157
3158 // This creates RTX for H264 in sender.
3159 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003160 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003161
3162 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3163 // This creates RTX for H264 in receiver.
3164 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003165 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003166
3167 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3168 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003169 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003170 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003171 std::unique_ptr<SessionDescription> answer =
3172 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003173 const VideoContentDescription* vcd =
3174 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003175 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3176 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3177 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003178
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003179 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003180}
3181
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003182// Test that after one RTX codec has been negotiated, a new offer can attempt
3183// to add another.
3184TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3185 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003186 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3187 RtpTransceiverDirection::kRecvOnly, kActive,
3188 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003189 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3190 // This creates RTX for H264 for the offerer.
3191 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003192 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003193
Steve Anton6fe1fba2018-12-11 10:15:23 -08003194 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003195 ASSERT_TRUE(offer);
3196 const VideoContentDescription* vcd =
3197 GetFirstVideoContentDescription(offer.get());
3198
3199 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3200 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3201 &expected_codecs);
3202 EXPECT_EQ(expected_codecs, vcd->codecs());
3203
3204 // Now, attempt to add RTX for H264-SVC.
3205 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003206 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003207
kwiberg31022942016-03-11 14:18:21 -08003208 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003209 f1_.CreateOffer(opts, offer.get()));
3210 ASSERT_TRUE(updated_offer);
3211 vcd = GetFirstVideoContentDescription(updated_offer.get());
3212
3213 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3214 &expected_codecs);
3215 EXPECT_EQ(expected_codecs, vcd->codecs());
3216}
3217
Noah Richards2e7a0982015-05-18 14:02:54 -07003218// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3219// generated for each simulcast ssrc and correctly grouped.
3220TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3221 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003222 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3223 RtpTransceiverDirection::kSendRecv, kActive,
3224 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003225 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003226 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3227 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003228
3229 // Use a single real codec, and then add RTX for it.
3230 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003231 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003232 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003233 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003234
3235 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3236 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003237 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003238 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003239 MediaContentDescription* media_desc =
3240 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3241 ASSERT_TRUE(media_desc);
3242 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003243 const StreamParamsVec& streams = desc->streams();
3244 // Single stream.
3245 ASSERT_EQ(1u, streams.size());
3246 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3247 EXPECT_EQ(6u, streams[0].ssrcs.size());
3248 // And should have a SIM group for the simulcast.
3249 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3250 // And a FID group for RTX.
3251 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003252 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003253 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3254 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003255 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003256 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3257 EXPECT_EQ(3u, fid_ssrcs.size());
3258}
3259
brandtr03d5fb12016-11-22 03:37:59 -08003260// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003261// together with a FEC-FR grouping. Guarded by WebRTC-FlexFEC-03 trial.
brandtr03d5fb12016-11-22 03:37:59 -08003262TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003263 webrtc::test::ScopedFieldTrials override_field_trials(
3264 "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003265 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003266 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3267 RtpTransceiverDirection::kSendRecv, kActive,
3268 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003269 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003270 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3271 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003272
3273 // Use a single real codec, and then add FlexFEC for it.
3274 std::vector<VideoCodec> f1_codecs;
3275 f1_codecs.push_back(VideoCodec(97, "H264"));
3276 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003277 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003278
3279 // Ensure that the offer has a single FlexFEC ssrc and that
3280 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003281 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003282 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003283 MediaContentDescription* media_desc =
3284 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3285 ASSERT_TRUE(media_desc);
3286 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003287 const StreamParamsVec& streams = desc->streams();
3288 // Single stream.
3289 ASSERT_EQ(1u, streams.size());
3290 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3291 EXPECT_EQ(2u, streams[0].ssrcs.size());
3292 // And should have a FEC-FR group for FlexFEC.
3293 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3294 std::vector<uint32_t> primary_ssrcs;
3295 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3296 ASSERT_EQ(1u, primary_ssrcs.size());
3297 uint32_t flexfec_ssrc;
3298 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3299 EXPECT_NE(flexfec_ssrc, 0u);
3300}
3301
3302// Test that FlexFEC is disabled for simulcast.
3303// TODO(brandtr): Remove this test when we support simulcast, either through
3304// multiple FlexfecSenders, or through multistream protection.
3305TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003306 webrtc::test::ScopedFieldTrials override_field_trials(
3307 "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003308 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003309 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3310 RtpTransceiverDirection::kSendRecv, kActive,
3311 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003312 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003313 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3314 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003315
3316 // Use a single real codec, and then add FlexFEC for it.
3317 std::vector<VideoCodec> f1_codecs;
3318 f1_codecs.push_back(VideoCodec(97, "H264"));
3319 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003320 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003321
3322 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3323 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003324 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003325 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003326 MediaContentDescription* media_desc =
3327 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3328 ASSERT_TRUE(media_desc);
3329 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003330 const StreamParamsVec& streams = desc->streams();
3331 // Single stream.
3332 ASSERT_EQ(1u, streams.size());
3333 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3334 EXPECT_EQ(3u, streams[0].ssrcs.size());
3335 // And should have a SIM group for the simulcast.
3336 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3337 // And not a FEC-FR group for FlexFEC.
3338 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3339 std::vector<uint32_t> primary_ssrcs;
3340 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3341 EXPECT_EQ(3u, primary_ssrcs.size());
3342 for (uint32_t primary_ssrc : primary_ssrcs) {
3343 uint32_t flexfec_ssrc;
3344 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3345 }
3346}
3347
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003348// Create an updated offer after creating an answer to the original offer and
3349// verify that the RTP header extensions that were part of the original answer
3350// are not changed in the updated offer.
3351TEST_F(MediaSessionDescriptionFactoryTest,
3352 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3353 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003354 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003355
Markus Handell755c65d2020-06-24 01:06:10 +02003356 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3357 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003358 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02003359 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3360 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003361 std::unique_ptr<SessionDescription> answer =
3362 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003363
Yves Gerey665174f2018-06-19 15:03:05 +02003364 EXPECT_EQ(
3365 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3366 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3367 EXPECT_EQ(
3368 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3369 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003370
kwiberg31022942016-03-11 14:18:21 -08003371 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003372 f2_.CreateOffer(opts, answer.get()));
3373
3374 // The expected RTP header extensions in the new offer are the resulting
3375 // extensions from the first offer/answer exchange plus the extensions only
Artem Titov880fa812021-07-30 22:30:23 +02003376 // `f2_` offer.
3377 // Since the default local extension id `f2_` uses has already been used by
3378 // `f1_` for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003379 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003380 kAudioRtpExtensionAnswer[0],
3381 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003382 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003383 };
3384
Artem Titov880fa812021-07-30 22:30:23 +02003385 // Since the default local extension id `f2_` uses has already been used by
3386 // `f1_` for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003387 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003388 kVideoRtpExtensionAnswer[0],
3389 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003390 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003391 };
3392
3393 const AudioContentDescription* updated_acd =
3394 GetFirstAudioContentDescription(updated_offer.get());
3395 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3396 updated_acd->rtp_header_extensions());
3397
3398 const VideoContentDescription* updated_vcd =
3399 GetFirstVideoContentDescription(updated_offer.get());
3400 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3401 updated_vcd->rtp_header_extensions());
3402}
3403
deadbeefa5b273a2015-08-20 17:30:13 -07003404// Verify that if the same RTP extension URI is used for audio and video, the
3405// same ID is used. Also verify that the ID isn't changed when creating an
3406// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003407TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003408 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003409 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003410
Markus Handell755c65d2020-06-24 01:06:10 +02003411 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3412 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003413 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003414
3415 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3416 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003417 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003418 kVideoRtpExtension3[0],
3419 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003420 };
3421
Yves Gerey665174f2018-06-19 15:03:05 +02003422 EXPECT_EQ(
3423 MAKE_VECTOR(kAudioRtpExtension3),
3424 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3425 EXPECT_EQ(
3426 MAKE_VECTOR(kExpectedVideoRtpExtension),
3427 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003428
3429 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003430 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003431 f1_.CreateOffer(opts, offer.get()));
3432
3433 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003434 GetFirstAudioContentDescription(updated_offer.get())
3435 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003436 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003437 GetFirstVideoContentDescription(updated_offer.get())
3438 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003439}
3440
jbauch5869f502017-06-29 12:31:36 -07003441// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3442TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3443 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003444 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003445
3446 f1_.set_enable_encrypted_rtp_header_extensions(true);
3447 f2_.set_enable_encrypted_rtp_header_extensions(true);
3448
Markus Handell755c65d2020-06-24 01:06:10 +02003449 SetAudioVideoRtpHeaderExtensions(
3450 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3451 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003452 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003453
Yves Gerey665174f2018-06-19 15:03:05 +02003454 EXPECT_EQ(
3455 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3456 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3457 EXPECT_EQ(
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003458 MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003459 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003460
3461 // Nothing should change when creating a new offer
3462 std::unique_ptr<SessionDescription> updated_offer(
3463 f1_.CreateOffer(opts, offer.get()));
3464
3465 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003466 GetFirstAudioContentDescription(updated_offer.get())
3467 ->rtp_header_extensions());
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003468 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003469 GetFirstVideoContentDescription(updated_offer.get())
3470 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003471}
3472
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003473TEST(MediaSessionDescription, CopySessionDescription) {
3474 SessionDescription source;
3475 cricket::ContentGroup group(cricket::CN_AUDIO);
3476 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003477 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003478 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003479 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3480 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003481 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003482 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003483 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003484 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3485 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003486 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003487
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003488 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003489 ASSERT_TRUE(copy.get() != NULL);
3490 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3491 const ContentInfo* ac = copy->GetContentByName("audio");
3492 const ContentInfo* vc = copy->GetContentByName("video");
3493 ASSERT_TRUE(ac != NULL);
3494 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003495 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003496 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003497 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3498 EXPECT_EQ(1u, acd->first_ssrc());
3499
Steve Anton5adfafd2017-12-20 16:34:00 -08003500 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003501 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003502 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3503 EXPECT_EQ(2u, vcd->first_ssrc());
3504}
3505
3506// The below TestTransportInfoXXX tests create different offers/answers, and
3507// ensure the TransportInfo in the SessionDescription matches what we expect.
3508TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3509 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003510 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3511 RtpTransceiverDirection::kRecvOnly, kActive,
3512 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003513 TestTransportInfo(true, options, false);
3514}
3515
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003516TEST_F(MediaSessionDescriptionFactoryTest,
3517 TestTransportInfoOfferIceRenomination) {
3518 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003519 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3520 RtpTransceiverDirection::kRecvOnly, kActive,
3521 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003522 options.media_description_options[0]
3523 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003524 TestTransportInfo(true, options, false);
3525}
3526
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003527TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3528 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003529 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3530 RtpTransceiverDirection::kRecvOnly, kActive,
3531 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003532 TestTransportInfo(true, options, true);
3533}
3534
3535TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3536 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003537 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003538 TestTransportInfo(true, options, false);
3539}
3540
3541TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003542 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003543 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003544 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003545 TestTransportInfo(true, options, true);
3546}
3547
3548TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3549 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003550 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003551 options.bundle_enabled = true;
3552 TestTransportInfo(true, options, false);
3553}
3554
3555TEST_F(MediaSessionDescriptionFactoryTest,
3556 TestTransportInfoOfferBundleCurrent) {
3557 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003558 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003559 options.bundle_enabled = true;
3560 TestTransportInfo(true, options, true);
3561}
3562
3563TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3564 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003565 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3566 RtpTransceiverDirection::kRecvOnly, kActive,
3567 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003568 TestTransportInfo(false, options, false);
3569}
3570
3571TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003572 TestTransportInfoAnswerIceRenomination) {
3573 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003574 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3575 RtpTransceiverDirection::kRecvOnly, kActive,
3576 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003577 options.media_description_options[0]
3578 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003579 TestTransportInfo(false, options, false);
3580}
3581
3582TEST_F(MediaSessionDescriptionFactoryTest,
3583 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003584 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003585 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3586 RtpTransceiverDirection::kRecvOnly, kActive,
3587 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003588 TestTransportInfo(false, options, true);
3589}
3590
3591TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3592 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003593 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003594 TestTransportInfo(false, options, false);
3595}
3596
3597TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003598 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003599 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003600 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003601 TestTransportInfo(false, options, true);
3602}
3603
3604TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3605 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003607 options.bundle_enabled = true;
3608 TestTransportInfo(false, options, false);
3609}
3610
3611TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003612 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003613 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003614 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003615 options.bundle_enabled = true;
3616 TestTransportInfo(false, options, true);
3617}
3618
Harald Alvestrand0d018412021-11-04 13:52:31 +00003619// Create an offer with bundle enabled and verify the crypto parameters are
3620// the common set of the available cryptos.
3621TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3622 TestCryptoWithBundle(true);
3623}
3624
3625// Create an answer with bundle enabled and verify the crypto parameters are
3626// the common set of the available cryptos.
3627TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3628 TestCryptoWithBundle(false);
3629}
3630
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003631// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3632// DTLS is not enabled locally.
3633TEST_F(MediaSessionDescriptionFactoryTest,
3634 TestOfferDtlsSavpfWithoutDtlsFailed) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003635 f1_.set_secure(SEC_ENABLED);
3636 f2_.set_secure(SEC_ENABLED);
3637 tdf1_.set_secure(SEC_DISABLED);
3638 tdf2_.set_secure(SEC_DISABLED);
3639
Steve Anton6fe1fba2018-12-11 10:15:23 -08003640 std::unique_ptr<SessionDescription> offer =
3641 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003642 ASSERT_TRUE(offer.get() != NULL);
3643 ContentInfo* offer_content = offer->GetContentByName("audio");
3644 ASSERT_TRUE(offer_content != NULL);
3645 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003646 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003647 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3648
Steve Anton6fe1fba2018-12-11 10:15:23 -08003649 std::unique_ptr<SessionDescription> answer =
3650 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003651 ASSERT_TRUE(answer != NULL);
3652 ContentInfo* answer_content = answer->GetContentByName("audio");
3653 ASSERT_TRUE(answer_content != NULL);
3654
3655 ASSERT_TRUE(answer_content->rejected);
3656}
3657
3658// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3659// UDP/TLS/RTP/SAVPF.
3660TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003661 f1_.set_secure(SEC_ENABLED);
3662 f2_.set_secure(SEC_ENABLED);
3663 tdf1_.set_secure(SEC_ENABLED);
3664 tdf2_.set_secure(SEC_ENABLED);
3665
Steve Anton6fe1fba2018-12-11 10:15:23 -08003666 std::unique_ptr<SessionDescription> offer =
3667 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003668 ASSERT_TRUE(offer.get() != NULL);
3669 ContentInfo* offer_content = offer->GetContentByName("audio");
3670 ASSERT_TRUE(offer_content != NULL);
3671 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003672 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003673 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3674
Steve Anton6fe1fba2018-12-11 10:15:23 -08003675 std::unique_ptr<SessionDescription> answer =
3676 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003677 ASSERT_TRUE(answer != NULL);
3678
3679 const ContentInfo* answer_content = answer->GetContentByName("audio");
3680 ASSERT_TRUE(answer_content != NULL);
3681 ASSERT_FALSE(answer_content->rejected);
3682
3683 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003684 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003685 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003686}
3687
Harald Alvestrand0d018412021-11-04 13:52:31 +00003688// Test that we include both SDES and DTLS in the offer, but only include SDES
3689// in the answer if DTLS isn't negotiated.
3690TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3691 f1_.set_secure(SEC_ENABLED);
3692 f2_.set_secure(SEC_ENABLED);
3693 tdf1_.set_secure(SEC_ENABLED);
3694 tdf2_.set_secure(SEC_DISABLED);
3695 MediaSessionOptions options;
3696 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3697 std::unique_ptr<SessionDescription> offer, answer;
3698 const cricket::MediaContentDescription* audio_media_desc;
3699 const cricket::MediaContentDescription* video_media_desc;
3700 const cricket::TransportDescription* audio_trans_desc;
3701 const cricket::TransportDescription* video_trans_desc;
3702
3703 // Generate an offer with SDES and DTLS support.
3704 offer = f1_.CreateOffer(options, NULL);
3705 ASSERT_TRUE(offer.get() != NULL);
3706
3707 audio_media_desc = offer->GetContentDescriptionByName("audio");
3708 ASSERT_TRUE(audio_media_desc != NULL);
3709 video_media_desc = offer->GetContentDescriptionByName("video");
3710 ASSERT_TRUE(video_media_desc != NULL);
3711 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3712 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3713
3714 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3715 ASSERT_TRUE(audio_trans_desc != NULL);
3716 video_trans_desc = offer->GetTransportDescriptionByName("video");
3717 ASSERT_TRUE(video_trans_desc != NULL);
3718 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3719 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3720
3721 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
3722 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3723 ASSERT_TRUE(answer.get() != NULL);
3724
3725 audio_media_desc = answer->GetContentDescriptionByName("audio");
3726 ASSERT_TRUE(audio_media_desc != NULL);
3727 video_media_desc = answer->GetContentDescriptionByName("video");
3728 ASSERT_TRUE(video_media_desc != NULL);
3729 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3730 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3731
3732 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3733 ASSERT_TRUE(audio_trans_desc != NULL);
3734 video_trans_desc = answer->GetTransportDescriptionByName("video");
3735 ASSERT_TRUE(video_trans_desc != NULL);
3736 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3737 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3738
3739 // Enable DTLS; the answer should now only have DTLS support.
3740 tdf2_.set_secure(SEC_ENABLED);
3741 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3742 ASSERT_TRUE(answer.get() != NULL);
3743
3744 audio_media_desc = answer->GetContentDescriptionByName("audio");
3745 ASSERT_TRUE(audio_media_desc != NULL);
3746 video_media_desc = answer->GetContentDescriptionByName("video");
3747 ASSERT_TRUE(video_media_desc != NULL);
3748 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3749 EXPECT_TRUE(video_media_desc->cryptos().empty());
3750 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3751 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
3752
3753 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3754 ASSERT_TRUE(audio_trans_desc != NULL);
3755 video_trans_desc = answer->GetTransportDescriptionByName("video");
3756 ASSERT_TRUE(video_trans_desc != NULL);
3757 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3758 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3759
3760 // Try creating offer again. DTLS enabled now, crypto's should be empty
3761 // in new offer.
3762 offer = f1_.CreateOffer(options, offer.get());
3763 ASSERT_TRUE(offer.get() != NULL);
3764 audio_media_desc = offer->GetContentDescriptionByName("audio");
3765 ASSERT_TRUE(audio_media_desc != NULL);
3766 video_media_desc = offer->GetContentDescriptionByName("video");
3767 ASSERT_TRUE(video_media_desc != NULL);
3768 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3769 EXPECT_TRUE(video_media_desc->cryptos().empty());
3770
3771 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3772 ASSERT_TRUE(audio_trans_desc != NULL);
3773 video_trans_desc = offer->GetTransportDescriptionByName("video");
3774 ASSERT_TRUE(video_trans_desc != NULL);
3775 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3776 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3777}
3778
3779// Test that an answer can't be created if cryptos are required but the offer is
3780// unsecure.
3781TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
3782 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
3783 f1_.set_secure(SEC_DISABLED);
3784 tdf1_.set_secure(SEC_DISABLED);
3785 f2_.set_secure(SEC_REQUIRED);
3786 tdf1_.set_secure(SEC_ENABLED);
3787
3788 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
3789 ASSERT_TRUE(offer.get() != NULL);
3790 std::unique_ptr<SessionDescription> answer =
3791 f2_.CreateAnswer(offer.get(), options, NULL);
3792 EXPECT_TRUE(answer.get() == NULL);
3793}
3794
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003795// Test that we accept a DTLS offer without SDES and create an appropriate
3796// answer.
3797TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003798 f1_.set_secure(SEC_DISABLED);
3799 f2_.set_secure(SEC_ENABLED);
3800 tdf1_.set_secure(SEC_ENABLED);
3801 tdf2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003802 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003803 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003804
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003805 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003806 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003807 ASSERT_TRUE(offer.get() != NULL);
3808
Harald Alvestrand0d018412021-11-04 13:52:31 +00003809 const AudioContentDescription* audio_offer =
3810 GetFirstAudioContentDescription(offer.get());
3811 ASSERT_TRUE(audio_offer->cryptos().empty());
3812 const VideoContentDescription* video_offer =
3813 GetFirstVideoContentDescription(offer.get());
3814 ASSERT_TRUE(video_offer->cryptos().empty());
3815
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003816 const cricket::TransportDescription* audio_offer_trans_desc =
3817 offer->GetTransportDescriptionByName("audio");
3818 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3819 const cricket::TransportDescription* video_offer_trans_desc =
3820 offer->GetTransportDescriptionByName("video");
3821 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003822
3823 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003824 std::unique_ptr<SessionDescription> answer =
3825 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003826 ASSERT_TRUE(answer.get() != NULL);
3827
3828 const cricket::TransportDescription* audio_answer_trans_desc =
3829 answer->GetTransportDescriptionByName("audio");
3830 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3831 const cricket::TransportDescription* video_answer_trans_desc =
3832 answer->GetTransportDescriptionByName("video");
3833 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003834}
3835
3836// Verifies if vad_enabled option is set to false, CN codecs are not present in
3837// offer or answer.
3838TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3839 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003840 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003841 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003842 ASSERT_TRUE(offer.get() != NULL);
3843 const ContentInfo* audio_content = offer->GetContentByName("audio");
3844 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3845
3846 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003847 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003848 ASSERT_TRUE(offer.get() != NULL);
3849 audio_content = offer->GetContentByName("audio");
3850 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003851 std::unique_ptr<SessionDescription> answer =
3852 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003853 ASSERT_TRUE(answer.get() != NULL);
3854 audio_content = answer->GetContentByName("audio");
3855 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3856}
deadbeef44f08192015-12-15 16:20:09 -08003857
zhihuang1c378ed2017-08-17 14:10:50 -07003858// Test that the generated MIDs match the existing offer.
3859TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003860 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003861 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3862 RtpTransceiverDirection::kRecvOnly, kActive,
3863 &opts);
3864 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3865 RtpTransceiverDirection::kRecvOnly, kActive,
3866 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003867 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3868 RtpTransceiverDirection::kSendRecv, kActive,
3869 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003870 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003871 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003872 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003873 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003874
deadbeef44f08192015-12-15 16:20:09 -08003875 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3876 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3877 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3878 ASSERT_TRUE(audio_content != nullptr);
3879 ASSERT_TRUE(video_content != nullptr);
3880 ASSERT_TRUE(data_content != nullptr);
3881 EXPECT_EQ("audio_modified", audio_content->name);
3882 EXPECT_EQ("video_modified", video_content->name);
3883 EXPECT_EQ("data_modified", data_content->name);
3884}
zhihuangcf5b37c2016-05-05 11:44:35 -07003885
zhihuang1c378ed2017-08-17 14:10:50 -07003886// The following tests verify that the unified plan SDP is supported.
3887// Test that we can create an offer with multiple media sections of same media
3888// type.
3889TEST_F(MediaSessionDescriptionFactoryTest,
3890 CreateOfferWithMultipleAVMediaSections) {
3891 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003892 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3893 RtpTransceiverDirection::kSendRecv, kActive,
3894 &opts);
3895 AttachSenderToMediaDescriptionOptions(
3896 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003897
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003898 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3899 RtpTransceiverDirection::kSendRecv, kActive,
3900 &opts);
3901 AttachSenderToMediaDescriptionOptions(
3902 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003903
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003904 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3905 RtpTransceiverDirection::kSendRecv, kActive,
3906 &opts);
3907 AttachSenderToMediaDescriptionOptions(
3908 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003909
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003910 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3911 RtpTransceiverDirection::kSendRecv, kActive,
3912 &opts);
3913 AttachSenderToMediaDescriptionOptions(
3914 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003915 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003916 ASSERT_TRUE(offer);
3917
3918 ASSERT_EQ(4u, offer->contents().size());
3919 EXPECT_FALSE(offer->contents()[0].rejected);
3920 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003921 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003922 ASSERT_EQ(1u, acd->streams().size());
3923 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003924 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003925
3926 EXPECT_FALSE(offer->contents()[1].rejected);
3927 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003928 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003929 ASSERT_EQ(1u, vcd->streams().size());
3930 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003931 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003932
3933 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003934 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003935 ASSERT_EQ(1u, acd->streams().size());
3936 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003937 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003938
3939 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003940 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003941 ASSERT_EQ(1u, vcd->streams().size());
3942 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003943 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003944}
3945
3946// Test that we can create an answer with multiple media sections of same media
3947// type.
3948TEST_F(MediaSessionDescriptionFactoryTest,
3949 CreateAnswerWithMultipleAVMediaSections) {
3950 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003951 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3952 RtpTransceiverDirection::kSendRecv, kActive,
3953 &opts);
3954 AttachSenderToMediaDescriptionOptions(
3955 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003956
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003957 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3958 RtpTransceiverDirection::kSendRecv, kActive,
3959 &opts);
3960 AttachSenderToMediaDescriptionOptions(
3961 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003962
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003963 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3964 RtpTransceiverDirection::kSendRecv, kActive,
3965 &opts);
3966 AttachSenderToMediaDescriptionOptions(
3967 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003968
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003969 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3970 RtpTransceiverDirection::kSendRecv, kActive,
3971 &opts);
3972 AttachSenderToMediaDescriptionOptions(
3973 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003974
Steve Anton6fe1fba2018-12-11 10:15:23 -08003975 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003976 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003977 std::unique_ptr<SessionDescription> answer =
3978 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003979
3980 ASSERT_EQ(4u, answer->contents().size());
3981 EXPECT_FALSE(answer->contents()[0].rejected);
3982 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003983 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003984 ASSERT_EQ(1u, acd->streams().size());
3985 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003986 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003987
3988 EXPECT_FALSE(answer->contents()[1].rejected);
3989 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003990 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003991 ASSERT_EQ(1u, vcd->streams().size());
3992 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003993 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003994
3995 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003996 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003997 ASSERT_EQ(1u, acd->streams().size());
3998 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003999 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004000
4001 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004002 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004003 ASSERT_EQ(1u, vcd->streams().size());
4004 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004005 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004006}
4007
4008// Test that the media section will be rejected in offer if the corresponding
4009// MediaDescriptionOptions is stopped by the offerer.
4010TEST_F(MediaSessionDescriptionFactoryTest,
4011 CreateOfferWithMediaSectionStoppedByOfferer) {
4012 // Create an offer with two audio sections and one of them is stopped.
4013 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004014 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4015 RtpTransceiverDirection::kSendRecv, kActive,
4016 &offer_opts);
4017 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4018 RtpTransceiverDirection::kInactive, kStopped,
4019 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004020 std::unique_ptr<SessionDescription> offer =
4021 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004022 ASSERT_TRUE(offer);
4023 ASSERT_EQ(2u, offer->contents().size());
4024 EXPECT_FALSE(offer->contents()[0].rejected);
4025 EXPECT_TRUE(offer->contents()[1].rejected);
4026}
4027
4028// Test that the media section will be rejected in answer if the corresponding
4029// MediaDescriptionOptions is stopped by the offerer.
4030TEST_F(MediaSessionDescriptionFactoryTest,
4031 CreateAnswerWithMediaSectionStoppedByOfferer) {
4032 // Create an offer with two audio sections and one of them is stopped.
4033 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004034 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4035 RtpTransceiverDirection::kSendRecv, kActive,
4036 &offer_opts);
4037 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4038 RtpTransceiverDirection::kInactive, kStopped,
4039 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004040 std::unique_ptr<SessionDescription> offer =
4041 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004042 ASSERT_TRUE(offer);
4043 ASSERT_EQ(2u, offer->contents().size());
4044 EXPECT_FALSE(offer->contents()[0].rejected);
4045 EXPECT_TRUE(offer->contents()[1].rejected);
4046
4047 // Create an answer based on the offer.
4048 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004049 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4050 RtpTransceiverDirection::kSendRecv, kActive,
4051 &answer_opts);
4052 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4053 RtpTransceiverDirection::kSendRecv, kActive,
4054 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004055 std::unique_ptr<SessionDescription> answer =
4056 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004057 ASSERT_EQ(2u, answer->contents().size());
4058 EXPECT_FALSE(answer->contents()[0].rejected);
4059 EXPECT_TRUE(answer->contents()[1].rejected);
4060}
4061
4062// Test that the media section will be rejected in answer if the corresponding
4063// MediaDescriptionOptions is stopped by the answerer.
4064TEST_F(MediaSessionDescriptionFactoryTest,
4065 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4066 // Create an offer with two audio sections.
4067 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004068 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4069 RtpTransceiverDirection::kSendRecv, kActive,
4070 &offer_opts);
4071 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4072 RtpTransceiverDirection::kSendRecv, kActive,
4073 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004074 std::unique_ptr<SessionDescription> offer =
4075 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004076 ASSERT_TRUE(offer);
4077 ASSERT_EQ(2u, offer->contents().size());
4078 ASSERT_FALSE(offer->contents()[0].rejected);
4079 ASSERT_FALSE(offer->contents()[1].rejected);
4080
4081 // The answerer rejects one of the audio sections.
4082 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004083 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4084 RtpTransceiverDirection::kSendRecv, kActive,
4085 &answer_opts);
4086 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4087 RtpTransceiverDirection::kInactive, kStopped,
4088 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004089 std::unique_ptr<SessionDescription> answer =
4090 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004091 ASSERT_EQ(2u, answer->contents().size());
4092 EXPECT_FALSE(answer->contents()[0].rejected);
4093 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004094
4095 // The TransportInfo of the rejected m= section is expected to be added in the
4096 // answer.
4097 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004098}
4099
4100// Test the generated media sections has the same order of the
4101// corresponding MediaDescriptionOptions.
4102TEST_F(MediaSessionDescriptionFactoryTest,
4103 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4104 MediaSessionOptions opts;
4105 // This tests put video section first because normally audio comes first by
4106 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004107 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4108 RtpTransceiverDirection::kSendRecv, kActive,
4109 &opts);
4110 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4111 RtpTransceiverDirection::kSendRecv, kActive,
4112 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004113 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004114
4115 ASSERT_TRUE(offer);
4116 ASSERT_EQ(2u, offer->contents().size());
4117 EXPECT_EQ("video", offer->contents()[0].name);
4118 EXPECT_EQ("audio", offer->contents()[1].name);
4119}
4120
4121// Test that different media sections using the same codec have same payload
4122// type.
4123TEST_F(MediaSessionDescriptionFactoryTest,
4124 PayloadTypesSharedByMediaSectionsOfSameType) {
4125 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004126 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4127 RtpTransceiverDirection::kSendRecv, kActive,
4128 &opts);
4129 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4130 RtpTransceiverDirection::kSendRecv, kActive,
4131 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004132 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004133 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004134 ASSERT_TRUE(offer);
4135 ASSERT_EQ(2u, offer->contents().size());
4136 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004137 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004138 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004139 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004140 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4141 ASSERT_EQ(2u, vcd1->codecs().size());
4142 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4143 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4144 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4145 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4146
4147 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004148 std::unique_ptr<SessionDescription> answer =
4149 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004150 ASSERT_TRUE(answer);
4151 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004152 vcd1 = answer->contents()[0].media_description()->as_video();
4153 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004154 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4155 ASSERT_EQ(1u, vcd1->codecs().size());
4156 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4157 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4158}
4159
4160// Test that the codec preference order per media section is respected in
4161// subsequent offer.
4162TEST_F(MediaSessionDescriptionFactoryTest,
4163 CreateOfferRespectsCodecPreferenceOrder) {
4164 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004165 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4166 RtpTransceiverDirection::kSendRecv, kActive,
4167 &opts);
4168 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4169 RtpTransceiverDirection::kSendRecv, kActive,
4170 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004171 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004172 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004173 ASSERT_TRUE(offer);
4174 ASSERT_EQ(2u, offer->contents().size());
4175 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004176 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004177 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004178 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004179 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4180 EXPECT_EQ(video_codecs, vcd1->codecs());
4181 EXPECT_EQ(video_codecs, vcd2->codecs());
4182
4183 // Change the codec preference of the first video section and create a
4184 // follow-up offer.
4185 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4186 vcd1->set_codecs(video_codecs_reverse);
4187 std::unique_ptr<SessionDescription> updated_offer(
4188 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004189 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4190 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004191 // The video codec preference order should be respected.
4192 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4193 EXPECT_EQ(video_codecs, vcd2->codecs());
4194}
4195
4196// Test that the codec preference order per media section is respected in
4197// the answer.
4198TEST_F(MediaSessionDescriptionFactoryTest,
4199 CreateAnswerRespectsCodecPreferenceOrder) {
4200 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004201 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4202 RtpTransceiverDirection::kSendRecv, kActive,
4203 &opts);
4204 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4205 RtpTransceiverDirection::kSendRecv, kActive,
4206 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004207 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004208 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004209 ASSERT_TRUE(offer);
4210 ASSERT_EQ(2u, offer->contents().size());
4211 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004212 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004213 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004214 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004215 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4216 EXPECT_EQ(video_codecs, vcd1->codecs());
4217 EXPECT_EQ(video_codecs, vcd2->codecs());
4218
4219 // Change the codec preference of the first video section and create an
4220 // answer.
4221 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4222 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004223 std::unique_ptr<SessionDescription> answer =
4224 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004225 vcd1 = answer->contents()[0].media_description()->as_video();
4226 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004227 // The video codec preference order should be respected.
4228 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4229 EXPECT_EQ(video_codecs, vcd2->codecs());
4230}
4231
Zhi Huang6f367472017-11-22 13:20:02 -08004232// Test that when creating an answer, the codecs use local parameters instead of
4233// the remote ones.
4234TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4235 const std::string audio_param_name = "audio_param";
4236 const std::string audio_value1 = "audio_v1";
4237 const std::string audio_value2 = "audio_v2";
4238 const std::string video_param_name = "video_param";
4239 const std::string video_value1 = "video_v1";
4240 const std::string video_value2 = "video_v2";
4241
4242 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4243 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4244 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4245 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4246
4247 // Set the parameters for codecs.
4248 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4249 video_codecs1[0].SetParam(video_param_name, video_value1);
4250 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4251 video_codecs2[0].SetParam(video_param_name, video_value2);
4252
4253 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004254 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004255 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004256 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004257
4258 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004259 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4260 RtpTransceiverDirection::kSendRecv, kActive,
4261 &opts);
4262 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4263 RtpTransceiverDirection::kSendRecv, kActive,
4264 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004265
Steve Anton6fe1fba2018-12-11 10:15:23 -08004266 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004267 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004268 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4269 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004270 std::string value;
4271 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4272 EXPECT_EQ(audio_value1, value);
4273 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4274 EXPECT_EQ(video_value1, value);
4275
Steve Anton6fe1fba2018-12-11 10:15:23 -08004276 std::unique_ptr<SessionDescription> answer =
4277 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004278 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004279 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4280 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004281 // Use the parameters from the local codecs.
4282 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4283 EXPECT_EQ(audio_value2, value);
4284 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4285 EXPECT_EQ(video_value2, value);
4286}
4287
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004288// Test that matching packetization-mode is part of the criteria for matching
4289// H264 codecs (in addition to profile-level-id). Previously, this was not the
4290// case, so the first H264 codec with the same profile-level-id would match and
4291// the payload type in the answer would be incorrect.
4292// This is a regression test for bugs.webrtc.org/8808
4293TEST_F(MediaSessionDescriptionFactoryTest,
4294 H264MatchCriteriaIncludesPacketizationMode) {
4295 // Create two H264 codecs with the same profile level ID and different
4296 // packetization modes.
4297 VideoCodec h264_pm0(96, "H264");
4298 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4299 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4300 VideoCodec h264_pm1(97, "H264");
4301 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4302 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4303
4304 // Offerer will send both codecs, answerer should choose the one with matching
4305 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004306 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4307 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004308
4309 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004310 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4311 RtpTransceiverDirection::kSendRecv, kActive,
4312 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004313
Steve Anton6fe1fba2018-12-11 10:15:23 -08004314 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004315 ASSERT_TRUE(offer);
4316
Steve Anton6fe1fba2018-12-11 10:15:23 -08004317 std::unique_ptr<SessionDescription> answer =
4318 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004319 ASSERT_TRUE(answer);
4320
4321 // Answer should have one negotiated codec with packetization-mode=1 using the
4322 // offered payload type.
4323 ASSERT_EQ(1u, answer->contents().size());
4324 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4325 ASSERT_EQ(1u, answer_vcd->codecs().size());
4326 auto answer_codec = answer_vcd->codecs()[0];
4327 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4328}
4329
zhihuangcf5b37c2016-05-05 11:44:35 -07004330class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4331 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004332 MediaProtocolTest()
4333 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004334 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4335 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004336 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4337 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -07004338 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4339 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004340 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4341 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004342 f1_.set_secure(SEC_ENABLED);
4343 f2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004344 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004345 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004346 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004347 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004348 tdf1_.set_secure(SEC_ENABLED);
4349 tdf2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004350 }
4351
4352 protected:
4353 MediaSessionDescriptionFactory f1_;
4354 MediaSessionDescriptionFactory f2_;
4355 TransportDescriptionFactory tdf1_;
4356 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004357 UniqueRandomIdGenerator ssrc_generator1;
4358 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004359};
4360
4361TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4362 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004363 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004364 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004365 ASSERT_TRUE(offer.get() != nullptr);
4366 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004367 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004368 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004369 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004370 std::unique_ptr<SessionDescription> answer =
4371 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004372 const ContentInfo* ac = answer->GetContentByName("audio");
4373 const ContentInfo* vc = answer->GetContentByName("video");
4374 ASSERT_TRUE(ac != nullptr);
4375 ASSERT_TRUE(vc != nullptr);
4376 EXPECT_FALSE(ac->rejected); // the offer is accepted
4377 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004378 const AudioContentDescription* acd = ac->media_description()->as_audio();
4379 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004380 EXPECT_EQ(GetParam(), acd->protocol());
4381 EXPECT_EQ(GetParam(), vcd->protocol());
4382}
4383
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004384INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4385 MediaProtocolTest,
4386 ::testing::ValuesIn(kMediaProtocols));
4387INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4388 MediaProtocolTest,
4389 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004390
4391TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4392 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004393 UniqueRandomIdGenerator ssrc_generator;
4394 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004395 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4396 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4397
4398 // The merged list of codecs should contain any send codecs that are also
4399 // nominally in the recieve codecs list. Payload types should be picked from
4400 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4401 // (set to 1). This equals what happens when the send codecs are used in an
4402 // offer and the receive codecs are used in the following answer.
4403 const std::vector<AudioCodec> sendrecv_codecs =
4404 MAKE_VECTOR(kAudioCodecsAnswer);
4405 const std::vector<AudioCodec> no_codecs;
4406
4407 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4408 << "Please don't change shared test data!";
4409 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4410 << "Please don't change shared test data!";
4411 // Alter iLBC send codec to have zero channels, to test that that is handled
4412 // properly.
4413 send_codecs[1].channels = 0;
4414
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004415 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004416 // are handled properly.
4417 recv_codecs[2].name = "ilbc";
4418
4419 // Test proper merge
4420 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004421 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4422 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4423 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004424
4425 // Test empty send codecs list
4426 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004427 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4428 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4429 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004430
4431 // Test empty recv codecs list
4432 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004433 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4434 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4435 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004436
4437 // Test all empty codec lists
4438 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004439 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4440 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4441 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004442}
4443
4444namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004445// Compare the two vectors of codecs ignoring the payload type.
4446template <class Codec>
4447bool CodecsMatch(const std::vector<Codec>& codecs1,
4448 const std::vector<Codec>& codecs2) {
4449 if (codecs1.size() != codecs2.size()) {
4450 return false;
4451 }
4452
4453 for (size_t i = 0; i < codecs1.size(); ++i) {
4454 if (!codecs1[i].Matches(codecs2[i])) {
4455 return false;
4456 }
4457 }
4458 return true;
4459}
4460
Steve Anton4e70a722017-11-28 14:57:10 -08004461void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004462 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004463 UniqueRandomIdGenerator ssrc_generator;
4464 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004465 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4466 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4467 const std::vector<AudioCodec> sendrecv_codecs =
4468 MAKE_VECTOR(kAudioCodecsAnswer);
4469 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004470
4471 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004472 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4473 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004474
Steve Anton4e70a722017-11-28 14:57:10 -08004475 if (direction == RtpTransceiverDirection::kSendRecv ||
4476 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004477 AttachSenderToMediaDescriptionOptions(
4478 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004479 }
ossu075af922016-06-14 03:29:38 -07004480
Steve Anton6fe1fba2018-12-11 10:15:23 -08004481 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004482 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004483 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004484
4485 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004486 // that the codecs put in are right. This happens when we neither want to
4487 // send nor receive audio. The checks are still in place if at some point
4488 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004489 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004490 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004491 // sendrecv and inactive should both present lists as if the channel was
4492 // to be used for sending and receiving. Inactive essentially means it
4493 // might eventually be used anything, but we don't know more at this
4494 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004495 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004496 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004497 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004498 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004499 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004500 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004501 }
4502 }
4503}
4504
4505static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004506 AudioCodec(0, "codec0", 16000, -1, 1),
4507 AudioCodec(1, "codec1", 8000, 13300, 1),
4508 AudioCodec(2, "codec2", 8000, 64000, 1),
4509 AudioCodec(3, "codec3", 8000, 64000, 1),
4510 AudioCodec(4, "codec4", 8000, 0, 2),
4511 AudioCodec(5, "codec5", 32000, 0, 1),
4512 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004513
zhihuang1c378ed2017-08-17 14:10:50 -07004514/* The codecs groups below are chosen as per the matrix below. The objective
4515 * is to have different sets of codecs in the inputs, to get unique sets of
4516 * codecs after negotiation, depending on offer and answer communication
4517 * directions. One-way directions in the offer should either result in the
4518 * opposite direction in the answer, or an inactive answer. Regardless, the
4519 * choice of codecs should be as if the answer contained the opposite
4520 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004521 *
4522 * | Offer | Answer | Result
4523 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4524 * 0 | x - - | - x - | x - - - -
4525 * 1 | x x x | - x - | x - - x -
4526 * 2 | - x - | x - - | - x - - -
4527 * 3 | x x x | x - - | - x x - -
4528 * 4 | - x - | x x x | - x - - -
4529 * 5 | x - - | x x x | x - - - -
4530 * 6 | x x x | x x x | x x x x x
4531 */
4532// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004533static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4534static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004535// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4536// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004537static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4538static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004539// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004540static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4541static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4542static const int kResultSendrecv_SendCodecs[] = {3, 6};
4543static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4544static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004545
4546template <typename T, int IDXS>
4547std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4548 std::vector<T> out;
4549 out.reserve(IDXS);
4550 for (int idx : indices)
4551 out.push_back(array[idx]);
4552
4553 return out;
4554}
4555
Steve Anton4e70a722017-11-28 14:57:10 -08004556void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4557 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004558 bool add_legacy_stream) {
4559 TransportDescriptionFactory offer_tdf;
4560 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004561 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4562 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4563 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004564 offer_factory.set_audio_codecs(
4565 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4566 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4567 answer_factory.set_audio_codecs(
4568 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4569 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4570
ossu075af922016-06-14 03:29:38 -07004571 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004572 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4573 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004574
Steve Anton4e70a722017-11-28 14:57:10 -08004575 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004576 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4577 kAudioTrack1, {kMediaStream1}, 1,
4578 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004579 }
4580
Steve Anton6fe1fba2018-12-11 10:15:23 -08004581 std::unique_ptr<SessionDescription> offer =
4582 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004583 ASSERT_TRUE(offer.get() != NULL);
4584
4585 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004586 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4587 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004588
Steve Anton4e70a722017-11-28 14:57:10 -08004589 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004590 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4591 kAudioTrack1, {kMediaStream1}, 1,
4592 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004593 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004594 std::unique_ptr<SessionDescription> answer =
4595 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004596 const ContentInfo* ac = answer->GetContentByName("audio");
4597
zhihuang1c378ed2017-08-17 14:10:50 -07004598 // If the factory didn't add any audio content to the answer, we cannot
4599 // check that the codecs put in are right. This happens when we neither want
4600 // to send nor receive audio. The checks are still in place if at some point
4601 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004602 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004603 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4604 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004605
ossu075af922016-06-14 03:29:38 -07004606 std::vector<AudioCodec> target_codecs;
4607 // For offers with sendrecv or inactive, we should never reply with more
4608 // codecs than offered, with these codec sets.
4609 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004610 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004611 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4612 kResultSendrecv_SendrecvCodecs);
4613 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004614 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004615 target_codecs =
4616 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004617 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004618 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004619 target_codecs =
4620 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004621 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004622 case RtpTransceiverDirection::kSendRecv:
4623 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004624 target_codecs =
4625 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004626 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004627 target_codecs =
4628 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004629 } else {
4630 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4631 kResultSendrecv_SendrecvCodecs);
4632 }
4633 break;
Harald Alvestrand6060df52020-08-11 09:54:02 +02004634 case RtpTransceiverDirection::kStopped:
4635 // This does not happen in any current test.
Artem Titovd3251962021-11-15 16:57:07 +01004636 RTC_DCHECK_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004637 }
4638
zhihuang1c378ed2017-08-17 14:10:50 -07004639 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004640 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004641 bool first = true;
4642 os << "{";
4643 for (const auto& c : codecs) {
4644 os << (first ? " " : ", ") << c.id;
4645 first = false;
4646 }
4647 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004648 return os.Release();
ossu075af922016-06-14 03:29:38 -07004649 };
4650
4651 EXPECT_TRUE(acd->codecs() == target_codecs)
4652 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004653 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4654 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004655 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004656 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4657 << "; got: "
4658 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004659 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004660 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004661 << "Only inactive offers are allowed to not generate any audio "
4662 "content";
ossu075af922016-06-14 03:29:38 -07004663 }
4664}
brandtr03d5fb12016-11-22 03:37:59 -08004665
4666} // namespace
ossu075af922016-06-14 03:29:38 -07004667
4668class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004669 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004670
4671TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004672 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004673}
4674
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004675INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4676 AudioCodecsOfferTest,
4677 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4678 RtpTransceiverDirection::kRecvOnly,
4679 RtpTransceiverDirection::kSendRecv,
4680 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004681
4682class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004683 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4684 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004685 bool>> {};
ossu075af922016-06-14 03:29:38 -07004686
4687TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004688 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4689 ::testing::get<1>(GetParam()),
4690 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004691}
4692
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004693INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004694 MediaSessionDescriptionFactoryTest,
4695 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004696 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4697 RtpTransceiverDirection::kRecvOnly,
4698 RtpTransceiverDirection::kSendRecv,
4699 RtpTransceiverDirection::kInactive),
4700 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4701 RtpTransceiverDirection::kRecvOnly,
4702 RtpTransceiverDirection::kSendRecv,
4703 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004704 ::testing::Bool()));