blob: 9d01e0772f8ec6d7f26a6696d140508ca822f50d [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/media_session.h"
12
Harald Alvestrandc24a2182022-02-23 13:44:59 +000013#include <stddef.h>
14
Amit Hilbuch77938e62018-12-21 09:23:38 -080015#include <algorithm>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000016#include <cstdint>
17#include <map>
kwiberg31022942016-03-11 14:18:21 -080018#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <string>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000020#include <tuple>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000021#include <vector>
22
Steve Anton64b626b2019-01-28 17:25:26 -080023#include "absl/algorithm/container.h"
Mirko Bonadei57cabed2020-04-01 12:03:11 +020024#include "absl/strings/match.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000025#include "absl/strings/string_view.h"
26#include "api/candidate.h"
27#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "media/base/codec.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000029#include "media/base/media_constants.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020031#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "p2p/base/p2p_constants.h"
33#include "p2p/base/transport_description.h"
34#include "p2p/base/transport_info.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000035#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080036#include "pc/rtp_media_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000037#include "rtc_base/arraysize.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080039#include "rtc_base/fake_ssl_identity.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000040#include "rtc_base/rtc_certificate.h"
41#include "rtc_base/ssl_identity.h"
42#include "rtc_base/ssl_stream_adapter.h"
43#include "rtc_base/string_encode.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020044#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080045#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080046#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000047#include "test/gtest.h"
Jonas Orelanded99dae2022-03-09 09:28:10 +010048#include "test/scoped_key_value_config.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049
Harald Alvestrand0d018412021-11-04 13:52:31 +000050#define ASSERT_CRYPTO(cd, s, cs) \
51 ASSERT_EQ(s, cd->cryptos().size()); \
52 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
53
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054typedef std::vector<cricket::Candidate> Candidates;
55
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080056using cricket::AudioCodec;
57using cricket::AudioContentDescription;
58using cricket::ContentInfo;
Harald Alvestrand0d018412021-11-04 13:52:31 +000059using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080060using cricket::GetFirstAudioContent;
61using cricket::GetFirstAudioContentDescription;
62using cricket::GetFirstDataContent;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080063using cricket::GetFirstVideoContent;
64using cricket::GetFirstVideoContentDescription;
65using cricket::kAutoBandwidth;
66using cricket::MEDIA_TYPE_AUDIO;
67using cricket::MEDIA_TYPE_DATA;
68using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070070using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080071using cricket::MediaProtocolType;
72using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073using cricket::MediaSessionOptions;
74using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080075using cricket::RidDescription;
76using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020077using cricket::SctpDataContentDescription;
Harald Alvestrand0d018412021-11-04 13:52:31 +000078using cricket::SEC_DISABLED;
79using cricket::SEC_ENABLED;
80using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080082using cricket::SimulcastDescription;
83using cricket::SimulcastLayer;
84using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085using cricket::SsrcGroup;
86using cricket::StreamParams;
87using cricket::StreamParamsVec;
88using cricket::TransportDescription;
89using cricket::TransportDescriptionFactory;
90using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080092using cricket::VideoContentDescription;
Mirko Bonadei7750d802021-07-26 17:27:42 +020093using rtc::kCsAeadAes128Gcm;
94using rtc::kCsAeadAes256Gcm;
95using rtc::kCsAesCm128HmacSha1_32;
96using rtc::kCsAesCm128HmacSha1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080097using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020098using ::testing::Contains;
99using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +0100100using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200101using ::testing::ElementsAreArray;
102using ::testing::Eq;
103using ::testing::Field;
104using ::testing::IsEmpty;
105using ::testing::IsFalse;
106using ::testing::Ne;
107using ::testing::Not;
108using ::testing::Pointwise;
109using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700110using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800111using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
113static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700114 AudioCodec(103, "ISAC", 16000, -1, 1),
115 AudioCodec(102, "iLBC", 8000, 13300, 1),
116 AudioCodec(0, "PCMU", 8000, 64000, 1),
117 AudioCodec(8, "PCMA", 8000, 64000, 1),
118 AudioCodec(117, "red", 8000, 0, 1),
119 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120
121static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200122 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700123 AudioCodec(0, "PCMU", 8000, 64000, 1),
124 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125};
126
127static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700128 AudioCodec(102, "iLBC", 8000, 13300, 1),
129 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130};
131
perkj26752742016-10-24 01:21:16 -0700132static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
133 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
zhihuang1c378ed2017-08-17 14:10:50 -0700135static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
136 VideoCodec(96, "H264-SVC")};
137
perkj26752742016-10-24 01:21:16 -0700138static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
139 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140
perkj26752742016-10-24 01:21:16 -0700141static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142
isheriff6f8d6862016-05-26 11:24:55 -0700143static const RtpExtension kAudioRtpExtension1[] = {
144 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
145 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146};
147
jbauch5869f502017-06-29 12:31:36 -0700148static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
149 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
150 RtpExtension("http://google.com/testing/audio_something", 10),
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200152 RtpExtension("http://google.com/testing/audio_something", 11, true),
jbauch5869f502017-06-29 12:31:36 -0700153};
154
isheriff6f8d6862016-05-26 11:24:55 -0700155static const RtpExtension kAudioRtpExtension2[] = {
156 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
157 RtpExtension("http://google.com/testing/audio_something_else", 8),
158 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159};
160
isheriff6f8d6862016-05-26 11:24:55 -0700161static const RtpExtension kAudioRtpExtension3[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700164};
165
jbauch5869f502017-06-29 12:31:36 -0700166static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
167 RtpExtension("http://google.com/testing/audio_something", 2),
168 // Use RTP extension that supports encryption.
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
170};
171
172static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
173 RtpExtension("http://google.com/testing/audio_something", 2),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200175 RtpExtension("http://google.com/testing/audio_something", 14, true),
176 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
177};
178
179static const RtpExtension kVideoRtpExtension3ForEncryptionOffer[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
182 RtpExtension("http://google.com/testing/video_something", 12, true),
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
jbauch5869f502017-06-29 12:31:36 -0700184};
185
isheriff6f8d6862016-05-26 11:24:55 -0700186static const RtpExtension kAudioRtpExtensionAnswer[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188};
189
jbauch5869f502017-06-29 12:31:36 -0700190static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
192};
193
isheriff6f8d6862016-05-26 11:24:55 -0700194static const RtpExtension kVideoRtpExtension1[] = {
195 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
196 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197};
198
jbauch5869f502017-06-29 12:31:36 -0700199static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
200 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
201 RtpExtension("http://google.com/testing/video_something", 13),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200202 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
203 RtpExtension("http://google.com/testing/video_something", 7, true),
jbauch5869f502017-06-29 12:31:36 -0700204};
205
isheriff6f8d6862016-05-26 11:24:55 -0700206static const RtpExtension kVideoRtpExtension2[] = {
207 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
208 RtpExtension("http://google.com/testing/video_something_else", 14),
209 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210};
211
isheriff6f8d6862016-05-26 11:24:55 -0700212static const RtpExtension kVideoRtpExtension3[] = {
213 RtpExtension("http://google.com/testing/video_something", 4),
214 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700215};
216
jbauch5869f502017-06-29 12:31:36 -0700217static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
218 RtpExtension("http://google.com/testing/video_something", 4),
219 // Use RTP extension that supports encryption.
220 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
221};
222
isheriff6f8d6862016-05-26 11:24:55 -0700223static const RtpExtension kVideoRtpExtensionAnswer[] = {
224 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225};
226
jbauch5869f502017-06-29 12:31:36 -0700227static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200228 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
jbauch5869f502017-06-29 12:31:36 -0700229};
230
Johannes Kronce8e8672019-02-22 13:06:44 +0100231static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
232 RtpExtension("http://www.ietf.org/id/"
233 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
234 1),
235};
236
237static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
238 RtpExtension("http://www.ietf.org/id/"
239 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
240 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100241 RtpExtension(
242 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
243 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100244};
245
246static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100247 RtpExtension(
248 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
249 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100250};
251
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100252static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
253 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
254 "generic-frame-descriptor-00",
255 3),
256};
257
Peter Boström0c4e06b2015-10-07 12:23:21 +0200258static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
259static const uint32_t kSimSsrc[] = {10, 20, 30};
260static const uint32_t kFec1Ssrc[] = {10, 11};
261static const uint32_t kFec2Ssrc[] = {20, 21};
262static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263
264static const char kMediaStream1[] = "stream_1";
265static const char kMediaStream2[] = "stream_2";
266static const char kVideoTrack1[] = "video_1";
267static const char kVideoTrack2[] = "video_2";
268static const char kAudioTrack1[] = "audio_1";
269static const char kAudioTrack2[] = "audio_2";
270static const char kAudioTrack3[] = "audio_3";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271
zhihuangcf5b37c2016-05-05 11:44:35 -0700272static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
273 "RTP/SAVPF"};
274static const char* kMediaProtocolsDtls[] = {
275 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
276 "UDP/TLS/RTP/SAVP"};
277
Harald Alvestrand0d018412021-11-04 13:52:31 +0000278// SRTP cipher name negotiated by the tests. This must be updated if the
279// default changes.
280static const char* kDefaultSrtpCryptoSuite = kCsAesCm128HmacSha1_80;
281static const char* kDefaultSrtpCryptoSuiteGcm = kCsAeadAes256Gcm;
282
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800283// These constants are used to make the code using "AddMediaDescriptionOptions"
284// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700285static constexpr bool kStopped = true;
286static constexpr bool kActive = false;
287
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000288static bool IsMediaContentOfType(const ContentInfo* content,
289 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800290 RTC_DCHECK(content);
291 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000292}
293
Steve Anton4e70a722017-11-28 14:57:10 -0800294static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800295 RTC_DCHECK(content);
296 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000297}
298
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000299static void AddRtxCodec(const VideoCodec& rtx_codec,
300 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800301 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000302 codecs->push_back(rtx_codec);
303}
304
305template <class T>
306static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
307 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100308 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000309 for (const auto& codec : codecs) {
310 codec_names.push_back(codec.name);
311 }
312 return codec_names;
313}
314
zhihuang1c378ed2017-08-17 14:10:50 -0700315// This is used for test only. MIDs are not the identification of the
316// MediaDescriptionOptions since some end points may not support MID and the SDP
317// may not contain 'mid'.
318std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
319 const std::string& mid,
320 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800321 return absl::c_find_if(
322 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700323 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
324}
325
326std::vector<MediaDescriptionOptions>::const_iterator
327FindFirstMediaDescriptionByMid(const std::string& mid,
328 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800329 return absl::c_find_if(
330 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700331 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700332}
333
Artem Titov880fa812021-07-30 22:30:23 +0200334// Add a media section to the `session_options`.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800335static void AddMediaDescriptionOptions(MediaType type,
336 const std::string& mid,
337 RtpTransceiverDirection direction,
338 bool stopped,
339 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800340 opts->media_description_options.push_back(
341 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700342}
343
Steve Anton4e70a722017-11-28 14:57:10 -0800344static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700345 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800346 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
347 opts);
348 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
349 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700350}
351
Florent Castelli516e2842021-04-19 15:29:50 +0200352static void AddDataSection(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700353 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800354 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700355}
356
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800357static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700358 const std::string& mid,
359 MediaType type,
360 const std::string& track_id,
361 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800362 const std::vector<RidDescription>& rids,
363 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700364 int num_sim_layer,
365 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700366 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
367 switch (type) {
368 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700369 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700370 break;
371 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800372 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
373 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700374 break;
zhihuang1c378ed2017-08-17 14:10:50 -0700375 default:
Artem Titovd3251962021-11-15 16:57:07 +0100376 RTC_DCHECK_NOTREACHED();
zhihuang1c378ed2017-08-17 14:10:50 -0700377 }
378}
379
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800380static void AttachSenderToMediaDescriptionOptions(
381 const std::string& mid,
382 MediaType type,
383 const std::string& track_id,
384 const std::vector<std::string>& stream_ids,
385 int num_sim_layer,
386 MediaSessionOptions* session_options) {
387 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
388 SimulcastLayerList(), num_sim_layer,
389 session_options);
390}
391
zhihuang1c378ed2017-08-17 14:10:50 -0700392static void DetachSenderFromMediaSection(const std::string& mid,
393 const std::string& track_id,
394 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700395 std::vector<cricket::SenderOptions>& sender_options_list =
396 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
397 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800398 absl::c_find_if(sender_options_list,
399 [track_id](const cricket::SenderOptions& sender_options) {
400 return sender_options.track_id == track_id;
401 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700402 RTC_DCHECK(sender_it != sender_options_list.end());
403 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700404}
405
406// Helper function used to create a default MediaSessionOptions for Plan B SDP.
407// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
408static MediaSessionOptions CreatePlanBMediaSessionOptions() {
409 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800410 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
411 RtpTransceiverDirection::kRecvOnly, kActive,
412 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700413 return session_options;
414}
415
Harald Alvestrand0d018412021-11-04 13:52:31 +0000416// prefers GCM SDES crypto suites by removing non-GCM defaults.
417void PreferGcmCryptoParameters(CryptoParamsVec* cryptos) {
418 cryptos->erase(
419 std::remove_if(cryptos->begin(), cryptos->end(),
420 [](const cricket::CryptoParams& crypto) {
421 return crypto.cipher_suite != kCsAeadAes256Gcm &&
422 crypto.cipher_suite != kCsAeadAes128Gcm;
423 }),
424 cryptos->end());
425}
426
zhihuang1c378ed2017-08-17 14:10:50 -0700427// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
428// was designed for Plan B SDP, where only one audio "m=" section and one video
429// "m=" section could be generated, and ordering couldn't be controlled. Many of
430// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200431class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800433 MediaSessionDescriptionFactoryTest()
Jonas Orelanded99dae2022-03-09 09:28:10 +0100434 : tdf1_(field_trials),
435 tdf2_(field_trials),
436 f1_(&tdf1_, &ssrc_generator1),
437 f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700438 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
439 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200440 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
441 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -0700442 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
443 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200444 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
445 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000446 tdf1_.set_certificate(rtc::RTCCertificate::Create(
447 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
448 tdf2_.set_certificate(rtc::RTCCertificate::Create(
449 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 }
451
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000452 // Create a video StreamParamsVec object with:
453 // - one video stream with 3 simulcast streams and FEC,
454 StreamParamsVec CreateComplexVideoStreamParamsVec() {
455 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
456 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
457 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
458 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
459
460 std::vector<SsrcGroup> ssrc_groups;
461 ssrc_groups.push_back(sim_group);
462 ssrc_groups.push_back(fec_group1);
463 ssrc_groups.push_back(fec_group2);
464 ssrc_groups.push_back(fec_group3);
465
466 StreamParams simulcast_params;
467 simulcast_params.id = kVideoTrack1;
468 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
469 simulcast_params.ssrc_groups = ssrc_groups;
470 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800471 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000472
473 StreamParamsVec video_streams;
474 video_streams.push_back(simulcast_params);
475
476 return video_streams;
477 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000478
Harald Alvestrand0d018412021-11-04 13:52:31 +0000479 bool CompareCryptoParams(const CryptoParamsVec& c1,
480 const CryptoParamsVec& c2) {
481 if (c1.size() != c2.size())
482 return false;
483 for (size_t i = 0; i < c1.size(); ++i)
484 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
485 c1[i].key_params != c2[i].key_params ||
486 c1[i].session_params != c2[i].session_params)
487 return false;
488 return true;
489 }
490
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700491 // Returns true if the transport info contains "renomination" as an
492 // ICE option.
493 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800494 return absl::c_linear_search(transport_info->description.transport_options,
495 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700496 }
497
zhihuang1c378ed2017-08-17 14:10:50 -0700498 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700499 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 bool has_current_desc) {
501 const std::string current_audio_ufrag = "current_audio_ufrag";
502 const std::string current_audio_pwd = "current_audio_pwd";
503 const std::string current_video_ufrag = "current_video_ufrag";
504 const std::string current_video_pwd = "current_video_pwd";
505 const std::string current_data_ufrag = "current_data_ufrag";
506 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800507 std::unique_ptr<SessionDescription> current_desc;
508 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200510 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800511 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200512 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800513 TransportDescription(current_audio_ufrag, current_audio_pwd)));
514 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200515 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800516 TransportDescription(current_video_ufrag, current_video_pwd)));
517 current_desc->AddTransportInfo(TransportInfo(
518 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 }
520 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800521 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522 } else {
kwiberg31022942016-03-11 14:18:21 -0800523 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800524 offer = f1_.CreateOffer(options, NULL);
525 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 }
527 ASSERT_TRUE(desc.get() != NULL);
528 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000529 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 EXPECT_TRUE(ti_audio != NULL);
531 if (has_current_desc) {
532 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
533 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
534 } else {
535 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
536 ti_audio->description.ice_ufrag.size());
537 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
538 ti_audio->description.ice_pwd.size());
539 }
zhihuang1c378ed2017-08-17 14:10:50 -0700540 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700541 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700542 EXPECT_EQ(
543 media_desc_options_it->transport_options.enable_ice_renomination,
544 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 } else {
546 EXPECT_TRUE(ti_audio == NULL);
547 }
548 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000549 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700551 auto media_desc_options_it =
552 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 if (options.bundle_enabled) {
554 EXPECT_EQ(ti_audio->description.ice_ufrag,
555 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200556 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 } else {
558 if (has_current_desc) {
559 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
560 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
561 } else {
562 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
563 ti_video->description.ice_ufrag.size());
564 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
565 ti_video->description.ice_pwd.size());
566 }
567 }
zhihuang1c378ed2017-08-17 14:10:50 -0700568 EXPECT_EQ(
569 media_desc_options_it->transport_options.enable_ice_renomination,
570 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 } else {
572 EXPECT_TRUE(ti_video == NULL);
573 }
574 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
575 if (options.has_data()) {
576 EXPECT_TRUE(ti_data != NULL);
577 if (options.bundle_enabled) {
578 EXPECT_EQ(ti_audio->description.ice_ufrag,
579 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200580 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 } else {
582 if (has_current_desc) {
583 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
584 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
585 } else {
586 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
587 ti_data->description.ice_ufrag.size());
588 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
589 ti_data->description.ice_pwd.size());
590 }
591 }
zhihuang1c378ed2017-08-17 14:10:50 -0700592 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700593 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700594 EXPECT_EQ(
595 media_desc_options_it->transport_options.enable_ice_renomination,
596 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700597
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700599 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 }
601 }
602
Harald Alvestrand0d018412021-11-04 13:52:31 +0000603 void TestCryptoWithBundle(bool offer) {
604 f1_.set_secure(SEC_ENABLED);
605 MediaSessionOptions options;
606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
607 std::unique_ptr<SessionDescription> ref_desc;
608 std::unique_ptr<SessionDescription> desc;
609 if (offer) {
610 options.bundle_enabled = false;
611 ref_desc = f1_.CreateOffer(options, NULL);
612 options.bundle_enabled = true;
613 desc = f1_.CreateOffer(options, ref_desc.get());
614 } else {
615 options.bundle_enabled = true;
616 ref_desc = f1_.CreateOffer(options, NULL);
617 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
618 }
619 ASSERT_TRUE(desc);
620 const cricket::MediaContentDescription* audio_media_desc =
621 desc->GetContentDescriptionByName("audio");
622 ASSERT_TRUE(audio_media_desc);
623 const cricket::MediaContentDescription* video_media_desc =
624 desc->GetContentDescriptionByName("video");
625 ASSERT_TRUE(video_media_desc);
626 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
627 video_media_desc->cryptos()));
628 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
629 EXPECT_EQ(kDefaultSrtpCryptoSuite,
630 audio_media_desc->cryptos()[0].cipher_suite);
631
632 // Verify the selected crypto is one from the reference audio
633 // media content.
634 const cricket::MediaContentDescription* ref_audio_media_desc =
635 ref_desc->GetContentDescriptionByName("audio");
636 bool found = false;
637 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
638 if (ref_audio_media_desc->cryptos()[i].Matches(
639 audio_media_desc->cryptos()[0])) {
640 found = true;
641 break;
642 }
643 }
644 EXPECT_TRUE(found);
645 }
646
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 // This test that the audio and video media direction is set to
Artem Titov880fa812021-07-30 22:30:23 +0200648 // `expected_direction_in_answer` in an answer if the offer direction is set
649 // to `direction_in_offer` and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800651 RtpTransceiverDirection direction_in_offer,
652 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700653 MediaSessionOptions offer_opts;
654 AddAudioVideoSections(direction_in_offer, &offer_opts);
655
Steve Anton6fe1fba2018-12-11 10:15:23 -0800656 std::unique_ptr<SessionDescription> offer =
657 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700659 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700661 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663
zhihuang1c378ed2017-08-17 14:10:50 -0700664 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800665 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800666 std::unique_ptr<SessionDescription> answer =
667 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 const AudioContentDescription* acd_answer =
669 GetFirstAudioContentDescription(answer.get());
670 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
671 const VideoContentDescription* vcd_answer =
672 GetFirstVideoContentDescription(answer.get());
673 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
674 }
675
676 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800677 RTC_DCHECK(content);
678 RTC_CHECK(content->media_description());
679 const cricket::AudioContentDescription* audio_desc =
680 content->media_description()->as_audio();
681 RTC_CHECK(audio_desc);
682 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
683 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800685 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 }
687 return true;
688 }
689
Harald Alvestrand0d018412021-11-04 13:52:31 +0000690 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
691 MediaSessionOptions offer_opts;
692 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
693 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
694
695 MediaSessionOptions answer_opts;
696 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
697 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
698
699 f1_.set_secure(SEC_ENABLED);
700 f2_.set_secure(SEC_ENABLED);
701 std::unique_ptr<SessionDescription> offer =
702 f1_.CreateOffer(offer_opts, NULL);
703 ASSERT_TRUE(offer.get() != NULL);
704 if (gcm_offer && gcm_answer) {
705 for (cricket::ContentInfo& content : offer->contents()) {
706 auto cryptos = content.media_description()->cryptos();
707 PreferGcmCryptoParameters(&cryptos);
708 content.media_description()->set_cryptos(cryptos);
709 }
710 }
711 std::unique_ptr<SessionDescription> answer =
712 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
713 const ContentInfo* ac = answer->GetContentByName("audio");
714 const ContentInfo* vc = answer->GetContentByName("video");
715 ASSERT_TRUE(ac != NULL);
716 ASSERT_TRUE(vc != NULL);
717 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
718 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
719 const AudioContentDescription* acd = ac->media_description()->as_audio();
720 const VideoContentDescription* vcd = vc->media_description()->as_video();
721 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
722 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
723 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
724 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
725 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
726 if (gcm_offer && gcm_answer) {
727 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
728 } else {
729 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
730 }
731 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
732 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
733 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
734 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
735 if (gcm_offer && gcm_answer) {
736 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
737 } else {
738 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
739 }
740 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
741 }
742
Johannes Kronce8e8672019-02-22 13:06:44 +0100743 void TestTransportSequenceNumberNegotiation(
744 const cricket::RtpHeaderExtensions& local,
745 const cricket::RtpHeaderExtensions& offered,
746 const cricket::RtpHeaderExtensions& expectedAnswer) {
747 MediaSessionOptions opts;
748 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +0200749 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100750 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
751 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +0200752 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100753 std::unique_ptr<SessionDescription> answer =
754 f2_.CreateAnswer(offer.get(), opts, NULL);
755
756 EXPECT_EQ(
757 expectedAnswer,
758 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
759 EXPECT_EQ(
760 expectedAnswer,
761 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
762 }
763
Markus Handell755c65d2020-06-24 01:06:10 +0200764 std::vector<webrtc::RtpHeaderExtensionCapability>
765 HeaderExtensionCapabilitiesFromRtpExtensions(
766 cricket::RtpHeaderExtensions extensions) {
767 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
768 for (const auto& extension : extensions) {
769 webrtc::RtpHeaderExtensionCapability capability(
770 extension.uri, extension.id,
771 webrtc::RtpTransceiverDirection::kSendRecv);
772 capabilities.push_back(capability);
773 }
774 return capabilities;
775 }
776
777 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
778 cricket::RtpHeaderExtensions video_exts,
779 MediaSessionOptions* opts) {
780 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
781 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
782 for (auto& entry : opts->media_description_options) {
783 switch (entry.type) {
784 case MEDIA_TYPE_AUDIO:
785 entry.header_extensions = audio_caps;
786 break;
787 case MEDIA_TYPE_VIDEO:
788 entry.header_extensions = video_caps;
789 break;
790 default:
791 break;
792 }
793 }
794 }
795
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 protected:
Jonas Orelanded99dae2022-03-09 09:28:10 +0100797 webrtc::test::ScopedKeyValueConfig field_trials;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800798 UniqueRandomIdGenerator ssrc_generator1;
799 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 TransportDescriptionFactory tdf1_;
801 TransportDescriptionFactory tdf2_;
Jonas Orelanded99dae2022-03-09 09:28:10 +0100802 MediaSessionDescriptionFactory f1_;
803 MediaSessionDescriptionFactory f2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804};
805
806// Create a typical audio offer, and ensure it matches what we expect.
807TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000808 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800809 std::unique_ptr<SessionDescription> offer =
810 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 ASSERT_TRUE(offer.get() != NULL);
812 const ContentInfo* ac = offer->GetContentByName("audio");
813 const ContentInfo* vc = offer->GetContentByName("video");
814 ASSERT_TRUE(ac != NULL);
815 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800816 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800817 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700819 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700820 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
822 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000823 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
824 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825}
826
827// Create a typical video offer, and ensure it matches what we expect.
828TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
829 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800830 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000831 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800832 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 ASSERT_TRUE(offer.get() != NULL);
834 const ContentInfo* ac = offer->GetContentByName("audio");
835 const ContentInfo* vc = offer->GetContentByName("video");
836 ASSERT_TRUE(ac != NULL);
837 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800838 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
839 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800840 const AudioContentDescription* acd = ac->media_description()->as_audio();
841 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700843 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700844 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
846 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000847 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
848 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200850 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700851 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
853 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000854 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
855 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856}
857
858// Test creating an offer with bundle where the Codecs have the same dynamic
859// RTP playlod type. The test verifies that the offer don't contain the
860// duplicate RTP payload types.
861TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200862 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700863 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865
866 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800867 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800869 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 const VideoContentDescription* vcd =
871 GetFirstVideoContentDescription(offer.get());
872 const AudioContentDescription* acd =
873 GetFirstAudioContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874 ASSERT_TRUE(NULL != vcd);
875 ASSERT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
878 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879}
880
zhihuang1c378ed2017-08-17 14:10:50 -0700881// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882// after an audio only session has been negotiated.
883TEST_F(MediaSessionDescriptionFactoryTest,
884 TestCreateUpdatedVideoOfferWithBundle) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000885 f1_.set_secure(SEC_ENABLED);
886 f2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800888 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
889 RtpTransceiverDirection::kRecvOnly, kActive,
890 &opts);
891 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
892 RtpTransceiverDirection::kInactive, kStopped,
893 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800895 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
896 std::unique_ptr<SessionDescription> answer =
897 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000898
899 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800900 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800902 std::unique_ptr<SessionDescription> updated_offer(
903 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904
905 const AudioContentDescription* acd =
906 GetFirstAudioContentDescription(updated_offer.get());
907 const VideoContentDescription* vcd =
908 GetFirstVideoContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909 EXPECT_TRUE(NULL != vcd);
910 EXPECT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911
Harald Alvestrand0d018412021-11-04 13:52:31 +0000912 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
913 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
914 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
915 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916}
917
wu@webrtc.org78187522013-10-07 23:32:02 +0000918// Create an SCTP data offer with bundle without error.
919TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
920 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000921 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200922 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000923 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800924 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000925 EXPECT_TRUE(offer.get() != NULL);
926 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000927 auto dcd = GetFirstSctpDataContentDescription(offer.get());
928 ASSERT_TRUE(dcd);
929 // Since this transport is insecure, the protocol should be "SCTP".
930 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
931}
932
933// Create an SCTP data offer with bundle without error.
934TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
935 MediaSessionOptions opts;
936 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200937 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000938 f1_.set_secure(SEC_ENABLED);
939 tdf1_.set_secure(SEC_ENABLED);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
941 EXPECT_TRUE(offer.get() != NULL);
942 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
943 auto dcd = GetFirstSctpDataContentDescription(offer.get());
944 ASSERT_TRUE(dcd);
945 // The protocol should now be "UDP/DTLS/SCTP"
946 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000947}
948
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000949// Test creating an sctp data channel from an already generated offer.
950TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
951 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000952 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200953 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000954 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800955 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000956 ASSERT_TRUE(offer1.get() != NULL);
957 const ContentInfo* data = offer1->GetContentByName("data");
958 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800959 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000960
kwiberg31022942016-03-11 14:18:21 -0800961 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000962 f1_.CreateOffer(opts, offer1.get()));
963 data = offer2->GetContentByName("data");
964 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800965 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000966}
967
Steve Anton2bed3972019-01-04 17:04:30 -0800968// Test that if BUNDLE is enabled and all media sections are rejected then the
969// BUNDLE group is not present in the re-offer.
970TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
971 MediaSessionOptions opts;
972 opts.bundle_enabled = true;
973 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
974 RtpTransceiverDirection::kSendRecv, kActive,
975 &opts);
976 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
977
978 opts.media_description_options[0].stopped = true;
979 std::unique_ptr<SessionDescription> reoffer =
980 f1_.CreateOffer(opts, offer.get());
981
982 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
983}
984
985// Test that if BUNDLE is enabled and the remote re-offer does not include a
986// BUNDLE group since all media sections are rejected, then the re-answer also
987// does not include a BUNDLE group.
988TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
989 MediaSessionOptions opts;
990 opts.bundle_enabled = true;
991 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
992 RtpTransceiverDirection::kSendRecv, kActive,
993 &opts);
994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
995 std::unique_ptr<SessionDescription> answer =
996 f2_.CreateAnswer(offer.get(), opts, nullptr);
997
998 opts.media_description_options[0].stopped = true;
999 std::unique_ptr<SessionDescription> reoffer =
1000 f1_.CreateOffer(opts, offer.get());
1001 std::unique_ptr<SessionDescription> reanswer =
1002 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1003
1004 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1005}
1006
1007// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1008// was rejected then the new offerer-tagged media section is the non-rejected
1009// media section.
1010TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1011 MediaSessionOptions opts;
1012 opts.bundle_enabled = true;
1013 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1014 RtpTransceiverDirection::kSendRecv, kActive,
1015 &opts);
1016 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1017
1018 // Reject the audio m= section and add a video m= section.
1019 opts.media_description_options[0].stopped = true;
1020 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1021 RtpTransceiverDirection::kSendRecv, kActive,
1022 &opts);
1023 std::unique_ptr<SessionDescription> reoffer =
1024 f1_.CreateOffer(opts, offer.get());
1025
1026 const cricket::ContentGroup* bundle_group =
1027 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1028 ASSERT_TRUE(bundle_group);
1029 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1030 EXPECT_TRUE(bundle_group->HasContentName("video"));
1031}
1032
1033// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1034// was rejected and a new media section is added, then the re-answer BUNDLE
1035// group will contain only the non-rejected media section.
1036TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1037 MediaSessionOptions opts;
1038 opts.bundle_enabled = true;
1039 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1040 RtpTransceiverDirection::kSendRecv, kActive,
1041 &opts);
1042 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1043 std::unique_ptr<SessionDescription> answer =
1044 f2_.CreateAnswer(offer.get(), opts, nullptr);
1045
1046 // Reject the audio m= section and add a video m= section.
1047 opts.media_description_options[0].stopped = true;
1048 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1049 RtpTransceiverDirection::kSendRecv, kActive,
1050 &opts);
1051 std::unique_ptr<SessionDescription> reoffer =
1052 f1_.CreateOffer(opts, offer.get());
1053 std::unique_ptr<SessionDescription> reanswer =
1054 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1055
1056 const cricket::ContentGroup* bundle_group =
1057 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1058 ASSERT_TRUE(bundle_group);
1059 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1060 EXPECT_TRUE(bundle_group->HasContentName("video"));
1061}
1062
Henrik Boströmf8187e02021-04-26 21:04:26 +02001063TEST_F(MediaSessionDescriptionFactoryTest,
1064 CreateAnswerForOfferWithMultipleBundleGroups) {
1065 // Create an offer with 4 m= sections, initially without BUNDLE groups.
1066 MediaSessionOptions opts;
1067 opts.bundle_enabled = false;
1068 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "1",
1069 RtpTransceiverDirection::kSendRecv, kActive,
1070 &opts);
1071 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "2",
1072 RtpTransceiverDirection::kSendRecv, kActive,
1073 &opts);
1074 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "3",
1075 RtpTransceiverDirection::kSendRecv, kActive,
1076 &opts);
1077 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "4",
1078 RtpTransceiverDirection::kSendRecv, kActive,
1079 &opts);
1080 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1081 ASSERT_TRUE(offer->groups().empty());
1082
1083 // Munge the offer to have two groups. Offers like these cannot be generated
1084 // without munging, but it is valid to receive such offers from remote
1085 // endpoints.
1086 cricket::ContentGroup bundle_group1(cricket::GROUP_TYPE_BUNDLE);
1087 bundle_group1.AddContentName("1");
1088 bundle_group1.AddContentName("2");
1089 cricket::ContentGroup bundle_group2(cricket::GROUP_TYPE_BUNDLE);
1090 bundle_group2.AddContentName("3");
1091 bundle_group2.AddContentName("4");
1092 offer->AddGroup(bundle_group1);
1093 offer->AddGroup(bundle_group2);
1094
1095 // If BUNDLE is enabled, the answer to this offer should accept both BUNDLE
1096 // groups.
1097 opts.bundle_enabled = true;
1098 std::unique_ptr<SessionDescription> answer =
1099 f2_.CreateAnswer(offer.get(), opts, nullptr);
1100
1101 std::vector<const cricket::ContentGroup*> answer_groups =
1102 answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1103 ASSERT_EQ(answer_groups.size(), 2u);
1104 EXPECT_EQ(answer_groups[0]->content_names().size(), 2u);
1105 EXPECT_TRUE(answer_groups[0]->HasContentName("1"));
1106 EXPECT_TRUE(answer_groups[0]->HasContentName("2"));
1107 EXPECT_EQ(answer_groups[1]->content_names().size(), 2u);
1108 EXPECT_TRUE(answer_groups[1]->HasContentName("3"));
1109 EXPECT_TRUE(answer_groups[1]->HasContentName("4"));
1110
1111 // If BUNDLE is disabled, the answer to this offer should reject both BUNDLE
1112 // groups.
1113 opts.bundle_enabled = false;
1114 answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1115
1116 answer_groups = answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1117 // Rejected groups are still listed, but they are empty.
1118 ASSERT_EQ(answer_groups.size(), 2u);
1119 EXPECT_TRUE(answer_groups[0]->content_names().empty());
1120 EXPECT_TRUE(answer_groups[1]->content_names().empty());
1121}
1122
Steve Anton2bed3972019-01-04 17:04:30 -08001123// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1124// and there is still a non-rejected media section that was in the initial
1125// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1126// media section.
1127TEST_F(MediaSessionDescriptionFactoryTest,
1128 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1129 MediaSessionOptions opts;
1130 opts.bundle_enabled = true;
1131 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1132 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1133 std::unique_ptr<SessionDescription> answer =
1134 f2_.CreateAnswer(offer.get(), opts, nullptr);
1135
1136 // Reject the audio m= section.
1137 opts.media_description_options[0].stopped = true;
1138 std::unique_ptr<SessionDescription> reoffer =
1139 f1_.CreateOffer(opts, offer.get());
1140
1141 const TransportDescription* offer_tagged =
1142 offer->GetTransportDescriptionByName("audio");
1143 ASSERT_TRUE(offer_tagged);
1144 const TransportDescription* reoffer_tagged =
1145 reoffer->GetTransportDescriptionByName("video");
1146 ASSERT_TRUE(reoffer_tagged);
1147 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1148 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1149}
1150
1151// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1152// and there is still a non-rejected media section that was in the initial
1153// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1154// media section.
1155TEST_F(MediaSessionDescriptionFactoryTest,
1156 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1157 MediaSessionOptions opts;
1158 opts.bundle_enabled = true;
1159 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1160 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1161 std::unique_ptr<SessionDescription> answer =
1162 f2_.CreateAnswer(offer.get(), opts, nullptr);
1163
1164 // Reject the audio m= section.
1165 opts.media_description_options[0].stopped = true;
1166 std::unique_ptr<SessionDescription> reoffer =
1167 f1_.CreateOffer(opts, offer.get());
1168 std::unique_ptr<SessionDescription> reanswer =
1169 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1170
1171 const TransportDescription* answer_tagged =
1172 answer->GetTransportDescriptionByName("audio");
1173 ASSERT_TRUE(answer_tagged);
1174 const TransportDescription* reanswer_tagged =
1175 reanswer->GetTransportDescriptionByName("video");
1176 ASSERT_TRUE(reanswer_tagged);
1177 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1178 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1179}
1180
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181// Create an audio, video offer without legacy StreamParams.
1182TEST_F(MediaSessionDescriptionFactoryTest,
1183 TestCreateOfferWithoutLegacyStreams) {
1184 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001185 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001186 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001187 ASSERT_TRUE(offer.get() != NULL);
1188 const ContentInfo* ac = offer->GetContentByName("audio");
1189 const ContentInfo* vc = offer->GetContentByName("video");
1190 ASSERT_TRUE(ac != NULL);
1191 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001192 const AudioContentDescription* acd = ac->media_description()->as_audio();
1193 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194
Yves Gerey665174f2018-06-19 15:03:05 +02001195 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1196 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197}
1198
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001199// Creates an audio+video sendonly offer.
1200TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001201 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001202 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001203 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1204 {kMediaStream1}, 1, &opts);
1205 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1206 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001207
Steve Anton6fe1fba2018-12-11 10:15:23 -08001208 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001209 ASSERT_TRUE(offer.get() != NULL);
1210 EXPECT_EQ(2u, offer->contents().size());
1211 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1212 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1213
Steve Anton4e70a722017-11-28 14:57:10 -08001214 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1215 GetMediaDirection(&offer->contents()[0]));
1216 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1217 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001218}
1219
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001220// Verifies that the order of the media contents in the current
1221// SessionDescription is preserved in the new SessionDescription.
1222TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1223 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001224 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001225
kwiberg31022942016-03-11 14:18:21 -08001226 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001227 ASSERT_TRUE(offer1.get() != NULL);
1228 EXPECT_EQ(1u, offer1->contents().size());
1229 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1230
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001231 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1232 RtpTransceiverDirection::kRecvOnly, kActive,
1233 &opts);
kwiberg31022942016-03-11 14:18:21 -08001234 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001235 f1_.CreateOffer(opts, offer1.get()));
1236 ASSERT_TRUE(offer2.get() != NULL);
1237 EXPECT_EQ(2u, offer2->contents().size());
1238 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1239 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1240
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001241 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1242 RtpTransceiverDirection::kRecvOnly, kActive,
1243 &opts);
kwiberg31022942016-03-11 14:18:21 -08001244 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001245 f1_.CreateOffer(opts, offer2.get()));
1246 ASSERT_TRUE(offer3.get() != NULL);
1247 EXPECT_EQ(3u, offer3->contents().size());
1248 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1249 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1250 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001251}
1252
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253// Create a typical audio answer, and ensure it matches what we expect.
1254TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001255 f1_.set_secure(SEC_ENABLED);
1256 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001257 std::unique_ptr<SessionDescription> offer =
1258 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001260 std::unique_ptr<SessionDescription> answer =
1261 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 const ContentInfo* ac = answer->GetContentByName("audio");
1263 const ContentInfo* vc = answer->GetContentByName("video");
1264 ASSERT_TRUE(ac != NULL);
1265 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001266 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001267 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001269 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001270 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1272 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001273 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1274 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
1275}
1276
1277// Create a typical audio answer with GCM ciphers enabled, and ensure it
1278// matches what we expect.
1279TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1280 f1_.set_secure(SEC_ENABLED);
1281 f2_.set_secure(SEC_ENABLED);
1282 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1283 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
1284 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1285 ASSERT_TRUE(offer.get() != NULL);
1286 for (cricket::ContentInfo& content : offer->contents()) {
1287 auto cryptos = content.media_description()->cryptos();
1288 PreferGcmCryptoParameters(&cryptos);
1289 content.media_description()->set_cryptos(cryptos);
1290 }
1291 std::unique_ptr<SessionDescription> answer =
1292 f2_.CreateAnswer(offer.get(), opts, NULL);
1293 const ContentInfo* ac = answer->GetContentByName("audio");
1294 const ContentInfo* vc = answer->GetContentByName("video");
1295 ASSERT_TRUE(ac != NULL);
1296 ASSERT_TRUE(vc == NULL);
1297 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1298 const AudioContentDescription* acd = ac->media_description()->as_audio();
1299 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1300 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
1301 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
1302 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1303 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1304 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
1305 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001306}
1307
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308// Create a typical video answer, and ensure it matches what we expect.
1309TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1310 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001311 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00001312 f1_.set_secure(SEC_ENABLED);
1313 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001314 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001315 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001316 std::unique_ptr<SessionDescription> answer =
1317 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 const ContentInfo* ac = answer->GetContentByName("audio");
1319 const ContentInfo* vc = answer->GetContentByName("video");
1320 ASSERT_TRUE(ac != NULL);
1321 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001322 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1323 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001324 const AudioContentDescription* acd = ac->media_description()->as_audio();
1325 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001326 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001327 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001329 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001330 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001331 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001333 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001334 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1335 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001336 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1337 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
1338}
1339
1340// Create a typical video answer with GCM ciphers enabled, and ensure it
1341// matches what we expect.
1342TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1343 TestVideoGcmCipher(true, true);
1344}
1345
1346// Create a typical video answer with GCM ciphers enabled for the offer only,
1347// and ensure it matches what we expect.
1348TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1349 TestVideoGcmCipher(true, false);
1350}
1351
1352// Create a typical video answer with GCM ciphers enabled for the answer only,
1353// and ensure it matches what we expect.
1354TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1355 TestVideoGcmCipher(false, true);
jbauchcb560652016-08-04 05:20:32 -07001356}
1357
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001358// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1359// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001360TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1361 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001362 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001363 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001364 ASSERT_TRUE(offer.get() != NULL);
1365 ContentInfo* dc_offer = offer->GetContentByName("data");
1366 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001367 SctpDataContentDescription* dcd_offer =
1368 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001369 EXPECT_TRUE(dcd_offer->use_sctpmap());
1370
Steve Anton6fe1fba2018-12-11 10:15:23 -08001371 std::unique_ptr<SessionDescription> answer =
1372 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001373 const ContentInfo* dc_answer = answer->GetContentByName("data");
1374 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001375 const SctpDataContentDescription* dcd_answer =
1376 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001377 EXPECT_TRUE(dcd_answer->use_sctpmap());
1378}
1379
1380// The answer's use_sctpmap flag should match the offer's.
1381TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1382 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001383 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001384 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001385 ASSERT_TRUE(offer.get() != NULL);
1386 ContentInfo* dc_offer = offer->GetContentByName("data");
1387 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001388 SctpDataContentDescription* dcd_offer =
1389 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001390 dcd_offer->set_use_sctpmap(false);
1391
Steve Anton6fe1fba2018-12-11 10:15:23 -08001392 std::unique_ptr<SessionDescription> answer =
1393 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001394 const ContentInfo* dc_answer = answer->GetContentByName("data");
1395 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001396 const SctpDataContentDescription* dcd_answer =
1397 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001398 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001399}
1400
deadbeef8b7e9ad2017-05-25 09:38:55 -07001401// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1402// and "TCP/DTLS/SCTP" offers.
1403TEST_F(MediaSessionDescriptionFactoryTest,
1404 TestCreateDataAnswerToDifferentOfferedProtos) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001405 // Need to enable DTLS offer/answer generation (disabled by default in this
1406 // test).
1407 f1_.set_secure(SEC_ENABLED);
1408 f2_.set_secure(SEC_ENABLED);
1409 tdf1_.set_secure(SEC_ENABLED);
1410 tdf2_.set_secure(SEC_ENABLED);
1411
deadbeef8b7e9ad2017-05-25 09:38:55 -07001412 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001413 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001414 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001415 ASSERT_TRUE(offer.get() != nullptr);
1416 ContentInfo* dc_offer = offer->GetContentByName("data");
1417 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001418 SctpDataContentDescription* dcd_offer =
1419 dc_offer->media_description()->as_sctp();
1420 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001421
1422 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1423 "TCP/DTLS/SCTP"};
1424 for (const std::string& proto : protos) {
1425 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001426 std::unique_ptr<SessionDescription> answer =
1427 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001428 const ContentInfo* dc_answer = answer->GetContentByName("data");
1429 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001430 const SctpDataContentDescription* dcd_answer =
1431 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001432 EXPECT_FALSE(dc_answer->rejected);
1433 EXPECT_EQ(proto, dcd_answer->protocol());
1434 }
1435}
1436
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001437TEST_F(MediaSessionDescriptionFactoryTest,
1438 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001439 // Need to enable DTLS offer/answer generation (disabled by default in this
1440 // test).
1441 f1_.set_secure(SEC_ENABLED);
1442 f2_.set_secure(SEC_ENABLED);
1443 tdf1_.set_secure(SEC_ENABLED);
1444 tdf2_.set_secure(SEC_ENABLED);
1445
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001446 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001447 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001448 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1449 ASSERT_TRUE(offer.get() != nullptr);
1450 ContentInfo* dc_offer = offer->GetContentByName("data");
1451 ASSERT_TRUE(dc_offer != nullptr);
1452 SctpDataContentDescription* dcd_offer =
1453 dc_offer->media_description()->as_sctp();
1454 ASSERT_TRUE(dcd_offer);
1455 dcd_offer->set_max_message_size(1234);
1456 std::unique_ptr<SessionDescription> answer =
1457 f2_.CreateAnswer(offer.get(), opts, nullptr);
1458 const ContentInfo* dc_answer = answer->GetContentByName("data");
1459 ASSERT_TRUE(dc_answer != nullptr);
1460 const SctpDataContentDescription* dcd_answer =
1461 dc_answer->media_description()->as_sctp();
1462 EXPECT_FALSE(dc_answer->rejected);
1463 EXPECT_EQ(1234, dcd_answer->max_message_size());
1464}
1465
1466TEST_F(MediaSessionDescriptionFactoryTest,
1467 TestCreateDataAnswerToOfferWithZeroMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001468 // Need to enable DTLS offer/answer generation (disabled by default in this
1469 // test).
1470 f1_.set_secure(SEC_ENABLED);
1471 f2_.set_secure(SEC_ENABLED);
1472 tdf1_.set_secure(SEC_ENABLED);
1473 tdf2_.set_secure(SEC_ENABLED);
1474
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001475 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001476 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001477 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1478 ASSERT_TRUE(offer.get() != nullptr);
1479 ContentInfo* dc_offer = offer->GetContentByName("data");
1480 ASSERT_TRUE(dc_offer != nullptr);
1481 SctpDataContentDescription* dcd_offer =
1482 dc_offer->media_description()->as_sctp();
1483 ASSERT_TRUE(dcd_offer);
1484 dcd_offer->set_max_message_size(0);
1485 std::unique_ptr<SessionDescription> answer =
1486 f2_.CreateAnswer(offer.get(), opts, nullptr);
1487 const ContentInfo* dc_answer = answer->GetContentByName("data");
1488 ASSERT_TRUE(dc_answer != nullptr);
1489 const SctpDataContentDescription* dcd_answer =
1490 dc_answer->media_description()->as_sctp();
1491 EXPECT_FALSE(dc_answer->rejected);
1492 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1493}
1494
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001495// Verifies that the order of the media contents in the offer is preserved in
1496// the answer.
1497TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1498 MediaSessionOptions opts;
1499
1500 // Creates a data only offer.
Florent Castelli516e2842021-04-19 15:29:50 +02001501 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001502 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001503 ASSERT_TRUE(offer1.get() != NULL);
1504
1505 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001506 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1507 RtpTransceiverDirection::kRecvOnly, kActive,
1508 &opts);
kwiberg31022942016-03-11 14:18:21 -08001509 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001510 f1_.CreateOffer(opts, offer1.get()));
1511 ASSERT_TRUE(offer2.get() != NULL);
1512
1513 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001514 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1515 RtpTransceiverDirection::kRecvOnly, kActive,
1516 &opts);
kwiberg31022942016-03-11 14:18:21 -08001517 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001518 f1_.CreateOffer(opts, offer2.get()));
1519 ASSERT_TRUE(offer3.get() != NULL);
1520
Steve Anton6fe1fba2018-12-11 10:15:23 -08001521 std::unique_ptr<SessionDescription> answer =
1522 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001523 ASSERT_TRUE(answer.get() != NULL);
1524 EXPECT_EQ(3u, answer->contents().size());
1525 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1526 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1527 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1528}
1529
ossu075af922016-06-14 03:29:38 -07001530// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1531// answerer settings.
1532
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001533// This test that the media direction is set to send/receive in an answer if
1534// the offer is send receive.
1535TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001536 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1537 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538}
1539
1540// This test that the media direction is set to receive only in an answer if
1541// the offer is send only.
1542TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001543 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1544 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001545}
1546
1547// This test that the media direction is set to send only in an answer if
1548// the offer is recv only.
1549TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001550 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1551 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001552}
1553
1554// This test that the media direction is set to inactive in an answer if
1555// the offer is inactive.
1556TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001557 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1558 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001559}
1560
Harald Alvestrand0d018412021-11-04 13:52:31 +00001561// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001562TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001563 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Harald Alvestrand0d018412021-11-04 13:52:31 +00001564 f1_.set_secure(SEC_DISABLED);
1565 f2_.set_secure(SEC_DISABLED);
1566 tdf1_.set_secure(SEC_DISABLED);
1567 tdf2_.set_secure(SEC_DISABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568
Steve Anton6fe1fba2018-12-11 10:15:23 -08001569 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001570 const AudioContentDescription* offer_acd =
1571 GetFirstAudioContentDescription(offer.get());
1572 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001573 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574
Steve Anton6fe1fba2018-12-11 10:15:23 -08001575 std::unique_ptr<SessionDescription> answer =
1576 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001577
1578 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1579 ASSERT_TRUE(ac_answer != NULL);
1580 EXPECT_FALSE(ac_answer->rejected);
1581
1582 const AudioContentDescription* answer_acd =
1583 GetFirstAudioContentDescription(answer.get());
1584 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001585 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001586}
1587
1588// Create a video offer and answer and ensure the RTP header extensions
1589// matches what we expect.
1590TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1591 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001592 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +02001593 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1594 MAKE_VECTOR(kVideoRtpExtension1), &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001595
Steve Anton6fe1fba2018-12-11 10:15:23 -08001596 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001597 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001598 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1599 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001600 std::unique_ptr<SessionDescription> answer =
1601 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001602
Yves Gerey665174f2018-06-19 15:03:05 +02001603 EXPECT_EQ(
1604 MAKE_VECTOR(kAudioRtpExtension1),
1605 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1606 EXPECT_EQ(
1607 MAKE_VECTOR(kVideoRtpExtension1),
1608 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1609 EXPECT_EQ(
1610 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1611 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1612 EXPECT_EQ(
1613 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1614 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001615}
1616
Johannes Kronce8e8672019-02-22 13:06:44 +01001617// Create a audio/video offer and answer and ensure that the
1618// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1619// supported and should take precedence even though not listed among locally
1620// supported extensions.
1621TEST_F(MediaSessionDescriptionFactoryTest,
1622 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1623 TestTransportSequenceNumberNegotiation(
1624 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1625 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1626 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1627}
1628TEST_F(MediaSessionDescriptionFactoryTest,
1629 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1630 TestTransportSequenceNumberNegotiation(
1631 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1632 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1633 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1634}
1635TEST_F(MediaSessionDescriptionFactoryTest,
1636 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1637 TestTransportSequenceNumberNegotiation(
1638 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1639 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1640 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1641}
1642
jbauch5869f502017-06-29 12:31:36 -07001643TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001644 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1645 MediaSessionOptions opts;
1646 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1647
Markus Handell755c65d2020-06-24 01:06:10 +02001648 SetAudioVideoRtpHeaderExtensions(
1649 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1650 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001651 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001652 SetAudioVideoRtpHeaderExtensions(
1653 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1654 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001655 std::unique_ptr<SessionDescription> answer =
1656 f2_.CreateAnswer(offer.get(), opts, nullptr);
1657 EXPECT_THAT(
1658 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001659 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001660 EXPECT_THAT(
1661 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001662 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001663}
1664
1665TEST_F(MediaSessionDescriptionFactoryTest,
1666 TestNegotiateFrameDescriptorWhenExposedLocally) {
1667 MediaSessionOptions opts;
1668 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1669
Markus Handell755c65d2020-06-24 01:06:10 +02001670 SetAudioVideoRtpHeaderExtensions(
1671 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1672 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001673 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1674 std::unique_ptr<SessionDescription> answer =
1675 f2_.CreateAnswer(offer.get(), opts, nullptr);
1676 EXPECT_THAT(
1677 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001678 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001679 EXPECT_THAT(
1680 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001681 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001682}
1683
1684TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001685 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1686 MediaSessionOptions opts;
1687 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1688
1689 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell755c65d2020-06-24 01:06:10 +02001690 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +00001691 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001692 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1693 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001694 std::unique_ptr<SessionDescription> answer =
1695 f2_.CreateAnswer(offer.get(), opts, nullptr);
1696 EXPECT_THAT(
1697 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1698 ElementsAre(offer_dd));
1699}
1700
1701TEST_F(MediaSessionDescriptionFactoryTest,
1702 NegotiateDependencyDescriptorWhenExposedLocally) {
1703 MediaSessionOptions opts;
1704 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1705
1706 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1707 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell755c65d2020-06-24 01:06:10 +02001708 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001709 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001710 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001711 std::unique_ptr<SessionDescription> answer =
1712 f2_.CreateAnswer(offer.get(), opts, nullptr);
1713 EXPECT_THAT(
1714 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1715 ElementsAre(offer_dd));
1716}
1717
1718TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001719 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1720 MediaSessionOptions opts;
1721 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1722
1723 const cricket::RtpHeaderExtensions offered_extensions = {
1724 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1725 const cricket::RtpHeaderExtensions local_extensions = {
1726 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001727 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1728 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001729 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001730 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001731 std::unique_ptr<SessionDescription> answer =
1732 f2_.CreateAnswer(offer.get(), opts, nullptr);
1733 EXPECT_THAT(
1734 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1735 ElementsAreArray(offered_extensions));
1736 EXPECT_THAT(
1737 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1738 ElementsAreArray(offered_extensions));
1739}
1740
1741TEST_F(MediaSessionDescriptionFactoryTest,
1742 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1743 MediaSessionOptions opts;
1744 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1745
1746 const cricket::RtpHeaderExtensions offered_extensions = {
1747 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1748 const cricket::RtpHeaderExtensions local_extensions = {
1749 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001750 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1751 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001752 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001753 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001754 std::unique_ptr<SessionDescription> answer =
1755 f2_.CreateAnswer(offer.get(), opts, nullptr);
1756 EXPECT_THAT(
1757 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1758 ElementsAreArray(offered_extensions));
1759 EXPECT_THAT(
1760 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1761 ElementsAreArray(offered_extensions));
1762}
1763
1764TEST_F(MediaSessionDescriptionFactoryTest,
1765 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1766 MediaSessionOptions opts;
1767 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1768
1769 const cricket::RtpHeaderExtensions offered_extensions = {
1770 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1771 const cricket::RtpHeaderExtensions local_extensions = {
1772 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001773 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1774 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001776 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001777 std::unique_ptr<SessionDescription> answer =
1778 f2_.CreateAnswer(offer.get(), opts, nullptr);
1779 EXPECT_THAT(
1780 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1781 IsEmpty());
1782 EXPECT_THAT(
1783 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1784 IsEmpty());
1785}
1786
1787TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handell755c65d2020-06-24 01:06:10 +02001788 OffersUnstoppedExtensionsWithAudioVideoExtensionStopped) {
1789 MediaSessionOptions opts;
1790 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1791 RtpTransceiverDirection::kSendRecv, kActive,
1792 &opts);
1793 opts.media_description_options.back().header_extensions = {
1794 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1795 RtpTransceiverDirection::kStopped),
1796 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1797 RtpTransceiverDirection::kSendOnly)};
1798 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1799 RtpTransceiverDirection::kSendRecv, kActive,
1800 &opts);
1801 opts.media_description_options.back().header_extensions = {
1802 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1803 RtpTransceiverDirection::kStopped),
1804 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1805 RtpTransceiverDirection::kSendOnly)};
1806 auto offer = f1_.CreateOffer(opts, nullptr);
1807 EXPECT_THAT(
1808 offer->contents(),
1809 ElementsAre(
1810 Property(&ContentInfo::media_description,
1811 Pointee(Property(
1812 &MediaContentDescription::rtp_header_extensions,
1813 ElementsAre(Field(&RtpExtension::uri, "uri2"))))),
1814 Property(&ContentInfo::media_description,
1815 Pointee(Property(
1816 &MediaContentDescription::rtp_header_extensions,
1817 ElementsAre(Field(&RtpExtension::uri, "uri3")))))));
1818}
1819
1820TEST_F(MediaSessionDescriptionFactoryTest,
1821 OffersUnstoppedExtensionsWithAudioExtensionStopped) {
1822 MediaSessionOptions opts;
1823 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1824 RtpTransceiverDirection::kSendRecv, kActive,
1825 &opts);
1826 opts.media_description_options.back().header_extensions = {
1827 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1828 RtpTransceiverDirection::kSendOnly),
1829 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1830 RtpTransceiverDirection::kStopped)};
1831 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1832 RtpTransceiverDirection::kSendRecv, kActive,
1833 &opts);
1834 opts.media_description_options.back().header_extensions = {
1835 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1836 RtpTransceiverDirection::kSendRecv),
1837 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1838 RtpTransceiverDirection::kSendOnly)};
1839 auto offer = f1_.CreateOffer(opts, nullptr);
1840 EXPECT_THAT(
1841 offer->contents(),
1842 ElementsAre(
1843 Property(&ContentInfo::media_description,
1844 Pointee(Property(
1845 &MediaContentDescription::rtp_header_extensions,
1846 ElementsAre(Field(&RtpExtension::uri, "uri1"))))),
1847 Property(
1848 &ContentInfo::media_description,
1849 Pointee(Property(
1850 &MediaContentDescription::rtp_header_extensions,
1851 UnorderedElementsAre(Field(&RtpExtension::uri, "uri3"),
1852 Field(&RtpExtension::uri, "uri42")))))));
1853}
1854
1855TEST_F(MediaSessionDescriptionFactoryTest,
1856 OffersUnstoppedExtensionsWithVideoExtensionStopped) {
1857 MediaSessionOptions opts;
1858 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1859 RtpTransceiverDirection::kSendRecv, kActive,
1860 &opts);
1861 opts.media_description_options.back().header_extensions = {
1862 webrtc::RtpHeaderExtensionCapability("uri1", 5,
1863 RtpTransceiverDirection::kSendOnly),
1864 webrtc::RtpHeaderExtensionCapability("uri2", 7,
1865 RtpTransceiverDirection::kSendRecv)};
1866 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1867 RtpTransceiverDirection::kSendRecv, kActive,
1868 &opts);
1869 opts.media_description_options.back().header_extensions = {
1870 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1871 RtpTransceiverDirection::kSendRecv),
1872 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1873 RtpTransceiverDirection::kStopped)};
1874 auto offer = f1_.CreateOffer(opts, nullptr);
1875 EXPECT_THAT(
1876 offer->contents(),
1877 ElementsAre(
1878 Property(
1879 &ContentInfo::media_description,
1880 Pointee(Property(
1881 &MediaContentDescription::rtp_header_extensions,
1882 UnorderedElementsAre(Field(&RtpExtension::uri, "uri1"),
1883 Field(&RtpExtension::uri, "uri2"))))),
1884 Property(&ContentInfo::media_description,
1885 Pointee(Property(
1886 &MediaContentDescription::rtp_header_extensions,
1887 ElementsAre(Field(&RtpExtension::uri, "uri42")))))));
1888}
1889
1890TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1891 MediaSessionOptions opts;
1892 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1893 RtpTransceiverDirection::kSendRecv, kActive,
1894 &opts);
1895 opts.media_description_options.back().header_extensions = {
1896 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1897 RtpTransceiverDirection::kStopped),
1898 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1899 RtpTransceiverDirection::kSendOnly),
1900 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1901 RtpTransceiverDirection::kRecvOnly),
1902 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1903 RtpTransceiverDirection::kSendRecv)};
1904 auto offer = f1_.CreateOffer(opts, nullptr);
1905 opts.media_description_options.back().header_extensions = {
1906 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1907 RtpTransceiverDirection::kSendOnly),
1908 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1909 RtpTransceiverDirection::kRecvOnly),
1910 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1911 RtpTransceiverDirection::kStopped),
1912 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1913 RtpTransceiverDirection::kSendRecv)};
1914 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1915 EXPECT_THAT(
1916 answer->contents(),
1917 ElementsAre(Property(
1918 &ContentInfo::media_description,
1919 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1920 ElementsAre(Field(&RtpExtension::uri, "uri2"),
1921 Field(&RtpExtension::uri, "uri4")))))));
1922}
1923
1924TEST_F(MediaSessionDescriptionFactoryTest,
1925 AppendsUnstoppedExtensionsToCurrentDescription) {
1926 MediaSessionOptions opts;
1927 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1928 RtpTransceiverDirection::kSendRecv, kActive,
1929 &opts);
1930 opts.media_description_options.back().header_extensions = {
1931 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1932 RtpTransceiverDirection::kSendRecv)};
1933 auto offer = f1_.CreateOffer(opts, nullptr);
1934 opts.media_description_options.back().header_extensions = {
1935 webrtc::RtpHeaderExtensionCapability("uri1", 2,
1936 RtpTransceiverDirection::kSendRecv),
1937 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1938 RtpTransceiverDirection::kRecvOnly),
1939 webrtc::RtpHeaderExtensionCapability("uri3", 5,
1940 RtpTransceiverDirection::kStopped),
1941 webrtc::RtpHeaderExtensionCapability("uri4", 6,
1942 RtpTransceiverDirection::kSendRecv)};
1943 auto offer2 = f1_.CreateOffer(opts, offer.get());
1944 EXPECT_THAT(
1945 offer2->contents(),
1946 ElementsAre(Property(
1947 &ContentInfo::media_description,
1948 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1949 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1950 Field(&RtpExtension::uri, "uri2"),
1951 Field(&RtpExtension::uri, "uri4")))))));
1952}
1953
1954TEST_F(MediaSessionDescriptionFactoryTest,
1955 AppendsStoppedExtensionIfKnownAndPresentInTheOffer) {
1956 MediaSessionOptions opts;
1957 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1958 RtpTransceiverDirection::kSendRecv, kActive,
1959 &opts);
1960 opts.media_description_options.back().header_extensions = {
1961 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1962 RtpTransceiverDirection::kSendRecv),
1963 webrtc::RtpHeaderExtensionCapability("uri2", 1,
1964 RtpTransceiverDirection::kSendRecv)};
1965 auto offer = f1_.CreateOffer(opts, nullptr);
1966
1967 // Now add "uri2" as stopped to the options verify that the offer contains
1968 // uri2 since it's already present since before.
1969 opts.media_description_options.back().header_extensions = {
1970 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1971 RtpTransceiverDirection::kSendRecv),
1972 webrtc::RtpHeaderExtensionCapability("uri2", 2,
1973 RtpTransceiverDirection::kStopped)};
1974 auto offer2 = f1_.CreateOffer(opts, offer.get());
1975 EXPECT_THAT(
1976 offer2->contents(),
1977 ElementsAre(Property(
1978 &ContentInfo::media_description,
1979 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1980 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1981 Field(&RtpExtension::uri, "uri2")))))));
1982}
1983
1984TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001985 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001986 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001987 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001988
1989 f1_.set_enable_encrypted_rtp_header_extensions(true);
1990 f2_.set_enable_encrypted_rtp_header_extensions(true);
1991
Markus Handell755c65d2020-06-24 01:06:10 +02001992 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1993 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001995 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001996 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1997 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001998 std::unique_ptr<SessionDescription> answer =
1999 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002000
Yves Gerey665174f2018-06-19 15:03:05 +02002001 EXPECT_EQ(
2002 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2003 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2004 EXPECT_EQ(
2005 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2006 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2007 EXPECT_EQ(
2008 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
2009 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2010 EXPECT_EQ(
2011 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
2012 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002013}
2014
2015TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002016 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07002017 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002018 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002019
2020 f1_.set_enable_encrypted_rtp_header_extensions(true);
2021
Markus Handell755c65d2020-06-24 01:06:10 +02002022 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2023 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002024 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002025 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002026 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2027 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002028 std::unique_ptr<SessionDescription> answer =
2029 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002030
Yves Gerey665174f2018-06-19 15:03:05 +02002031 EXPECT_EQ(
2032 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2033 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2034 EXPECT_EQ(
2035 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2036 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2037 EXPECT_EQ(
2038 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2039 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2040 EXPECT_EQ(
2041 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2042 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002043}
2044
2045TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002046 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07002047 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002048 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002049
2050 f2_.set_enable_encrypted_rtp_header_extensions(true);
2051
Markus Handell755c65d2020-06-24 01:06:10 +02002052 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2053 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002054 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002055 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002056 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2057 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002058 std::unique_ptr<SessionDescription> answer =
2059 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002060
Yves Gerey665174f2018-06-19 15:03:05 +02002061 EXPECT_EQ(
2062 MAKE_VECTOR(kAudioRtpExtension1),
2063 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2064 EXPECT_EQ(
2065 MAKE_VECTOR(kVideoRtpExtension1),
2066 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2067 EXPECT_EQ(
2068 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2069 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2070 EXPECT_EQ(
2071 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2072 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002073}
2074
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002075// Create an audio, video, data answer without legacy StreamParams.
2076TEST_F(MediaSessionDescriptionFactoryTest,
2077 TestCreateAnswerWithoutLegacyStreams) {
2078 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002079 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002080 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002082 std::unique_ptr<SessionDescription> answer =
2083 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002084 const ContentInfo* ac = answer->GetContentByName("audio");
2085 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002086 ASSERT_TRUE(ac != NULL);
2087 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002088 const AudioContentDescription* acd = ac->media_description()->as_audio();
2089 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002090
2091 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2092 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002093}
2094
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002095// Create a typical video answer, and ensure it matches what we expect.
2096TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2097 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002098 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002099
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002100 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002101 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002102
kwiberg31022942016-03-11 14:18:21 -08002103 std::unique_ptr<SessionDescription> offer;
2104 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002105
2106 offer_opts.rtcp_mux_enabled = true;
2107 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002108 offer = f1_.CreateOffer(offer_opts, NULL);
2109 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002110 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2111 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002112 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2113 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002114 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2115 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002116 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2117 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002118
2119 offer_opts.rtcp_mux_enabled = true;
2120 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002121 offer = f1_.CreateOffer(offer_opts, NULL);
2122 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002123 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2124 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002125 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2126 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002127 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2128 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002129 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2130 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131
2132 offer_opts.rtcp_mux_enabled = false;
2133 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002134 offer = f1_.CreateOffer(offer_opts, NULL);
2135 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002136 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2137 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002138 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2139 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002140 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2141 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002142 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2143 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002144
2145 offer_opts.rtcp_mux_enabled = false;
2146 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002147 offer = f1_.CreateOffer(offer_opts, NULL);
2148 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002149 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2150 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2152 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002153 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2154 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2156 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002157}
2158
2159// Create an audio-only answer to a video offer.
2160TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2161 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002162 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2163 RtpTransceiverDirection::kRecvOnly, kActive,
2164 &opts);
2165 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2166 RtpTransceiverDirection::kRecvOnly, kActive,
2167 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002168 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002169 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002170
2171 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002172 std::unique_ptr<SessionDescription> answer =
2173 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174 const ContentInfo* ac = answer->GetContentByName("audio");
2175 const ContentInfo* vc = answer->GetContentByName("video");
2176 ASSERT_TRUE(ac != NULL);
2177 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002178 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179 EXPECT_TRUE(vc->rejected);
2180}
2181
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002182// Create an answer that rejects the contents which are rejected in the offer.
2183TEST_F(MediaSessionDescriptionFactoryTest,
2184 CreateAnswerToOfferWithRejectedMedia) {
2185 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002186 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002187 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 ASSERT_TRUE(offer.get() != NULL);
2189 ContentInfo* ac = offer->GetContentByName("audio");
2190 ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002191 ASSERT_TRUE(ac != NULL);
2192 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002193 ac->rejected = true;
2194 vc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002195 std::unique_ptr<SessionDescription> answer =
2196 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197 ac = answer->GetContentByName("audio");
2198 vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002199 ASSERT_TRUE(ac != NULL);
2200 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002201 EXPECT_TRUE(ac->rejected);
2202 EXPECT_TRUE(vc->rejected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002203}
2204
Johannes Kron0854eb62018-10-10 22:33:20 +02002205TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002206 OfferAndAnswerDoesNotHaveMixedByteSessionAttribute) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002207 MediaSessionOptions opts;
Emil Lundmark801c9992021-01-19 13:06:32 +01002208 std::unique_ptr<SessionDescription> offer =
2209 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002210 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002211
Emil Lundmark801c9992021-01-19 13:06:32 +01002212 std::unique_ptr<SessionDescription> answer(
2213 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2214
2215 EXPECT_FALSE(answer->extmap_allow_mixed());
2216}
2217
2218TEST_F(MediaSessionDescriptionFactoryTest,
2219 OfferAndAnswerHaveMixedByteSessionAttribute) {
2220 MediaSessionOptions opts;
2221 std::unique_ptr<SessionDescription> offer =
2222 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002223 offer->set_extmap_allow_mixed(true);
Emil Lundmark801c9992021-01-19 13:06:32 +01002224
Johannes Kron0854eb62018-10-10 22:33:20 +02002225 std::unique_ptr<SessionDescription> answer_support(
Emil Lundmark801c9992021-01-19 13:06:32 +01002226 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2227
Johannes Kron9581bc42018-10-23 10:17:39 +02002228 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002229}
2230
2231TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002232 OfferAndAnswerDoesNotHaveMixedByteMediaAttributes) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002233 MediaSessionOptions opts;
2234 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Emil Lundmark801c9992021-01-19 13:06:32 +01002235 std::unique_ptr<SessionDescription> offer =
2236 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2237 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002238 MediaContentDescription* audio_offer =
2239 offer->GetContentDescriptionByName("audio");
Emil Lundmark801c9992021-01-19 13:06:32 +01002240 MediaContentDescription* video_offer =
2241 offer->GetContentDescriptionByName("video");
2242 ASSERT_EQ(MediaContentDescription::kNo,
2243 audio_offer->extmap_allow_mixed_enum());
2244 ASSERT_EQ(MediaContentDescription::kNo,
2245 video_offer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002246
Emil Lundmark801c9992021-01-19 13:06:32 +01002247 std::unique_ptr<SessionDescription> answer(
2248 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
Johannes Kron0854eb62018-10-10 22:33:20 +02002249
Johannes Kron0854eb62018-10-10 22:33:20 +02002250 MediaContentDescription* audio_answer =
Emil Lundmark801c9992021-01-19 13:06:32 +01002251 answer->GetContentDescriptionByName("audio");
2252 MediaContentDescription* video_answer =
2253 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002254 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002255 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002256 EXPECT_EQ(MediaContentDescription::kNo,
2257 video_answer->extmap_allow_mixed_enum());
2258}
Johannes Kron0854eb62018-10-10 22:33:20 +02002259
Emil Lundmark801c9992021-01-19 13:06:32 +01002260TEST_F(MediaSessionDescriptionFactoryTest,
2261 OfferAndAnswerHaveSameMixedByteMediaAttributes) {
2262 MediaSessionOptions opts;
2263 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2264 std::unique_ptr<SessionDescription> offer =
2265 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2266 offer->set_extmap_allow_mixed(false);
2267 MediaContentDescription* audio_offer =
2268 offer->GetContentDescriptionByName("audio");
Johannes Kron9581bc42018-10-23 10:17:39 +02002269 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Emil Lundmark801c9992021-01-19 13:06:32 +01002270 MediaContentDescription* video_offer =
2271 offer->GetContentDescriptionByName("video");
2272 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2273
2274 std::unique_ptr<SessionDescription> answer(
2275 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2276
2277 MediaContentDescription* audio_answer =
2278 answer->GetContentDescriptionByName("audio");
2279 MediaContentDescription* video_answer =
2280 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002281 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002282 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002283 EXPECT_EQ(MediaContentDescription::kMedia,
2284 video_answer->extmap_allow_mixed_enum());
2285}
2286
2287TEST_F(MediaSessionDescriptionFactoryTest,
2288 OfferAndAnswerHaveDifferentMixedByteMediaAttributes) {
2289 MediaSessionOptions opts;
2290 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2291 std::unique_ptr<SessionDescription> offer =
2292 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2293 offer->set_extmap_allow_mixed(false);
2294 MediaContentDescription* audio_offer =
2295 offer->GetContentDescriptionByName("audio");
2296 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2297 MediaContentDescription* video_offer =
2298 offer->GetContentDescriptionByName("video");
2299 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2300
2301 std::unique_ptr<SessionDescription> answer(
2302 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2303
2304 MediaContentDescription* audio_answer =
2305 answer->GetContentDescriptionByName("audio");
2306 MediaContentDescription* video_answer =
2307 answer->GetContentDescriptionByName("video");
2308 EXPECT_EQ(MediaContentDescription::kNo,
2309 audio_answer->extmap_allow_mixed_enum());
2310 EXPECT_EQ(MediaContentDescription::kMedia,
2311 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002312}
2313
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002314// Create an audio and video offer with:
2315// - one video track
2316// - two audio tracks
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002317// and ensure it matches what we expect. Also updates the initial offer by
2318// adding a new video track and replaces one of the audio tracks.
2319TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2320 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002321 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002322 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2323 {kMediaStream1}, 1, &opts);
2324 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2325 {kMediaStream1}, 1, &opts);
2326 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2327 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002328
Harald Alvestrand0d018412021-11-04 13:52:31 +00002329 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002330 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002331
2332 ASSERT_TRUE(offer.get() != NULL);
2333 const ContentInfo* ac = offer->GetContentByName("audio");
2334 const ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002335 ASSERT_TRUE(ac != NULL);
2336 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002337 const AudioContentDescription* acd = ac->media_description()->as_audio();
2338 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002339 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002340 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002341
2342 const StreamParamsVec& audio_streams = acd->streams();
2343 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002344 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002345 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2346 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2347 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2348 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2349 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2350 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2351
2352 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2353 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +00002354 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002355
2356 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002357 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002358 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002359
2360 const StreamParamsVec& video_streams = vcd->streams();
2361 ASSERT_EQ(1U, video_streams.size());
2362 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2363 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2364 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2365 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2366
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002367 // Update the offer. Add a new video track that is not synched to the
2368 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002369 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2370 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002371 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002372 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2373 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002374 std::unique_ptr<SessionDescription> updated_offer(
2375 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002376
2377 ASSERT_TRUE(updated_offer.get() != NULL);
2378 ac = updated_offer->GetContentByName("audio");
2379 vc = updated_offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002380 ASSERT_TRUE(ac != NULL);
2381 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002383 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002384 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002385 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002386
2387 EXPECT_EQ(acd->type(), updated_acd->type());
2388 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2389 EXPECT_EQ(vcd->type(), updated_vcd->type());
2390 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002391 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2392 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2393 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2394 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002395
2396 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2397 ASSERT_EQ(2U, updated_audio_streams.size());
2398 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2399 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2400 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2401 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2402 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2403
2404 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2405 ASSERT_EQ(2U, updated_video_streams.size());
2406 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2407 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002408 // All the media streams in one PeerConnection share one RTCP CNAME.
2409 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002410}
2411
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002412// Create an offer with simulcast video stream.
2413TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2414 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002415 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2416 RtpTransceiverDirection::kRecvOnly, kActive,
2417 &opts);
2418 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2419 RtpTransceiverDirection::kSendRecv, kActive,
2420 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002421 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002422 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2423 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002424 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002425
2426 ASSERT_TRUE(offer.get() != NULL);
2427 const ContentInfo* vc = offer->GetContentByName("video");
2428 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002429 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002430
2431 const StreamParamsVec& video_streams = vcd->streams();
2432 ASSERT_EQ(1U, video_streams.size());
2433 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2434 const SsrcGroup* sim_ssrc_group =
2435 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2436 ASSERT_TRUE(sim_ssrc_group != NULL);
2437 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2438}
2439
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002440MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2441 const RidDescription& rid1 = ::testing::get<0>(arg);
2442 const RidDescription& rid2 = ::testing::get<1>(arg);
2443 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2444}
2445
2446static void CheckSimulcastInSessionDescription(
2447 const SessionDescription* description,
2448 const std::string& content_name,
2449 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002450 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002451 ASSERT_NE(description, nullptr);
2452 const ContentInfo* content = description->GetContentByName(content_name);
2453 ASSERT_NE(content, nullptr);
2454 const MediaContentDescription* cd = content->media_description();
2455 ASSERT_NE(cd, nullptr);
2456 const StreamParamsVec& streams = cd->streams();
2457 ASSERT_THAT(streams, SizeIs(1));
2458 const StreamParams& stream = streams[0];
2459 ASSERT_THAT(stream.ssrcs, IsEmpty());
2460 EXPECT_TRUE(stream.has_rids());
2461 const std::vector<RidDescription> rids = stream.rids();
2462
2463 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2464
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002465 EXPECT_TRUE(cd->HasSimulcast());
2466 const SimulcastDescription& simulcast = cd->simulcast_description();
2467 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2468 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2469
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002470 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002471}
2472
2473// Create an offer with spec-compliant simulcast video stream.
2474TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2475 MediaSessionOptions opts;
2476 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2477 RtpTransceiverDirection::kSendRecv, kActive,
2478 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002479 std::vector<RidDescription> send_rids;
2480 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2481 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2482 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2483 SimulcastLayerList simulcast_layers;
2484 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2485 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2486 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2487 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2488 {kMediaStream1}, send_rids,
2489 simulcast_layers, 0, &opts);
2490 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2491
2492 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002493 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002494}
2495
2496// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2497// In this scenario, RIDs do not need to be negotiated (there is only one).
2498TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2499 MediaSessionOptions opts;
2500 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2501 RtpTransceiverDirection::kSendRecv, kActive,
2502 &opts);
2503 RidDescription rid("f", RidDirection::kSend);
2504 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2505 {kMediaStream1}, {rid},
2506 SimulcastLayerList(), 0, &opts);
2507 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2508
2509 ASSERT_NE(offer.get(), nullptr);
2510 const ContentInfo* content = offer->GetContentByName("video");
2511 ASSERT_NE(content, nullptr);
2512 const MediaContentDescription* cd = content->media_description();
2513 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002514 const StreamParamsVec& streams = cd->streams();
2515 ASSERT_THAT(streams, SizeIs(1));
2516 const StreamParams& stream = streams[0];
2517 ASSERT_THAT(stream.ssrcs, IsEmpty());
2518 EXPECT_FALSE(stream.has_rids());
2519 EXPECT_FALSE(cd->HasSimulcast());
2520}
2521
2522// Create an answer with spec-compliant simulcast video stream.
2523// In this scenario, the SFU is the caller requesting that we send Simulcast.
2524TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2525 MediaSessionOptions offer_opts;
2526 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2527 RtpTransceiverDirection::kSendRecv, kActive,
2528 &offer_opts);
2529 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2530 {kMediaStream1}, 1, &offer_opts);
2531 std::unique_ptr<SessionDescription> offer =
2532 f1_.CreateOffer(offer_opts, nullptr);
2533
2534 MediaSessionOptions answer_opts;
2535 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2536 RtpTransceiverDirection::kSendRecv, kActive,
2537 &answer_opts);
2538
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002539 std::vector<RidDescription> rid_descriptions{
2540 RidDescription("f", RidDirection::kSend),
2541 RidDescription("h", RidDirection::kSend),
2542 RidDescription("q", RidDirection::kSend),
2543 };
2544 SimulcastLayerList simulcast_layers;
2545 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2546 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2547 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2548 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2549 {kMediaStream1}, rid_descriptions,
2550 simulcast_layers, 0, &answer_opts);
2551 std::unique_ptr<SessionDescription> answer =
2552 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2553
2554 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002555 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002556}
2557
2558// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2559// In this scenario, RIDs do not need to be negotiated (there is only one).
2560// Note that RID Direction is not the same as the transceiver direction.
2561TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2562 MediaSessionOptions offer_opts;
2563 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2564 RtpTransceiverDirection::kSendRecv, kActive,
2565 &offer_opts);
2566 RidDescription rid_offer("f", RidDirection::kSend);
2567 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2568 {kMediaStream1}, {rid_offer},
2569 SimulcastLayerList(), 0, &offer_opts);
2570 std::unique_ptr<SessionDescription> offer =
2571 f1_.CreateOffer(offer_opts, nullptr);
2572
2573 MediaSessionOptions answer_opts;
2574 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2575 RtpTransceiverDirection::kSendRecv, kActive,
2576 &answer_opts);
2577
2578 RidDescription rid_answer("f", RidDirection::kReceive);
2579 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2580 {kMediaStream1}, {rid_answer},
2581 SimulcastLayerList(), 0, &answer_opts);
2582 std::unique_ptr<SessionDescription> answer =
2583 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2584
2585 ASSERT_NE(answer.get(), nullptr);
2586 const ContentInfo* content = offer->GetContentByName("video");
2587 ASSERT_NE(content, nullptr);
2588 const MediaContentDescription* cd = content->media_description();
2589 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002590 const StreamParamsVec& streams = cd->streams();
2591 ASSERT_THAT(streams, SizeIs(1));
2592 const StreamParams& stream = streams[0];
2593 ASSERT_THAT(stream.ssrcs, IsEmpty());
2594 EXPECT_FALSE(stream.has_rids());
2595 EXPECT_FALSE(cd->HasSimulcast());
2596}
2597
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002598// Create an audio and video answer to a standard video offer with:
2599// - one video track
2600// - two audio tracks
2601// - two data tracks
2602// and ensure it matches what we expect. Also updates the initial answer by
2603// adding a new video track and removes one of the audio tracks.
2604TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2605 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002606 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2607 RtpTransceiverDirection::kRecvOnly, kActive,
2608 &offer_opts);
2609 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2610 RtpTransceiverDirection::kRecvOnly, kActive,
2611 &offer_opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00002612 f1_.set_secure(SEC_ENABLED);
2613 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002614 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002615
zhihuang1c378ed2017-08-17 14:10:50 -07002616 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002617 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2618 RtpTransceiverDirection::kSendRecv, kActive,
2619 &answer_opts);
2620 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2621 RtpTransceiverDirection::kSendRecv, kActive,
2622 &answer_opts);
2623 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2624 {kMediaStream1}, 1, &answer_opts);
2625 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2626 {kMediaStream1}, 1, &answer_opts);
2627 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2628 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002629
Steve Anton6fe1fba2018-12-11 10:15:23 -08002630 std::unique_ptr<SessionDescription> answer =
2631 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002632
2633 ASSERT_TRUE(answer.get() != NULL);
2634 const ContentInfo* ac = answer->GetContentByName("audio");
2635 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002636 ASSERT_TRUE(ac != NULL);
2637 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002638 const AudioContentDescription* acd = ac->media_description()->as_audio();
2639 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand0d018412021-11-04 13:52:31 +00002640 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2641 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642
2643 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002644 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002645
2646 const StreamParamsVec& audio_streams = acd->streams();
2647 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002648 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002649 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2650 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2651 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2652 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2653 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2654 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2655
2656 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2657 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2658
2659 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002660 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661
2662 const StreamParamsVec& video_streams = vcd->streams();
2663 ASSERT_EQ(1U, video_streams.size());
2664 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2665 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2666 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2667 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2668
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002669 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002670 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002671 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2672 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002673 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002674 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002675 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002676
2677 ASSERT_TRUE(updated_answer.get() != NULL);
2678 ac = updated_answer->GetContentByName("audio");
2679 vc = updated_answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680 ASSERT_TRUE(ac != NULL);
2681 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002682 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002683 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002685 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686
Harald Alvestrand0d018412021-11-04 13:52:31 +00002687 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2688 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2689 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2690 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
2691
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002692 EXPECT_EQ(acd->type(), updated_acd->type());
2693 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2694 EXPECT_EQ(vcd->type(), updated_vcd->type());
2695 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696
2697 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2698 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002699 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002700
2701 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2702 ASSERT_EQ(2U, updated_video_streams.size());
2703 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2704 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002705 // All media streams in one PeerConnection share one CNAME.
2706 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707}
2708
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002709// Create an updated offer after creating an answer to the original offer and
2710// verify that the codecs that were part of the original answer are not changed
2711// in the updated offer.
2712TEST_F(MediaSessionDescriptionFactoryTest,
2713 RespondentCreatesOfferAfterCreatingAnswer) {
2714 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002715 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716
Steve Anton6fe1fba2018-12-11 10:15:23 -08002717 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2718 std::unique_ptr<SessionDescription> answer =
2719 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720
2721 const AudioContentDescription* acd =
2722 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002723 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002724
2725 const VideoContentDescription* vcd =
2726 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002727 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002728
kwiberg31022942016-03-11 14:18:21 -08002729 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730 f2_.CreateOffer(opts, answer.get()));
2731
2732 // The expected audio codecs are the common audio codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002733 // offer/answer exchange plus the audio codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002734 // preference order.
Artem Titov880fa812021-07-30 22:30:23 +02002735 // TODO(wu): `updated_offer` should not include the codec
Artem Titovcfea2182021-08-10 01:22:31 +02002736 // (i.e. `kAudioCodecs2[0]`) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002738 kAudioCodecsAnswer[0],
2739 kAudioCodecsAnswer[1],
2740 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002741 };
2742
2743 // The expected video codecs are the common video codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002744 // offer/answer exchange plus the video codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002745 // preference order.
2746 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002747 kVideoCodecsAnswer[0],
2748 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002749 };
2750
2751 const AudioContentDescription* updated_acd =
2752 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002753 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002754
2755 const VideoContentDescription* updated_vcd =
2756 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002757 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758}
2759
Steve Anton5c72e712018-12-10 14:25:30 -08002760// Test that a reoffer does not reuse audio codecs from a previous media section
2761// that is being recycled.
2762TEST_F(MediaSessionDescriptionFactoryTest,
2763 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002764 f1_.set_video_codecs({}, {});
2765 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002766
2767 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002768 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2769 RtpTransceiverDirection::kSendRecv, kActive,
2770 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002771 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2772 std::unique_ptr<SessionDescription> answer =
2773 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002774
2775 // Recycle the media section by changing its mid.
2776 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002777 std::unique_ptr<SessionDescription> reoffer =
2778 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002779
2780 // Expect that the results of the first negotiation are ignored. If the m=
2781 // section was not recycled the payload types would match the initial offerer.
2782 const AudioContentDescription* acd =
2783 GetFirstAudioContentDescription(reoffer.get());
2784 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2785}
2786
2787// Test that a reoffer does not reuse video codecs from a previous media section
2788// that is being recycled.
2789TEST_F(MediaSessionDescriptionFactoryTest,
2790 ReOfferDoesNotReUseRecycledVideoCodecs) {
2791 f1_.set_audio_codecs({}, {});
2792 f2_.set_audio_codecs({}, {});
2793
2794 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002795 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2796 RtpTransceiverDirection::kSendRecv, kActive,
2797 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002798 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2799 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002800
2801 // Recycle the media section by changing its mid.
2802 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002803 std::unique_ptr<SessionDescription> reoffer =
2804 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002805
2806 // Expect that the results of the first negotiation are ignored. If the m=
2807 // section was not recycled the payload types would match the initial offerer.
2808 const VideoContentDescription* vcd =
2809 GetFirstVideoContentDescription(reoffer.get());
2810 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2811}
2812
2813// Test that a reanswer does not reuse audio codecs from a previous media
2814// section that is being recycled.
2815TEST_F(MediaSessionDescriptionFactoryTest,
2816 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002817 f1_.set_video_codecs({}, {});
2818 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002819
Artem Titov880fa812021-07-30 22:30:23 +02002820 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2821 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002822 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002823 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2824 RtpTransceiverDirection::kSendRecv, kActive,
2825 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002826 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2827 std::unique_ptr<SessionDescription> answer =
2828 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002829
2830 // Recycle the media section by changing its mid.
2831 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002832 std::unique_ptr<SessionDescription> reoffer =
2833 f1_.CreateOffer(opts, answer.get());
2834 std::unique_ptr<SessionDescription> reanswer =
2835 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002836
2837 // Expect that the results of the first negotiation are ignored. If the m=
2838 // section was not recycled the payload types would match the initial offerer.
2839 const AudioContentDescription* acd =
2840 GetFirstAudioContentDescription(reanswer.get());
2841 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2842}
2843
2844// Test that a reanswer does not reuse video codecs from a previous media
2845// section that is being recycled.
2846TEST_F(MediaSessionDescriptionFactoryTest,
2847 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2848 f1_.set_audio_codecs({}, {});
2849 f2_.set_audio_codecs({}, {});
2850
Artem Titov880fa812021-07-30 22:30:23 +02002851 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2852 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002853 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002854 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2855 RtpTransceiverDirection::kSendRecv, kActive,
2856 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002857 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2858 std::unique_ptr<SessionDescription> answer =
2859 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002860
2861 // Recycle the media section by changing its mid.
2862 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002863 std::unique_ptr<SessionDescription> reoffer =
2864 f1_.CreateOffer(opts, answer.get());
2865 std::unique_ptr<SessionDescription> reanswer =
2866 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002867
2868 // Expect that the results of the first negotiation are ignored. If the m=
2869 // section was not recycled the payload types would match the initial offerer.
2870 const VideoContentDescription* vcd =
2871 GetFirstVideoContentDescription(reanswer.get());
2872 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2873}
2874
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002875// Create an updated offer after creating an answer to the original offer and
2876// verify that the codecs that were part of the original answer are not changed
2877// in the updated offer. In this test Rtx is enabled.
2878TEST_F(MediaSessionDescriptionFactoryTest,
2879 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2880 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002881 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2882 RtpTransceiverDirection::kRecvOnly, kActive,
2883 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002884 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02002885 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002886 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002887 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002888
2889 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02002890 // This creates rtx for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002891 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002892 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002893
Steve Anton6fe1fba2018-12-11 10:15:23 -08002894 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002895 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002896 std::unique_ptr<SessionDescription> answer =
2897 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002898
2899 const VideoContentDescription* vcd =
2900 GetFirstVideoContentDescription(answer.get());
2901
2902 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002903 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2904 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002905
2906 EXPECT_EQ(expected_codecs, vcd->codecs());
2907
Artem Titov880fa812021-07-30 22:30:23 +02002908 // Now, make sure we get same result (except for the order) if `f2_` creates
2909 // an updated offer even though the default payload types between `f1_` and
2910 // `f2_` are different.
kwiberg31022942016-03-11 14:18:21 -08002911 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002912 f2_.CreateOffer(opts, answer.get()));
2913 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002914 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002915 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2916
2917 const VideoContentDescription* updated_vcd =
2918 GetFirstVideoContentDescription(updated_answer.get());
2919
2920 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2921}
2922
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002923// Regression test for:
2924// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2925// Existing codecs should always appear before new codecs in re-offers. But
2926// under a specific set of circumstances, the existing RTX codec was ending up
2927// added to the end of the list.
2928TEST_F(MediaSessionDescriptionFactoryTest,
2929 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2930 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002931 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2932 RtpTransceiverDirection::kRecvOnly, kActive,
2933 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002934 // We specifically choose different preferred payload types for VP8 to
2935 // trigger the issue.
2936 cricket::VideoCodec vp8_offerer(100, "VP8");
2937 cricket::VideoCodec vp8_offerer_rtx =
2938 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2939 cricket::VideoCodec vp8_answerer(110, "VP8");
2940 cricket::VideoCodec vp8_answerer_rtx =
2941 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2942 cricket::VideoCodec vp9(120, "VP9");
2943 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2944
2945 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2946 // We also specifically cause the answerer to prefer VP9, such that if it
2947 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2948 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2949 vp8_answerer_rtx};
2950
Johannes Kron3e983682020-03-29 22:17:00 +02002951 f1_.set_video_codecs(f1_codecs, f1_codecs);
2952 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002953 std::vector<AudioCodec> audio_codecs;
2954 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2955 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2956
2957 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002958 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002959 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002960 std::unique_ptr<SessionDescription> answer =
2961 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002962
2963 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2964 // But if the bug is triggered, RTX for VP8 ends up last.
2965 std::unique_ptr<SessionDescription> updated_offer(
2966 f2_.CreateOffer(opts, answer.get()));
2967
2968 const VideoContentDescription* vcd =
2969 GetFirstVideoContentDescription(updated_offer.get());
2970 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2971 ASSERT_EQ(4u, codecs.size());
2972 EXPECT_EQ(vp8_offerer, codecs[0]);
2973 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2974 EXPECT_EQ(vp9, codecs[2]);
2975 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002976}
2977
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002978// Create an updated offer that adds video after creating an audio only answer
2979// to the original offer. This test verifies that if a video codec and the RTX
2980// codec have the same default payload type as an audio codec that is already in
2981// use, the added codecs payload types are changed.
2982TEST_F(MediaSessionDescriptionFactoryTest,
2983 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2984 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02002985 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002986 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002987 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002988
2989 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002990 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2991 RtpTransceiverDirection::kRecvOnly, kActive,
2992 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002993
Steve Anton6fe1fba2018-12-11 10:15:23 -08002994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2995 std::unique_ptr<SessionDescription> answer =
2996 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002997
2998 const AudioContentDescription* acd =
2999 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003000 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003001
Artem Titov880fa812021-07-30 22:30:23 +02003002 // Now - let `f2_` add video with RTX and let the payload type the RTX codec
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003003 // reference be the same as an audio codec that was negotiated in the
3004 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07003005 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08003006 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003007
3008 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3009 int used_pl_type = acd->codecs()[0].id;
3010 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003011 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003012 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003013
kwiberg31022942016-03-11 14:18:21 -08003014 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003015 f2_.CreateOffer(opts, answer.get()));
3016 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003017 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003018 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3019
3020 const AudioContentDescription* updated_acd =
3021 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003022 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003023
3024 const VideoContentDescription* updated_vcd =
3025 GetFirstVideoContentDescription(updated_answer.get());
3026
3027 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003028 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003029 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003030 EXPECT_NE(used_pl_type, new_h264_pl_type);
3031 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003032 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003033 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3034 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3035}
3036
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003037// Create an updated offer with RTX after creating an answer to an offer
3038// without RTX, and with different default payload types.
3039// Verify that the added RTX codec references the correct payload type.
3040TEST_F(MediaSessionDescriptionFactoryTest,
3041 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3042 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003043 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003044
3045 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003046 // This creates rtx for H264 with the payload type `f2_` uses.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003047 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003048 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003049
Steve Anton6fe1fba2018-12-11 10:15:23 -08003050 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003051 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003052 std::unique_ptr<SessionDescription> answer =
3053 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003054
3055 const VideoContentDescription* vcd =
3056 GetFirstVideoContentDescription(answer.get());
3057
3058 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3059 EXPECT_EQ(expected_codecs, vcd->codecs());
3060
Artem Titov880fa812021-07-30 22:30:23 +02003061 // Now, ensure that the RTX codec is created correctly when `f2_` creates an
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003062 // updated offer, even though the default payload types are different from
Artem Titov880fa812021-07-30 22:30:23 +02003063 // those of `f1_`.
kwiberg31022942016-03-11 14:18:21 -08003064 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003065 f2_.CreateOffer(opts, answer.get()));
3066 ASSERT_TRUE(updated_offer);
3067
3068 const VideoContentDescription* updated_vcd =
3069 GetFirstVideoContentDescription(updated_offer.get());
3070
3071 // New offer should attempt to add H263, and RTX for H264.
3072 expected_codecs.push_back(kVideoCodecs2[1]);
3073 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3074 &expected_codecs);
3075 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3076}
3077
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003078// Test that RTX is ignored when there is no associated payload type parameter.
3079TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3080 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003081 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3082 RtpTransceiverDirection::kRecvOnly, kActive,
3083 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003084 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003085 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003086 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003087 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003088
3089 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003090 // This creates RTX for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003091 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003092 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003093
Steve Anton6fe1fba2018-12-11 10:15:23 -08003094 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003095 ASSERT_TRUE(offer.get() != NULL);
3096 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3097 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3098 // is possible to test that that RTX is dropped when
3099 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003100 MediaContentDescription* media_desc =
3101 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3102 ASSERT_TRUE(media_desc);
3103 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003104 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003105 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003106 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003107 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003108 }
3109 }
3110 desc->set_codecs(codecs);
3111
Steve Anton6fe1fba2018-12-11 10:15:23 -08003112 std::unique_ptr<SessionDescription> answer =
3113 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003114
Steve Anton64b626b2019-01-28 17:25:26 -08003115 EXPECT_THAT(
3116 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3117 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003118}
3119
3120// Test that RTX will be filtered out in the answer if its associated payload
3121// type doesn't match the local value.
3122TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3123 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003124 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3125 RtpTransceiverDirection::kRecvOnly, kActive,
3126 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003127 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3128 // This creates RTX for H264 in sender.
3129 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003130 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003131
3132 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3133 // This creates RTX for H263 in receiver.
3134 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003135 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003136
Steve Anton6fe1fba2018-12-11 10:15:23 -08003137 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003138 ASSERT_TRUE(offer.get() != NULL);
3139 // Associated payload type doesn't match, therefore, RTX codec is removed in
3140 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003141 std::unique_ptr<SessionDescription> answer =
3142 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003143
Steve Anton64b626b2019-01-28 17:25:26 -08003144 EXPECT_THAT(
3145 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3146 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003147}
3148
3149// Test that when multiple RTX codecs are offered, only the matched RTX codec
3150// is added in the answer, and the unsupported RTX codec is filtered out.
3151TEST_F(MediaSessionDescriptionFactoryTest,
3152 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3153 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003154 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3155 RtpTransceiverDirection::kRecvOnly, kActive,
3156 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003157 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3158 // This creates RTX for H264-SVC in sender.
3159 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].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 // This creates RTX for H264 in sender.
3163 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003164 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003165
3166 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3167 // This creates RTX for H264 in receiver.
3168 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003169 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003170
3171 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3172 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003173 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003174 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003175 std::unique_ptr<SessionDescription> answer =
3176 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003177 const VideoContentDescription* vcd =
3178 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003179 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3180 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3181 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003182
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003183 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003184}
3185
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003186// Test that after one RTX codec has been negotiated, a new offer can attempt
3187// to add another.
3188TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3189 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003190 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3191 RtpTransceiverDirection::kRecvOnly, kActive,
3192 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003193 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3194 // This creates RTX for H264 for the offerer.
3195 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003196 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003197
Steve Anton6fe1fba2018-12-11 10:15:23 -08003198 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003199 ASSERT_TRUE(offer);
3200 const VideoContentDescription* vcd =
3201 GetFirstVideoContentDescription(offer.get());
3202
3203 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3204 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3205 &expected_codecs);
3206 EXPECT_EQ(expected_codecs, vcd->codecs());
3207
3208 // Now, attempt to add RTX for H264-SVC.
3209 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003210 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003211
kwiberg31022942016-03-11 14:18:21 -08003212 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003213 f1_.CreateOffer(opts, offer.get()));
3214 ASSERT_TRUE(updated_offer);
3215 vcd = GetFirstVideoContentDescription(updated_offer.get());
3216
3217 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3218 &expected_codecs);
3219 EXPECT_EQ(expected_codecs, vcd->codecs());
3220}
3221
Noah Richards2e7a0982015-05-18 14:02:54 -07003222// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3223// generated for each simulcast ssrc and correctly grouped.
3224TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3225 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003226 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3227 RtpTransceiverDirection::kSendRecv, kActive,
3228 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003229 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003230 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3231 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003232
3233 // Use a single real codec, and then add RTX for it.
3234 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003235 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003236 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003237 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003238
3239 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3240 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003241 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003242 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003243 MediaContentDescription* media_desc =
3244 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3245 ASSERT_TRUE(media_desc);
3246 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003247 const StreamParamsVec& streams = desc->streams();
3248 // Single stream.
3249 ASSERT_EQ(1u, streams.size());
3250 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3251 EXPECT_EQ(6u, streams[0].ssrcs.size());
3252 // And should have a SIM group for the simulcast.
3253 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3254 // And a FID group for RTX.
3255 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003256 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003257 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3258 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003259 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003260 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3261 EXPECT_EQ(3u, fid_ssrcs.size());
3262}
3263
brandtr03d5fb12016-11-22 03:37:59 -08003264// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003265// together with a FEC-FR grouping. Guarded by WebRTC-FlexFEC-03 trial.
brandtr03d5fb12016-11-22 03:37:59 -08003266TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01003267 webrtc::test::ScopedKeyValueConfig override_field_trials(
3268 field_trials, "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003269 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003270 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3271 RtpTransceiverDirection::kSendRecv, kActive,
3272 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003273 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003274 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3275 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003276
3277 // Use a single real codec, and then add FlexFEC for it.
3278 std::vector<VideoCodec> f1_codecs;
3279 f1_codecs.push_back(VideoCodec(97, "H264"));
3280 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003281 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003282
3283 // Ensure that the offer has a single FlexFEC ssrc and that
3284 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003285 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003286 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003287 MediaContentDescription* media_desc =
3288 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3289 ASSERT_TRUE(media_desc);
3290 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003291 const StreamParamsVec& streams = desc->streams();
3292 // Single stream.
3293 ASSERT_EQ(1u, streams.size());
3294 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3295 EXPECT_EQ(2u, streams[0].ssrcs.size());
3296 // And should have a FEC-FR group for FlexFEC.
3297 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3298 std::vector<uint32_t> primary_ssrcs;
3299 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3300 ASSERT_EQ(1u, primary_ssrcs.size());
3301 uint32_t flexfec_ssrc;
3302 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3303 EXPECT_NE(flexfec_ssrc, 0u);
3304}
3305
3306// Test that FlexFEC is disabled for simulcast.
3307// TODO(brandtr): Remove this test when we support simulcast, either through
3308// multiple FlexfecSenders, or through multistream protection.
3309TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01003310 webrtc::test::ScopedKeyValueConfig override_field_trials(
3311 field_trials, "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003312 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003313 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3314 RtpTransceiverDirection::kSendRecv, kActive,
3315 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003316 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003317 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3318 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003319
3320 // Use a single real codec, and then add FlexFEC for it.
3321 std::vector<VideoCodec> f1_codecs;
3322 f1_codecs.push_back(VideoCodec(97, "H264"));
3323 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003324 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003325
3326 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3327 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003328 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003329 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003330 MediaContentDescription* media_desc =
3331 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3332 ASSERT_TRUE(media_desc);
3333 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003334 const StreamParamsVec& streams = desc->streams();
3335 // Single stream.
3336 ASSERT_EQ(1u, streams.size());
3337 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3338 EXPECT_EQ(3u, streams[0].ssrcs.size());
3339 // And should have a SIM group for the simulcast.
3340 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3341 // And not a FEC-FR group for FlexFEC.
3342 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3343 std::vector<uint32_t> primary_ssrcs;
3344 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3345 EXPECT_EQ(3u, primary_ssrcs.size());
3346 for (uint32_t primary_ssrc : primary_ssrcs) {
3347 uint32_t flexfec_ssrc;
3348 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3349 }
3350}
3351
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003352// Create an updated offer after creating an answer to the original offer and
3353// verify that the RTP header extensions that were part of the original answer
3354// are not changed in the updated offer.
3355TEST_F(MediaSessionDescriptionFactoryTest,
3356 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3357 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003358 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003359
Markus Handell755c65d2020-06-24 01:06:10 +02003360 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3361 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003362 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02003363 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3364 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003365 std::unique_ptr<SessionDescription> answer =
3366 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003367
Yves Gerey665174f2018-06-19 15:03:05 +02003368 EXPECT_EQ(
3369 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3370 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3371 EXPECT_EQ(
3372 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3373 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003374
kwiberg31022942016-03-11 14:18:21 -08003375 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003376 f2_.CreateOffer(opts, answer.get()));
3377
3378 // The expected RTP header extensions in the new offer are the resulting
3379 // extensions from the first offer/answer exchange plus the extensions only
Artem Titov880fa812021-07-30 22:30:23 +02003380 // `f2_` offer.
3381 // Since the default local extension id `f2_` uses has already been used by
3382 // `f1_` for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003383 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003384 kAudioRtpExtensionAnswer[0],
3385 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003386 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003387 };
3388
Artem Titov880fa812021-07-30 22:30:23 +02003389 // Since the default local extension id `f2_` uses has already been used by
3390 // `f1_` for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003391 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003392 kVideoRtpExtensionAnswer[0],
3393 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003394 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003395 };
3396
3397 const AudioContentDescription* updated_acd =
3398 GetFirstAudioContentDescription(updated_offer.get());
3399 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3400 updated_acd->rtp_header_extensions());
3401
3402 const VideoContentDescription* updated_vcd =
3403 GetFirstVideoContentDescription(updated_offer.get());
3404 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3405 updated_vcd->rtp_header_extensions());
3406}
3407
deadbeefa5b273a2015-08-20 17:30:13 -07003408// Verify that if the same RTP extension URI is used for audio and video, the
3409// same ID is used. Also verify that the ID isn't changed when creating an
3410// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003411TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003412 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003413 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003414
Markus Handell755c65d2020-06-24 01:06:10 +02003415 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3416 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003417 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003418
3419 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3420 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003421 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003422 kVideoRtpExtension3[0],
3423 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003424 };
3425
Yves Gerey665174f2018-06-19 15:03:05 +02003426 EXPECT_EQ(
3427 MAKE_VECTOR(kAudioRtpExtension3),
3428 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3429 EXPECT_EQ(
3430 MAKE_VECTOR(kExpectedVideoRtpExtension),
3431 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003432
3433 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003434 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003435 f1_.CreateOffer(opts, offer.get()));
3436
3437 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003438 GetFirstAudioContentDescription(updated_offer.get())
3439 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003440 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003441 GetFirstVideoContentDescription(updated_offer.get())
3442 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003443}
3444
jbauch5869f502017-06-29 12:31:36 -07003445// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3446TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3447 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003448 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003449
3450 f1_.set_enable_encrypted_rtp_header_extensions(true);
3451 f2_.set_enable_encrypted_rtp_header_extensions(true);
3452
Markus Handell755c65d2020-06-24 01:06:10 +02003453 SetAudioVideoRtpHeaderExtensions(
3454 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3455 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003456 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003457
Yves Gerey665174f2018-06-19 15:03:05 +02003458 EXPECT_EQ(
3459 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3460 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3461 EXPECT_EQ(
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003462 MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003463 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003464
3465 // Nothing should change when creating a new offer
3466 std::unique_ptr<SessionDescription> updated_offer(
3467 f1_.CreateOffer(opts, offer.get()));
3468
3469 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003470 GetFirstAudioContentDescription(updated_offer.get())
3471 ->rtp_header_extensions());
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003472 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003473 GetFirstVideoContentDescription(updated_offer.get())
3474 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003475}
3476
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003477TEST(MediaSessionDescription, CopySessionDescription) {
3478 SessionDescription source;
3479 cricket::ContentGroup group(cricket::CN_AUDIO);
3480 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003481 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003482 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003483 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3484 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003485 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003486 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003487 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003488 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3489 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003490 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003491
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003492 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003493 ASSERT_TRUE(copy.get() != NULL);
3494 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3495 const ContentInfo* ac = copy->GetContentByName("audio");
3496 const ContentInfo* vc = copy->GetContentByName("video");
3497 ASSERT_TRUE(ac != NULL);
3498 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003499 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003500 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003501 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3502 EXPECT_EQ(1u, acd->first_ssrc());
3503
Steve Anton5adfafd2017-12-20 16:34:00 -08003504 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003505 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003506 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3507 EXPECT_EQ(2u, vcd->first_ssrc());
3508}
3509
3510// The below TestTransportInfoXXX tests create different offers/answers, and
3511// ensure the TransportInfo in the SessionDescription matches what we expect.
3512TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3513 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003514 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3515 RtpTransceiverDirection::kRecvOnly, kActive,
3516 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003517 TestTransportInfo(true, options, false);
3518}
3519
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003520TEST_F(MediaSessionDescriptionFactoryTest,
3521 TestTransportInfoOfferIceRenomination) {
3522 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003523 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3524 RtpTransceiverDirection::kRecvOnly, kActive,
3525 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003526 options.media_description_options[0]
3527 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003528 TestTransportInfo(true, options, false);
3529}
3530
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003531TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3532 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003533 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3534 RtpTransceiverDirection::kRecvOnly, kActive,
3535 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003536 TestTransportInfo(true, options, true);
3537}
3538
3539TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3540 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003541 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003542 TestTransportInfo(true, options, false);
3543}
3544
3545TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003546 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003547 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003548 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003549 TestTransportInfo(true, options, true);
3550}
3551
3552TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3553 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003554 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003555 options.bundle_enabled = true;
3556 TestTransportInfo(true, options, false);
3557}
3558
3559TEST_F(MediaSessionDescriptionFactoryTest,
3560 TestTransportInfoOfferBundleCurrent) {
3561 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003562 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003563 options.bundle_enabled = true;
3564 TestTransportInfo(true, options, true);
3565}
3566
3567TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3568 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003569 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3570 RtpTransceiverDirection::kRecvOnly, kActive,
3571 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003572 TestTransportInfo(false, options, false);
3573}
3574
3575TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003576 TestTransportInfoAnswerIceRenomination) {
3577 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003578 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3579 RtpTransceiverDirection::kRecvOnly, kActive,
3580 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003581 options.media_description_options[0]
3582 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003583 TestTransportInfo(false, options, false);
3584}
3585
3586TEST_F(MediaSessionDescriptionFactoryTest,
3587 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003588 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003589 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3590 RtpTransceiverDirection::kRecvOnly, kActive,
3591 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003592 TestTransportInfo(false, options, true);
3593}
3594
3595TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3596 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003597 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003598 TestTransportInfo(false, options, false);
3599}
3600
3601TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003602 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003603 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003604 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003605 TestTransportInfo(false, options, true);
3606}
3607
3608TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3609 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003610 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003611 options.bundle_enabled = true;
3612 TestTransportInfo(false, options, false);
3613}
3614
3615TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003616 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003617 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003618 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003619 options.bundle_enabled = true;
3620 TestTransportInfo(false, options, true);
3621}
3622
Harald Alvestrand0d018412021-11-04 13:52:31 +00003623// Create an offer with bundle enabled and verify the crypto parameters are
3624// the common set of the available cryptos.
3625TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3626 TestCryptoWithBundle(true);
3627}
3628
3629// Create an answer with bundle enabled and verify the crypto parameters are
3630// the common set of the available cryptos.
3631TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3632 TestCryptoWithBundle(false);
3633}
3634
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003635// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3636// DTLS is not enabled locally.
3637TEST_F(MediaSessionDescriptionFactoryTest,
3638 TestOfferDtlsSavpfWithoutDtlsFailed) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003639 f1_.set_secure(SEC_ENABLED);
3640 f2_.set_secure(SEC_ENABLED);
3641 tdf1_.set_secure(SEC_DISABLED);
3642 tdf2_.set_secure(SEC_DISABLED);
3643
Steve Anton6fe1fba2018-12-11 10:15:23 -08003644 std::unique_ptr<SessionDescription> offer =
3645 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003646 ASSERT_TRUE(offer.get() != NULL);
3647 ContentInfo* offer_content = offer->GetContentByName("audio");
3648 ASSERT_TRUE(offer_content != NULL);
3649 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003650 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003651 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3652
Steve Anton6fe1fba2018-12-11 10:15:23 -08003653 std::unique_ptr<SessionDescription> answer =
3654 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003655 ASSERT_TRUE(answer != NULL);
3656 ContentInfo* answer_content = answer->GetContentByName("audio");
3657 ASSERT_TRUE(answer_content != NULL);
3658
3659 ASSERT_TRUE(answer_content->rejected);
3660}
3661
3662// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3663// UDP/TLS/RTP/SAVPF.
3664TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003665 f1_.set_secure(SEC_ENABLED);
3666 f2_.set_secure(SEC_ENABLED);
3667 tdf1_.set_secure(SEC_ENABLED);
3668 tdf2_.set_secure(SEC_ENABLED);
3669
Steve Anton6fe1fba2018-12-11 10:15:23 -08003670 std::unique_ptr<SessionDescription> offer =
3671 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003672 ASSERT_TRUE(offer.get() != NULL);
3673 ContentInfo* offer_content = offer->GetContentByName("audio");
3674 ASSERT_TRUE(offer_content != NULL);
3675 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003676 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003677 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3678
Steve Anton6fe1fba2018-12-11 10:15:23 -08003679 std::unique_ptr<SessionDescription> answer =
3680 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003681 ASSERT_TRUE(answer != NULL);
3682
3683 const ContentInfo* answer_content = answer->GetContentByName("audio");
3684 ASSERT_TRUE(answer_content != NULL);
3685 ASSERT_FALSE(answer_content->rejected);
3686
3687 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003688 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003689 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003690}
3691
Harald Alvestrand0d018412021-11-04 13:52:31 +00003692// Test that we include both SDES and DTLS in the offer, but only include SDES
3693// in the answer if DTLS isn't negotiated.
3694TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3695 f1_.set_secure(SEC_ENABLED);
3696 f2_.set_secure(SEC_ENABLED);
3697 tdf1_.set_secure(SEC_ENABLED);
3698 tdf2_.set_secure(SEC_DISABLED);
3699 MediaSessionOptions options;
3700 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3701 std::unique_ptr<SessionDescription> offer, answer;
3702 const cricket::MediaContentDescription* audio_media_desc;
3703 const cricket::MediaContentDescription* video_media_desc;
3704 const cricket::TransportDescription* audio_trans_desc;
3705 const cricket::TransportDescription* video_trans_desc;
3706
3707 // Generate an offer with SDES and DTLS support.
3708 offer = f1_.CreateOffer(options, NULL);
3709 ASSERT_TRUE(offer.get() != NULL);
3710
3711 audio_media_desc = offer->GetContentDescriptionByName("audio");
3712 ASSERT_TRUE(audio_media_desc != NULL);
3713 video_media_desc = offer->GetContentDescriptionByName("video");
3714 ASSERT_TRUE(video_media_desc != NULL);
3715 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3716 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3717
3718 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3719 ASSERT_TRUE(audio_trans_desc != NULL);
3720 video_trans_desc = offer->GetTransportDescriptionByName("video");
3721 ASSERT_TRUE(video_trans_desc != NULL);
3722 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3723 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3724
3725 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
3726 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3727 ASSERT_TRUE(answer.get() != NULL);
3728
3729 audio_media_desc = answer->GetContentDescriptionByName("audio");
3730 ASSERT_TRUE(audio_media_desc != NULL);
3731 video_media_desc = answer->GetContentDescriptionByName("video");
3732 ASSERT_TRUE(video_media_desc != NULL);
3733 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3734 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3735
3736 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3737 ASSERT_TRUE(audio_trans_desc != NULL);
3738 video_trans_desc = answer->GetTransportDescriptionByName("video");
3739 ASSERT_TRUE(video_trans_desc != NULL);
3740 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3741 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3742
3743 // Enable DTLS; the answer should now only have DTLS support.
3744 tdf2_.set_secure(SEC_ENABLED);
3745 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3746 ASSERT_TRUE(answer.get() != NULL);
3747
3748 audio_media_desc = answer->GetContentDescriptionByName("audio");
3749 ASSERT_TRUE(audio_media_desc != NULL);
3750 video_media_desc = answer->GetContentDescriptionByName("video");
3751 ASSERT_TRUE(video_media_desc != NULL);
3752 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3753 EXPECT_TRUE(video_media_desc->cryptos().empty());
3754 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3755 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
3756
3757 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3758 ASSERT_TRUE(audio_trans_desc != NULL);
3759 video_trans_desc = answer->GetTransportDescriptionByName("video");
3760 ASSERT_TRUE(video_trans_desc != NULL);
3761 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3762 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3763
3764 // Try creating offer again. DTLS enabled now, crypto's should be empty
3765 // in new offer.
3766 offer = f1_.CreateOffer(options, offer.get());
3767 ASSERT_TRUE(offer.get() != NULL);
3768 audio_media_desc = offer->GetContentDescriptionByName("audio");
3769 ASSERT_TRUE(audio_media_desc != NULL);
3770 video_media_desc = offer->GetContentDescriptionByName("video");
3771 ASSERT_TRUE(video_media_desc != NULL);
3772 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3773 EXPECT_TRUE(video_media_desc->cryptos().empty());
3774
3775 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3776 ASSERT_TRUE(audio_trans_desc != NULL);
3777 video_trans_desc = offer->GetTransportDescriptionByName("video");
3778 ASSERT_TRUE(video_trans_desc != NULL);
3779 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3780 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3781}
3782
3783// Test that an answer can't be created if cryptos are required but the offer is
3784// unsecure.
3785TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
3786 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
3787 f1_.set_secure(SEC_DISABLED);
3788 tdf1_.set_secure(SEC_DISABLED);
3789 f2_.set_secure(SEC_REQUIRED);
3790 tdf1_.set_secure(SEC_ENABLED);
3791
3792 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
3793 ASSERT_TRUE(offer.get() != NULL);
3794 std::unique_ptr<SessionDescription> answer =
3795 f2_.CreateAnswer(offer.get(), options, NULL);
3796 EXPECT_TRUE(answer.get() == NULL);
3797}
3798
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003799// Test that we accept a DTLS offer without SDES and create an appropriate
3800// answer.
3801TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003802 f1_.set_secure(SEC_DISABLED);
3803 f2_.set_secure(SEC_ENABLED);
3804 tdf1_.set_secure(SEC_ENABLED);
3805 tdf2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003806 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003807 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003808
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003809 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003810 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003811 ASSERT_TRUE(offer.get() != NULL);
3812
Harald Alvestrand0d018412021-11-04 13:52:31 +00003813 const AudioContentDescription* audio_offer =
3814 GetFirstAudioContentDescription(offer.get());
3815 ASSERT_TRUE(audio_offer->cryptos().empty());
3816 const VideoContentDescription* video_offer =
3817 GetFirstVideoContentDescription(offer.get());
3818 ASSERT_TRUE(video_offer->cryptos().empty());
3819
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003820 const cricket::TransportDescription* audio_offer_trans_desc =
3821 offer->GetTransportDescriptionByName("audio");
3822 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3823 const cricket::TransportDescription* video_offer_trans_desc =
3824 offer->GetTransportDescriptionByName("video");
3825 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003826
3827 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003828 std::unique_ptr<SessionDescription> answer =
3829 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003830 ASSERT_TRUE(answer.get() != NULL);
3831
3832 const cricket::TransportDescription* audio_answer_trans_desc =
3833 answer->GetTransportDescriptionByName("audio");
3834 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3835 const cricket::TransportDescription* video_answer_trans_desc =
3836 answer->GetTransportDescriptionByName("video");
3837 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003838}
3839
3840// Verifies if vad_enabled option is set to false, CN codecs are not present in
3841// offer or answer.
3842TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3843 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003844 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003845 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003846 ASSERT_TRUE(offer.get() != NULL);
3847 const ContentInfo* audio_content = offer->GetContentByName("audio");
3848 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3849
3850 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003851 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003852 ASSERT_TRUE(offer.get() != NULL);
3853 audio_content = offer->GetContentByName("audio");
3854 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003855 std::unique_ptr<SessionDescription> answer =
3856 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003857 ASSERT_TRUE(answer.get() != NULL);
3858 audio_content = answer->GetContentByName("audio");
3859 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3860}
deadbeef44f08192015-12-15 16:20:09 -08003861
zhihuang1c378ed2017-08-17 14:10:50 -07003862// Test that the generated MIDs match the existing offer.
3863TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003864 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003865 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3866 RtpTransceiverDirection::kRecvOnly, kActive,
3867 &opts);
3868 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3869 RtpTransceiverDirection::kRecvOnly, kActive,
3870 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003871 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3872 RtpTransceiverDirection::kSendRecv, kActive,
3873 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003874 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003875 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003876 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003877 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003878
deadbeef44f08192015-12-15 16:20:09 -08003879 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3880 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3881 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3882 ASSERT_TRUE(audio_content != nullptr);
3883 ASSERT_TRUE(video_content != nullptr);
3884 ASSERT_TRUE(data_content != nullptr);
3885 EXPECT_EQ("audio_modified", audio_content->name);
3886 EXPECT_EQ("video_modified", video_content->name);
3887 EXPECT_EQ("data_modified", data_content->name);
3888}
zhihuangcf5b37c2016-05-05 11:44:35 -07003889
zhihuang1c378ed2017-08-17 14:10:50 -07003890// The following tests verify that the unified plan SDP is supported.
3891// Test that we can create an offer with multiple media sections of same media
3892// type.
3893TEST_F(MediaSessionDescriptionFactoryTest,
3894 CreateOfferWithMultipleAVMediaSections) {
3895 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003896 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3897 RtpTransceiverDirection::kSendRecv, kActive,
3898 &opts);
3899 AttachSenderToMediaDescriptionOptions(
3900 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003901
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003902 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3903 RtpTransceiverDirection::kSendRecv, kActive,
3904 &opts);
3905 AttachSenderToMediaDescriptionOptions(
3906 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003907
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003908 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3909 RtpTransceiverDirection::kSendRecv, kActive,
3910 &opts);
3911 AttachSenderToMediaDescriptionOptions(
3912 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003913
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003914 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3915 RtpTransceiverDirection::kSendRecv, kActive,
3916 &opts);
3917 AttachSenderToMediaDescriptionOptions(
3918 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003919 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003920 ASSERT_TRUE(offer);
3921
3922 ASSERT_EQ(4u, offer->contents().size());
3923 EXPECT_FALSE(offer->contents()[0].rejected);
3924 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003925 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003926 ASSERT_EQ(1u, acd->streams().size());
3927 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003928 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003929
3930 EXPECT_FALSE(offer->contents()[1].rejected);
3931 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003932 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003933 ASSERT_EQ(1u, vcd->streams().size());
3934 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003935 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003936
3937 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003938 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003939 ASSERT_EQ(1u, acd->streams().size());
3940 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003941 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003942
3943 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003944 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003945 ASSERT_EQ(1u, vcd->streams().size());
3946 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003947 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003948}
3949
3950// Test that we can create an answer with multiple media sections of same media
3951// type.
3952TEST_F(MediaSessionDescriptionFactoryTest,
3953 CreateAnswerWithMultipleAVMediaSections) {
3954 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003955 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3956 RtpTransceiverDirection::kSendRecv, kActive,
3957 &opts);
3958 AttachSenderToMediaDescriptionOptions(
3959 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003960
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003961 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3962 RtpTransceiverDirection::kSendRecv, kActive,
3963 &opts);
3964 AttachSenderToMediaDescriptionOptions(
3965 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003966
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003967 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3968 RtpTransceiverDirection::kSendRecv, kActive,
3969 &opts);
3970 AttachSenderToMediaDescriptionOptions(
3971 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003972
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003973 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3974 RtpTransceiverDirection::kSendRecv, kActive,
3975 &opts);
3976 AttachSenderToMediaDescriptionOptions(
3977 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003978
Steve Anton6fe1fba2018-12-11 10:15:23 -08003979 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003980 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003981 std::unique_ptr<SessionDescription> answer =
3982 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003983
3984 ASSERT_EQ(4u, answer->contents().size());
3985 EXPECT_FALSE(answer->contents()[0].rejected);
3986 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003987 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003988 ASSERT_EQ(1u, acd->streams().size());
3989 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003990 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003991
3992 EXPECT_FALSE(answer->contents()[1].rejected);
3993 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003994 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003995 ASSERT_EQ(1u, vcd->streams().size());
3996 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003997 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003998
3999 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004000 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004001 ASSERT_EQ(1u, acd->streams().size());
4002 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004003 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004004
4005 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004006 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004007 ASSERT_EQ(1u, vcd->streams().size());
4008 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004009 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004010}
4011
4012// Test that the media section will be rejected in offer if the corresponding
4013// MediaDescriptionOptions is stopped by the offerer.
4014TEST_F(MediaSessionDescriptionFactoryTest,
4015 CreateOfferWithMediaSectionStoppedByOfferer) {
4016 // Create an offer with two audio sections and one of them is stopped.
4017 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004018 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4019 RtpTransceiverDirection::kSendRecv, kActive,
4020 &offer_opts);
4021 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4022 RtpTransceiverDirection::kInactive, kStopped,
4023 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004024 std::unique_ptr<SessionDescription> offer =
4025 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004026 ASSERT_TRUE(offer);
4027 ASSERT_EQ(2u, offer->contents().size());
4028 EXPECT_FALSE(offer->contents()[0].rejected);
4029 EXPECT_TRUE(offer->contents()[1].rejected);
4030}
4031
4032// Test that the media section will be rejected in answer if the corresponding
4033// MediaDescriptionOptions is stopped by the offerer.
4034TEST_F(MediaSessionDescriptionFactoryTest,
4035 CreateAnswerWithMediaSectionStoppedByOfferer) {
4036 // Create an offer with two audio sections and one of them is stopped.
4037 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004038 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4039 RtpTransceiverDirection::kSendRecv, kActive,
4040 &offer_opts);
4041 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4042 RtpTransceiverDirection::kInactive, kStopped,
4043 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004044 std::unique_ptr<SessionDescription> offer =
4045 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004046 ASSERT_TRUE(offer);
4047 ASSERT_EQ(2u, offer->contents().size());
4048 EXPECT_FALSE(offer->contents()[0].rejected);
4049 EXPECT_TRUE(offer->contents()[1].rejected);
4050
4051 // Create an answer based on the offer.
4052 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004053 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4054 RtpTransceiverDirection::kSendRecv, kActive,
4055 &answer_opts);
4056 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4057 RtpTransceiverDirection::kSendRecv, kActive,
4058 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004059 std::unique_ptr<SessionDescription> answer =
4060 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004061 ASSERT_EQ(2u, answer->contents().size());
4062 EXPECT_FALSE(answer->contents()[0].rejected);
4063 EXPECT_TRUE(answer->contents()[1].rejected);
4064}
4065
4066// Test that the media section will be rejected in answer if the corresponding
4067// MediaDescriptionOptions is stopped by the answerer.
4068TEST_F(MediaSessionDescriptionFactoryTest,
4069 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4070 // Create an offer with two audio sections.
4071 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004072 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4073 RtpTransceiverDirection::kSendRecv, kActive,
4074 &offer_opts);
4075 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4076 RtpTransceiverDirection::kSendRecv, kActive,
4077 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004078 std::unique_ptr<SessionDescription> offer =
4079 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004080 ASSERT_TRUE(offer);
4081 ASSERT_EQ(2u, offer->contents().size());
4082 ASSERT_FALSE(offer->contents()[0].rejected);
4083 ASSERT_FALSE(offer->contents()[1].rejected);
4084
4085 // The answerer rejects one of the audio sections.
4086 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004087 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4088 RtpTransceiverDirection::kSendRecv, kActive,
4089 &answer_opts);
4090 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4091 RtpTransceiverDirection::kInactive, kStopped,
4092 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004093 std::unique_ptr<SessionDescription> answer =
4094 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004095 ASSERT_EQ(2u, answer->contents().size());
4096 EXPECT_FALSE(answer->contents()[0].rejected);
4097 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004098
4099 // The TransportInfo of the rejected m= section is expected to be added in the
4100 // answer.
4101 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004102}
4103
4104// Test the generated media sections has the same order of the
4105// corresponding MediaDescriptionOptions.
4106TEST_F(MediaSessionDescriptionFactoryTest,
4107 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4108 MediaSessionOptions opts;
4109 // This tests put video section first because normally audio comes first by
4110 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004111 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4112 RtpTransceiverDirection::kSendRecv, kActive,
4113 &opts);
4114 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4115 RtpTransceiverDirection::kSendRecv, kActive,
4116 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004117 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004118
4119 ASSERT_TRUE(offer);
4120 ASSERT_EQ(2u, offer->contents().size());
4121 EXPECT_EQ("video", offer->contents()[0].name);
4122 EXPECT_EQ("audio", offer->contents()[1].name);
4123}
4124
4125// Test that different media sections using the same codec have same payload
4126// type.
4127TEST_F(MediaSessionDescriptionFactoryTest,
4128 PayloadTypesSharedByMediaSectionsOfSameType) {
4129 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004130 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4131 RtpTransceiverDirection::kSendRecv, kActive,
4132 &opts);
4133 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4134 RtpTransceiverDirection::kSendRecv, kActive,
4135 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004136 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004137 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004138 ASSERT_TRUE(offer);
4139 ASSERT_EQ(2u, offer->contents().size());
4140 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004141 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004142 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004143 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004144 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4145 ASSERT_EQ(2u, vcd1->codecs().size());
4146 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4147 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4148 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4149 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4150
4151 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004152 std::unique_ptr<SessionDescription> answer =
4153 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004154 ASSERT_TRUE(answer);
4155 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004156 vcd1 = answer->contents()[0].media_description()->as_video();
4157 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004158 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4159 ASSERT_EQ(1u, vcd1->codecs().size());
4160 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4161 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4162}
4163
4164// Test that the codec preference order per media section is respected in
4165// subsequent offer.
4166TEST_F(MediaSessionDescriptionFactoryTest,
4167 CreateOfferRespectsCodecPreferenceOrder) {
4168 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004169 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4170 RtpTransceiverDirection::kSendRecv, kActive,
4171 &opts);
4172 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4173 RtpTransceiverDirection::kSendRecv, kActive,
4174 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004175 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004176 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004177 ASSERT_TRUE(offer);
4178 ASSERT_EQ(2u, offer->contents().size());
4179 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004180 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004181 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004182 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004183 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4184 EXPECT_EQ(video_codecs, vcd1->codecs());
4185 EXPECT_EQ(video_codecs, vcd2->codecs());
4186
4187 // Change the codec preference of the first video section and create a
4188 // follow-up offer.
4189 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4190 vcd1->set_codecs(video_codecs_reverse);
4191 std::unique_ptr<SessionDescription> updated_offer(
4192 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004193 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4194 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004195 // The video codec preference order should be respected.
4196 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4197 EXPECT_EQ(video_codecs, vcd2->codecs());
4198}
4199
4200// Test that the codec preference order per media section is respected in
4201// the answer.
4202TEST_F(MediaSessionDescriptionFactoryTest,
4203 CreateAnswerRespectsCodecPreferenceOrder) {
4204 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004205 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4206 RtpTransceiverDirection::kSendRecv, kActive,
4207 &opts);
4208 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4209 RtpTransceiverDirection::kSendRecv, kActive,
4210 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004211 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004212 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004213 ASSERT_TRUE(offer);
4214 ASSERT_EQ(2u, offer->contents().size());
4215 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004216 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004217 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004218 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004219 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4220 EXPECT_EQ(video_codecs, vcd1->codecs());
4221 EXPECT_EQ(video_codecs, vcd2->codecs());
4222
4223 // Change the codec preference of the first video section and create an
4224 // answer.
4225 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4226 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004227 std::unique_ptr<SessionDescription> answer =
4228 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004229 vcd1 = answer->contents()[0].media_description()->as_video();
4230 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004231 // The video codec preference order should be respected.
4232 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4233 EXPECT_EQ(video_codecs, vcd2->codecs());
4234}
4235
Zhi Huang6f367472017-11-22 13:20:02 -08004236// Test that when creating an answer, the codecs use local parameters instead of
4237// the remote ones.
4238TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4239 const std::string audio_param_name = "audio_param";
4240 const std::string audio_value1 = "audio_v1";
4241 const std::string audio_value2 = "audio_v2";
4242 const std::string video_param_name = "video_param";
4243 const std::string video_value1 = "video_v1";
4244 const std::string video_value2 = "video_v2";
4245
4246 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4247 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4248 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4249 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4250
4251 // Set the parameters for codecs.
4252 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4253 video_codecs1[0].SetParam(video_param_name, video_value1);
4254 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4255 video_codecs2[0].SetParam(video_param_name, video_value2);
4256
4257 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004258 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004259 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004260 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004261
4262 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004263 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4264 RtpTransceiverDirection::kSendRecv, kActive,
4265 &opts);
4266 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4267 RtpTransceiverDirection::kSendRecv, kActive,
4268 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004269
Steve Anton6fe1fba2018-12-11 10:15:23 -08004270 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004271 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004272 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4273 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004274 std::string value;
4275 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4276 EXPECT_EQ(audio_value1, value);
4277 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4278 EXPECT_EQ(video_value1, value);
4279
Steve Anton6fe1fba2018-12-11 10:15:23 -08004280 std::unique_ptr<SessionDescription> answer =
4281 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004282 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004283 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4284 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004285 // Use the parameters from the local codecs.
4286 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4287 EXPECT_EQ(audio_value2, value);
4288 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4289 EXPECT_EQ(video_value2, value);
4290}
4291
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004292// Test that matching packetization-mode is part of the criteria for matching
4293// H264 codecs (in addition to profile-level-id). Previously, this was not the
4294// case, so the first H264 codec with the same profile-level-id would match and
4295// the payload type in the answer would be incorrect.
4296// This is a regression test for bugs.webrtc.org/8808
4297TEST_F(MediaSessionDescriptionFactoryTest,
4298 H264MatchCriteriaIncludesPacketizationMode) {
4299 // Create two H264 codecs with the same profile level ID and different
4300 // packetization modes.
4301 VideoCodec h264_pm0(96, "H264");
4302 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4303 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4304 VideoCodec h264_pm1(97, "H264");
4305 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4306 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4307
4308 // Offerer will send both codecs, answerer should choose the one with matching
4309 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004310 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4311 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004312
4313 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004314 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4315 RtpTransceiverDirection::kSendRecv, kActive,
4316 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004317
Steve Anton6fe1fba2018-12-11 10:15:23 -08004318 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004319 ASSERT_TRUE(offer);
4320
Steve Anton6fe1fba2018-12-11 10:15:23 -08004321 std::unique_ptr<SessionDescription> answer =
4322 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004323 ASSERT_TRUE(answer);
4324
4325 // Answer should have one negotiated codec with packetization-mode=1 using the
4326 // offered payload type.
4327 ASSERT_EQ(1u, answer->contents().size());
4328 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4329 ASSERT_EQ(1u, answer_vcd->codecs().size());
4330 auto answer_codec = answer_vcd->codecs()[0];
4331 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4332}
4333
zhihuangcf5b37c2016-05-05 11:44:35 -07004334class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4335 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004336 MediaProtocolTest()
Jonas Orelanded99dae2022-03-09 09:28:10 +01004337 : tdf1_(field_trials_),
4338 tdf2_(field_trials_),
4339 f1_(&tdf1_, &ssrc_generator1),
4340 f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004341 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4342 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004343 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4344 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -07004345 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4346 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004347 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4348 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004349 f1_.set_secure(SEC_ENABLED);
4350 f2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004351 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004352 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004353 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004354 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004355 tdf1_.set_secure(SEC_ENABLED);
4356 tdf2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004357 }
4358
4359 protected:
Jonas Orelanded99dae2022-03-09 09:28:10 +01004360 webrtc::test::ScopedKeyValueConfig field_trials_;
zhihuangcf5b37c2016-05-05 11:44:35 -07004361 TransportDescriptionFactory tdf1_;
4362 TransportDescriptionFactory tdf2_;
Jonas Orelanded99dae2022-03-09 09:28:10 +01004363 MediaSessionDescriptionFactory f1_;
4364 MediaSessionDescriptionFactory f2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004365 UniqueRandomIdGenerator ssrc_generator1;
4366 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004367};
4368
4369TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4370 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004371 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004372 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004373 ASSERT_TRUE(offer.get() != nullptr);
4374 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004375 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004376 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004377 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004378 std::unique_ptr<SessionDescription> answer =
4379 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004380 const ContentInfo* ac = answer->GetContentByName("audio");
4381 const ContentInfo* vc = answer->GetContentByName("video");
4382 ASSERT_TRUE(ac != nullptr);
4383 ASSERT_TRUE(vc != nullptr);
4384 EXPECT_FALSE(ac->rejected); // the offer is accepted
4385 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004386 const AudioContentDescription* acd = ac->media_description()->as_audio();
4387 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004388 EXPECT_EQ(GetParam(), acd->protocol());
4389 EXPECT_EQ(GetParam(), vcd->protocol());
4390}
4391
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004392INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4393 MediaProtocolTest,
4394 ::testing::ValuesIn(kMediaProtocols));
4395INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4396 MediaProtocolTest,
4397 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004398
4399TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004400 webrtc::test::ScopedKeyValueConfig field_trials;
4401 TransportDescriptionFactory tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004402 UniqueRandomIdGenerator ssrc_generator;
4403 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004404 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4405 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4406
4407 // The merged list of codecs should contain any send codecs that are also
Niels Möllerbe74b802022-03-18 14:10:15 +01004408 // nominally in the receive codecs list. Payload types should be picked from
ossu075af922016-06-14 03:29:38 -07004409 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4410 // (set to 1). This equals what happens when the send codecs are used in an
4411 // offer and the receive codecs are used in the following answer.
4412 const std::vector<AudioCodec> sendrecv_codecs =
4413 MAKE_VECTOR(kAudioCodecsAnswer);
4414 const std::vector<AudioCodec> no_codecs;
4415
4416 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4417 << "Please don't change shared test data!";
4418 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4419 << "Please don't change shared test data!";
4420 // Alter iLBC send codec to have zero channels, to test that that is handled
4421 // properly.
4422 send_codecs[1].channels = 0;
4423
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004424 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004425 // are handled properly.
4426 recv_codecs[2].name = "ilbc";
4427
4428 // Test proper merge
4429 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004430 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4431 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4432 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004433
4434 // Test empty send codecs list
4435 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004436 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4437 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4438 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004439
4440 // Test empty recv codecs list
4441 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004442 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4443 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4444 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004445
4446 // Test all empty codec lists
4447 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004448 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4449 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4450 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004451}
4452
4453namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004454// Compare the two vectors of codecs ignoring the payload type.
4455template <class Codec>
4456bool CodecsMatch(const std::vector<Codec>& codecs1,
Jonas Oreland4476b822022-03-10 15:21:28 +01004457 const std::vector<Codec>& codecs2,
4458 const webrtc::WebRtcKeyValueConfig* field_trials) {
zhihuang1c378ed2017-08-17 14:10:50 -07004459 if (codecs1.size() != codecs2.size()) {
4460 return false;
4461 }
4462
4463 for (size_t i = 0; i < codecs1.size(); ++i) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004464 if (!codecs1[i].Matches(codecs2[i], field_trials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07004465 return false;
4466 }
4467 }
4468 return true;
4469}
4470
Steve Anton4e70a722017-11-28 14:57:10 -08004471void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004472 webrtc::test::ScopedKeyValueConfig field_trials;
4473 TransportDescriptionFactory tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004474 UniqueRandomIdGenerator ssrc_generator;
4475 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004476 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4477 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4478 const std::vector<AudioCodec> sendrecv_codecs =
4479 MAKE_VECTOR(kAudioCodecsAnswer);
4480 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004481
4482 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004483 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4484 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004485
Steve Anton4e70a722017-11-28 14:57:10 -08004486 if (direction == RtpTransceiverDirection::kSendRecv ||
4487 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004488 AttachSenderToMediaDescriptionOptions(
4489 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004490 }
ossu075af922016-06-14 03:29:38 -07004491
Steve Anton6fe1fba2018-12-11 10:15:23 -08004492 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004493 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004494 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004495
4496 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004497 // that the codecs put in are right. This happens when we neither want to
4498 // send nor receive audio. The checks are still in place if at some point
4499 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004500 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004501 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004502 // sendrecv and inactive should both present lists as if the channel was
4503 // to be used for sending and receiving. Inactive essentially means it
4504 // might eventually be used anything, but we don't know more at this
4505 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004506 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004507 EXPECT_TRUE(
4508 CodecsMatch<AudioCodec>(send_codecs, acd->codecs(), &field_trials));
Steve Anton4e70a722017-11-28 14:57:10 -08004509 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004510 EXPECT_TRUE(
4511 CodecsMatch<AudioCodec>(recv_codecs, acd->codecs(), &field_trials));
ossu075af922016-06-14 03:29:38 -07004512 } else {
Jonas Oreland4476b822022-03-10 15:21:28 +01004513 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs(),
4514 &field_trials));
ossu075af922016-06-14 03:29:38 -07004515 }
4516 }
4517}
4518
4519static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004520 AudioCodec(0, "codec0", 16000, -1, 1),
4521 AudioCodec(1, "codec1", 8000, 13300, 1),
4522 AudioCodec(2, "codec2", 8000, 64000, 1),
4523 AudioCodec(3, "codec3", 8000, 64000, 1),
4524 AudioCodec(4, "codec4", 8000, 0, 2),
4525 AudioCodec(5, "codec5", 32000, 0, 1),
4526 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004527
zhihuang1c378ed2017-08-17 14:10:50 -07004528/* The codecs groups below are chosen as per the matrix below. The objective
4529 * is to have different sets of codecs in the inputs, to get unique sets of
4530 * codecs after negotiation, depending on offer and answer communication
4531 * directions. One-way directions in the offer should either result in the
4532 * opposite direction in the answer, or an inactive answer. Regardless, the
4533 * choice of codecs should be as if the answer contained the opposite
4534 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004535 *
4536 * | Offer | Answer | Result
4537 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4538 * 0 | x - - | - x - | x - - - -
4539 * 1 | x x x | - x - | x - - x -
4540 * 2 | - x - | x - - | - x - - -
4541 * 3 | x x x | x - - | - x x - -
4542 * 4 | - x - | x x x | - x - - -
4543 * 5 | x - - | x x x | x - - - -
4544 * 6 | x x x | x x x | x x x x x
4545 */
4546// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004547static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4548static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004549// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4550// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004551static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4552static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004553// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004554static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4555static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4556static const int kResultSendrecv_SendCodecs[] = {3, 6};
4557static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4558static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004559
4560template <typename T, int IDXS>
4561std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4562 std::vector<T> out;
4563 out.reserve(IDXS);
4564 for (int idx : indices)
4565 out.push_back(array[idx]);
4566
4567 return out;
4568}
4569
Steve Anton4e70a722017-11-28 14:57:10 -08004570void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4571 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004572 bool add_legacy_stream) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004573 webrtc::test::ScopedKeyValueConfig field_trials;
4574 TransportDescriptionFactory offer_tdf(field_trials);
4575 TransportDescriptionFactory answer_tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004576 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4577 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4578 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
Jonas Orelanded99dae2022-03-09 09:28:10 +01004579
ossu075af922016-06-14 03:29:38 -07004580 offer_factory.set_audio_codecs(
4581 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4582 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4583 answer_factory.set_audio_codecs(
4584 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4585 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4586
ossu075af922016-06-14 03:29:38 -07004587 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004588 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4589 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004590
Steve Anton4e70a722017-11-28 14:57:10 -08004591 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004592 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4593 kAudioTrack1, {kMediaStream1}, 1,
4594 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004595 }
4596
Steve Anton6fe1fba2018-12-11 10:15:23 -08004597 std::unique_ptr<SessionDescription> offer =
4598 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004599 ASSERT_TRUE(offer.get() != NULL);
4600
4601 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004602 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4603 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004604
Steve Anton4e70a722017-11-28 14:57:10 -08004605 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004606 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4607 kAudioTrack1, {kMediaStream1}, 1,
4608 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004609 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004610 std::unique_ptr<SessionDescription> answer =
4611 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004612 const ContentInfo* ac = answer->GetContentByName("audio");
4613
zhihuang1c378ed2017-08-17 14:10:50 -07004614 // If the factory didn't add any audio content to the answer, we cannot
4615 // check that the codecs put in are right. This happens when we neither want
4616 // to send nor receive audio. The checks are still in place if at some point
4617 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004618 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004619 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4620 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004621
ossu075af922016-06-14 03:29:38 -07004622 std::vector<AudioCodec> target_codecs;
4623 // For offers with sendrecv or inactive, we should never reply with more
4624 // codecs than offered, with these codec sets.
4625 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004626 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004627 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4628 kResultSendrecv_SendrecvCodecs);
4629 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004630 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004631 target_codecs =
4632 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004633 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004634 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004635 target_codecs =
4636 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004637 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004638 case RtpTransceiverDirection::kSendRecv:
4639 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004640 target_codecs =
4641 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004642 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004643 target_codecs =
4644 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004645 } else {
4646 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4647 kResultSendrecv_SendrecvCodecs);
4648 }
4649 break;
Harald Alvestrand6060df52020-08-11 09:54:02 +02004650 case RtpTransceiverDirection::kStopped:
4651 // This does not happen in any current test.
Artem Titovd3251962021-11-15 16:57:07 +01004652 RTC_DCHECK_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004653 }
4654
zhihuang1c378ed2017-08-17 14:10:50 -07004655 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004656 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004657 bool first = true;
4658 os << "{";
4659 for (const auto& c : codecs) {
4660 os << (first ? " " : ", ") << c.id;
4661 first = false;
4662 }
4663 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004664 return os.Release();
ossu075af922016-06-14 03:29:38 -07004665 };
4666
4667 EXPECT_TRUE(acd->codecs() == target_codecs)
4668 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004669 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4670 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004671 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004672 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4673 << "; got: "
4674 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004675 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004676 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004677 << "Only inactive offers are allowed to not generate any audio "
4678 "content";
ossu075af922016-06-14 03:29:38 -07004679 }
4680}
brandtr03d5fb12016-11-22 03:37:59 -08004681
4682} // namespace
ossu075af922016-06-14 03:29:38 -07004683
4684class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004685 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004686
4687TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004688 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004689}
4690
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004691INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4692 AudioCodecsOfferTest,
4693 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4694 RtpTransceiverDirection::kRecvOnly,
4695 RtpTransceiverDirection::kSendRecv,
4696 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004697
4698class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004699 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4700 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004701 bool>> {};
ossu075af922016-06-14 03:29:38 -07004702
4703TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004704 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4705 ::testing::get<1>(GetParam()),
4706 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004707}
4708
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004709INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004710 MediaSessionDescriptionFactoryTest,
4711 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004712 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4713 RtpTransceiverDirection::kRecvOnly,
4714 RtpTransceiverDirection::kSendRecv,
4715 RtpTransceiverDirection::kInactive),
4716 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4717 RtpTransceiverDirection::kRecvOnly,
4718 RtpTransceiverDirection::kSendRecv,
4719 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004720 ::testing::Bool()));