blob: 8f38f6a1b4912b70356f25a14775e99be1b15ac7 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/media_session.h"
12
Harald Alvestrandc24a2182022-02-23 13:44:59 +000013#include <stddef.h>
14
Amit Hilbuch77938e62018-12-21 09:23:38 -080015#include <algorithm>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000016#include <cstdint>
17#include <map>
kwiberg31022942016-03-11 14:18:21 -080018#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000019#include <string>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000020#include <tuple>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000021#include <vector>
22
Steve Anton64b626b2019-01-28 17:25:26 -080023#include "absl/algorithm/container.h"
Mirko Bonadei57cabed2020-04-01 12:03:11 +020024#include "absl/strings/match.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000025#include "absl/strings/string_view.h"
26#include "api/candidate.h"
27#include "api/crypto_params.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "media/base/codec.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000029#include "media/base/media_constants.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020031#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "p2p/base/p2p_constants.h"
33#include "p2p/base/transport_description.h"
34#include "p2p/base/transport_info.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000035#include "pc/media_protocol_names.h"
Steve Anton10542f22019-01-11 09:11:00 -080036#include "pc/rtp_media_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000037#include "rtc_base/arraysize.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080039#include "rtc_base/fake_ssl_identity.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000040#include "rtc_base/rtc_certificate.h"
41#include "rtc_base/ssl_identity.h"
42#include "rtc_base/ssl_stream_adapter.h"
43#include "rtc_base/string_encode.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020044#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080045#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080046#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000047#include "test/gtest.h"
Jonas Orelanded99dae2022-03-09 09:28:10 +010048#include "test/scoped_key_value_config.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049
Harald Alvestrand0d018412021-11-04 13:52:31 +000050#define ASSERT_CRYPTO(cd, s, cs) \
51 ASSERT_EQ(s, cd->cryptos().size()); \
52 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
53
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054typedef std::vector<cricket::Candidate> Candidates;
55
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080056using cricket::AudioCodec;
57using cricket::AudioContentDescription;
58using cricket::ContentInfo;
Harald Alvestrand0d018412021-11-04 13:52:31 +000059using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080060using cricket::GetFirstAudioContent;
61using cricket::GetFirstAudioContentDescription;
62using cricket::GetFirstDataContent;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080063using cricket::GetFirstVideoContent;
64using cricket::GetFirstVideoContentDescription;
65using cricket::kAutoBandwidth;
66using cricket::MEDIA_TYPE_AUDIO;
67using cricket::MEDIA_TYPE_DATA;
68using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070070using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080071using cricket::MediaProtocolType;
72using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073using cricket::MediaSessionOptions;
74using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080075using cricket::RidDescription;
76using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020077using cricket::SctpDataContentDescription;
Harald Alvestrand0d018412021-11-04 13:52:31 +000078using cricket::SEC_DISABLED;
79using cricket::SEC_ENABLED;
80using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080082using cricket::SimulcastDescription;
83using cricket::SimulcastLayer;
84using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085using cricket::SsrcGroup;
86using cricket::StreamParams;
87using cricket::StreamParamsVec;
88using cricket::TransportDescription;
89using cricket::TransportDescriptionFactory;
90using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080092using cricket::VideoContentDescription;
Mirko Bonadei7750d802021-07-26 17:27:42 +020093using rtc::kCsAeadAes128Gcm;
94using rtc::kCsAeadAes256Gcm;
95using rtc::kCsAesCm128HmacSha1_32;
96using rtc::kCsAesCm128HmacSha1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080097using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020098using ::testing::Contains;
99using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +0100100using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200101using ::testing::ElementsAreArray;
102using ::testing::Eq;
103using ::testing::Field;
104using ::testing::IsEmpty;
105using ::testing::IsFalse;
106using ::testing::Ne;
107using ::testing::Not;
108using ::testing::Pointwise;
109using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700110using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800111using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
113static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700114 AudioCodec(103, "ISAC", 16000, -1, 1),
115 AudioCodec(102, "iLBC", 8000, 13300, 1),
116 AudioCodec(0, "PCMU", 8000, 64000, 1),
117 AudioCodec(8, "PCMA", 8000, 64000, 1),
118 AudioCodec(117, "red", 8000, 0, 1),
119 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120
121static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200122 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700123 AudioCodec(0, "PCMU", 8000, 64000, 1),
124 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125};
126
127static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700128 AudioCodec(102, "iLBC", 8000, 13300, 1),
129 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130};
131
perkj26752742016-10-24 01:21:16 -0700132static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
133 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
zhihuang1c378ed2017-08-17 14:10:50 -0700135static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
136 VideoCodec(96, "H264-SVC")};
137
perkj26752742016-10-24 01:21:16 -0700138static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
139 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140
perkj26752742016-10-24 01:21:16 -0700141static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142
isheriff6f8d6862016-05-26 11:24:55 -0700143static const RtpExtension kAudioRtpExtension1[] = {
144 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
145 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146};
147
jbauch5869f502017-06-29 12:31:36 -0700148static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
149 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
150 RtpExtension("http://google.com/testing/audio_something", 10),
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200152 RtpExtension("http://google.com/testing/audio_something", 11, true),
jbauch5869f502017-06-29 12:31:36 -0700153};
154
isheriff6f8d6862016-05-26 11:24:55 -0700155static const RtpExtension kAudioRtpExtension2[] = {
156 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
157 RtpExtension("http://google.com/testing/audio_something_else", 8),
158 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159};
160
isheriff6f8d6862016-05-26 11:24:55 -0700161static const RtpExtension kAudioRtpExtension3[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700164};
165
jbauch5869f502017-06-29 12:31:36 -0700166static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
167 RtpExtension("http://google.com/testing/audio_something", 2),
168 // Use RTP extension that supports encryption.
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
170};
171
172static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
173 RtpExtension("http://google.com/testing/audio_something", 2),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200175 RtpExtension("http://google.com/testing/audio_something", 14, true),
176 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
177};
178
179static const RtpExtension kVideoRtpExtension3ForEncryptionOffer[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
182 RtpExtension("http://google.com/testing/video_something", 12, true),
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
jbauch5869f502017-06-29 12:31:36 -0700184};
185
isheriff6f8d6862016-05-26 11:24:55 -0700186static const RtpExtension kAudioRtpExtensionAnswer[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188};
189
jbauch5869f502017-06-29 12:31:36 -0700190static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
192};
193
isheriff6f8d6862016-05-26 11:24:55 -0700194static const RtpExtension kVideoRtpExtension1[] = {
195 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
196 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197};
198
jbauch5869f502017-06-29 12:31:36 -0700199static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
200 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
201 RtpExtension("http://google.com/testing/video_something", 13),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200202 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
203 RtpExtension("http://google.com/testing/video_something", 7, true),
jbauch5869f502017-06-29 12:31:36 -0700204};
205
isheriff6f8d6862016-05-26 11:24:55 -0700206static const RtpExtension kVideoRtpExtension2[] = {
207 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
208 RtpExtension("http://google.com/testing/video_something_else", 14),
209 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210};
211
isheriff6f8d6862016-05-26 11:24:55 -0700212static const RtpExtension kVideoRtpExtension3[] = {
213 RtpExtension("http://google.com/testing/video_something", 4),
214 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700215};
216
jbauch5869f502017-06-29 12:31:36 -0700217static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
218 RtpExtension("http://google.com/testing/video_something", 4),
219 // Use RTP extension that supports encryption.
220 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
221};
222
isheriff6f8d6862016-05-26 11:24:55 -0700223static const RtpExtension kVideoRtpExtensionAnswer[] = {
224 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225};
226
jbauch5869f502017-06-29 12:31:36 -0700227static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200228 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
jbauch5869f502017-06-29 12:31:36 -0700229};
230
Johannes Kronce8e8672019-02-22 13:06:44 +0100231static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
232 RtpExtension("http://www.ietf.org/id/"
233 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
234 1),
235};
236
237static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
238 RtpExtension("http://www.ietf.org/id/"
239 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
240 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100241 RtpExtension(
242 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
243 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100244};
245
246static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100247 RtpExtension(
248 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
249 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100250};
251
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100252static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
253 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
254 "generic-frame-descriptor-00",
255 3),
256};
257
Peter Boström0c4e06b2015-10-07 12:23:21 +0200258static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
259static const uint32_t kSimSsrc[] = {10, 20, 30};
260static const uint32_t kFec1Ssrc[] = {10, 11};
261static const uint32_t kFec2Ssrc[] = {20, 21};
262static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263
264static const char kMediaStream1[] = "stream_1";
265static const char kMediaStream2[] = "stream_2";
266static const char kVideoTrack1[] = "video_1";
267static const char kVideoTrack2[] = "video_2";
268static const char kAudioTrack1[] = "audio_1";
269static const char kAudioTrack2[] = "audio_2";
270static const char kAudioTrack3[] = "audio_3";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271
zhihuangcf5b37c2016-05-05 11:44:35 -0700272static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
273 "RTP/SAVPF"};
274static const char* kMediaProtocolsDtls[] = {
275 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
276 "UDP/TLS/RTP/SAVP"};
277
Harald Alvestrand0d018412021-11-04 13:52:31 +0000278// SRTP cipher name negotiated by the tests. This must be updated if the
279// default changes.
280static const char* kDefaultSrtpCryptoSuite = kCsAesCm128HmacSha1_80;
281static const char* kDefaultSrtpCryptoSuiteGcm = kCsAeadAes256Gcm;
282
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800283// These constants are used to make the code using "AddMediaDescriptionOptions"
284// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700285static constexpr bool kStopped = true;
286static constexpr bool kActive = false;
287
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000288static bool IsMediaContentOfType(const ContentInfo* content,
289 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800290 RTC_DCHECK(content);
291 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000292}
293
Steve Anton4e70a722017-11-28 14:57:10 -0800294static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800295 RTC_DCHECK(content);
296 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000297}
298
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000299static void AddRtxCodec(const VideoCodec& rtx_codec,
300 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800301 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000302 codecs->push_back(rtx_codec);
303}
304
305template <class T>
306static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
307 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100308 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000309 for (const auto& codec : codecs) {
310 codec_names.push_back(codec.name);
311 }
312 return codec_names;
313}
314
zhihuang1c378ed2017-08-17 14:10:50 -0700315// This is used for test only. MIDs are not the identification of the
316// MediaDescriptionOptions since some end points may not support MID and the SDP
317// may not contain 'mid'.
318std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
319 const std::string& mid,
320 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800321 return absl::c_find_if(
322 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700323 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
324}
325
326std::vector<MediaDescriptionOptions>::const_iterator
327FindFirstMediaDescriptionByMid(const std::string& mid,
328 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800329 return absl::c_find_if(
330 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700331 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700332}
333
Artem Titov880fa812021-07-30 22:30:23 +0200334// Add a media section to the `session_options`.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800335static void AddMediaDescriptionOptions(MediaType type,
336 const std::string& mid,
337 RtpTransceiverDirection direction,
338 bool stopped,
339 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800340 opts->media_description_options.push_back(
341 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700342}
343
Steve Anton4e70a722017-11-28 14:57:10 -0800344static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700345 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800346 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
347 opts);
348 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
349 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700350}
351
Florent Castelli516e2842021-04-19 15:29:50 +0200352static void AddDataSection(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700353 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800354 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700355}
356
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800357static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700358 const std::string& mid,
359 MediaType type,
360 const std::string& track_id,
361 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800362 const std::vector<RidDescription>& rids,
363 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700364 int num_sim_layer,
365 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700366 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
367 switch (type) {
368 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700369 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700370 break;
371 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800372 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
373 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700374 break;
zhihuang1c378ed2017-08-17 14:10:50 -0700375 default:
Artem Titovd3251962021-11-15 16:57:07 +0100376 RTC_DCHECK_NOTREACHED();
zhihuang1c378ed2017-08-17 14:10:50 -0700377 }
378}
379
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800380static void AttachSenderToMediaDescriptionOptions(
381 const std::string& mid,
382 MediaType type,
383 const std::string& track_id,
384 const std::vector<std::string>& stream_ids,
385 int num_sim_layer,
386 MediaSessionOptions* session_options) {
387 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
388 SimulcastLayerList(), num_sim_layer,
389 session_options);
390}
391
zhihuang1c378ed2017-08-17 14:10:50 -0700392static void DetachSenderFromMediaSection(const std::string& mid,
393 const std::string& track_id,
394 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700395 std::vector<cricket::SenderOptions>& sender_options_list =
396 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
397 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800398 absl::c_find_if(sender_options_list,
399 [track_id](const cricket::SenderOptions& sender_options) {
400 return sender_options.track_id == track_id;
401 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700402 RTC_DCHECK(sender_it != sender_options_list.end());
403 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700404}
405
406// Helper function used to create a default MediaSessionOptions for Plan B SDP.
407// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
408static MediaSessionOptions CreatePlanBMediaSessionOptions() {
409 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800410 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
411 RtpTransceiverDirection::kRecvOnly, kActive,
412 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700413 return session_options;
414}
415
Harald Alvestrand0d018412021-11-04 13:52:31 +0000416// prefers GCM SDES crypto suites by removing non-GCM defaults.
417void PreferGcmCryptoParameters(CryptoParamsVec* cryptos) {
418 cryptos->erase(
419 std::remove_if(cryptos->begin(), cryptos->end(),
420 [](const cricket::CryptoParams& crypto) {
421 return crypto.cipher_suite != kCsAeadAes256Gcm &&
422 crypto.cipher_suite != kCsAeadAes128Gcm;
423 }),
424 cryptos->end());
425}
426
zhihuang1c378ed2017-08-17 14:10:50 -0700427// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
428// was designed for Plan B SDP, where only one audio "m=" section and one video
429// "m=" section could be generated, and ordering couldn't be controlled. Many of
430// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200431class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800433 MediaSessionDescriptionFactoryTest()
Jonas Orelanded99dae2022-03-09 09:28:10 +0100434 : tdf1_(field_trials),
435 tdf2_(field_trials),
436 f1_(&tdf1_, &ssrc_generator1),
437 f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700438 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
439 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200440 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
441 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -0700442 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
443 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200444 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
445 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000446 tdf1_.set_certificate(rtc::RTCCertificate::Create(
447 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
448 tdf2_.set_certificate(rtc::RTCCertificate::Create(
449 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 }
451
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000452 // Create a video StreamParamsVec object with:
453 // - one video stream with 3 simulcast streams and FEC,
454 StreamParamsVec CreateComplexVideoStreamParamsVec() {
455 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
456 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
457 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
458 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
459
460 std::vector<SsrcGroup> ssrc_groups;
461 ssrc_groups.push_back(sim_group);
462 ssrc_groups.push_back(fec_group1);
463 ssrc_groups.push_back(fec_group2);
464 ssrc_groups.push_back(fec_group3);
465
466 StreamParams simulcast_params;
467 simulcast_params.id = kVideoTrack1;
468 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
469 simulcast_params.ssrc_groups = ssrc_groups;
470 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800471 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000472
473 StreamParamsVec video_streams;
474 video_streams.push_back(simulcast_params);
475
476 return video_streams;
477 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000478
Harald Alvestrand0d018412021-11-04 13:52:31 +0000479 bool CompareCryptoParams(const CryptoParamsVec& c1,
480 const CryptoParamsVec& c2) {
481 if (c1.size() != c2.size())
482 return false;
483 for (size_t i = 0; i < c1.size(); ++i)
484 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
485 c1[i].key_params != c2[i].key_params ||
486 c1[i].session_params != c2[i].session_params)
487 return false;
488 return true;
489 }
490
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700491 // Returns true if the transport info contains "renomination" as an
492 // ICE option.
493 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800494 return absl::c_linear_search(transport_info->description.transport_options,
495 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700496 }
497
zhihuang1c378ed2017-08-17 14:10:50 -0700498 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700499 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 bool has_current_desc) {
501 const std::string current_audio_ufrag = "current_audio_ufrag";
502 const std::string current_audio_pwd = "current_audio_pwd";
503 const std::string current_video_ufrag = "current_video_ufrag";
504 const std::string current_video_pwd = "current_video_pwd";
505 const std::string current_data_ufrag = "current_data_ufrag";
506 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800507 std::unique_ptr<SessionDescription> current_desc;
508 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200510 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800511 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200512 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800513 TransportDescription(current_audio_ufrag, current_audio_pwd)));
514 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200515 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800516 TransportDescription(current_video_ufrag, current_video_pwd)));
517 current_desc->AddTransportInfo(TransportInfo(
518 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 }
520 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800521 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522 } else {
kwiberg31022942016-03-11 14:18:21 -0800523 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800524 offer = f1_.CreateOffer(options, NULL);
525 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 }
527 ASSERT_TRUE(desc.get() != NULL);
528 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000529 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 EXPECT_TRUE(ti_audio != NULL);
531 if (has_current_desc) {
532 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
533 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
534 } else {
535 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
536 ti_audio->description.ice_ufrag.size());
537 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
538 ti_audio->description.ice_pwd.size());
539 }
zhihuang1c378ed2017-08-17 14:10:50 -0700540 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700541 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700542 EXPECT_EQ(
543 media_desc_options_it->transport_options.enable_ice_renomination,
544 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 } else {
546 EXPECT_TRUE(ti_audio == NULL);
547 }
548 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000549 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700551 auto media_desc_options_it =
552 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 if (options.bundle_enabled) {
554 EXPECT_EQ(ti_audio->description.ice_ufrag,
555 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200556 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 } else {
558 if (has_current_desc) {
559 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
560 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
561 } else {
562 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
563 ti_video->description.ice_ufrag.size());
564 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
565 ti_video->description.ice_pwd.size());
566 }
567 }
zhihuang1c378ed2017-08-17 14:10:50 -0700568 EXPECT_EQ(
569 media_desc_options_it->transport_options.enable_ice_renomination,
570 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 } else {
572 EXPECT_TRUE(ti_video == NULL);
573 }
574 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
575 if (options.has_data()) {
576 EXPECT_TRUE(ti_data != NULL);
577 if (options.bundle_enabled) {
578 EXPECT_EQ(ti_audio->description.ice_ufrag,
579 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200580 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 } else {
582 if (has_current_desc) {
583 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
584 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
585 } else {
586 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
587 ti_data->description.ice_ufrag.size());
588 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
589 ti_data->description.ice_pwd.size());
590 }
591 }
zhihuang1c378ed2017-08-17 14:10:50 -0700592 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700593 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700594 EXPECT_EQ(
595 media_desc_options_it->transport_options.enable_ice_renomination,
596 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700597
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700599 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 }
601 }
602
Harald Alvestrand0d018412021-11-04 13:52:31 +0000603 void TestCryptoWithBundle(bool offer) {
604 f1_.set_secure(SEC_ENABLED);
605 MediaSessionOptions options;
606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
607 std::unique_ptr<SessionDescription> ref_desc;
608 std::unique_ptr<SessionDescription> desc;
609 if (offer) {
610 options.bundle_enabled = false;
611 ref_desc = f1_.CreateOffer(options, NULL);
612 options.bundle_enabled = true;
613 desc = f1_.CreateOffer(options, ref_desc.get());
614 } else {
615 options.bundle_enabled = true;
616 ref_desc = f1_.CreateOffer(options, NULL);
617 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
618 }
619 ASSERT_TRUE(desc);
620 const cricket::MediaContentDescription* audio_media_desc =
621 desc->GetContentDescriptionByName("audio");
622 ASSERT_TRUE(audio_media_desc);
623 const cricket::MediaContentDescription* video_media_desc =
624 desc->GetContentDescriptionByName("video");
625 ASSERT_TRUE(video_media_desc);
626 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
627 video_media_desc->cryptos()));
628 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
629 EXPECT_EQ(kDefaultSrtpCryptoSuite,
630 audio_media_desc->cryptos()[0].cipher_suite);
631
632 // Verify the selected crypto is one from the reference audio
633 // media content.
634 const cricket::MediaContentDescription* ref_audio_media_desc =
635 ref_desc->GetContentDescriptionByName("audio");
636 bool found = false;
637 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
638 if (ref_audio_media_desc->cryptos()[i].Matches(
639 audio_media_desc->cryptos()[0])) {
640 found = true;
641 break;
642 }
643 }
644 EXPECT_TRUE(found);
645 }
646
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 // This test that the audio and video media direction is set to
Artem Titov880fa812021-07-30 22:30:23 +0200648 // `expected_direction_in_answer` in an answer if the offer direction is set
649 // to `direction_in_offer` and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800651 RtpTransceiverDirection direction_in_offer,
652 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700653 MediaSessionOptions offer_opts;
654 AddAudioVideoSections(direction_in_offer, &offer_opts);
655
Steve Anton6fe1fba2018-12-11 10:15:23 -0800656 std::unique_ptr<SessionDescription> offer =
657 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700659 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700661 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663
zhihuang1c378ed2017-08-17 14:10:50 -0700664 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800665 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800666 std::unique_ptr<SessionDescription> answer =
667 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 const AudioContentDescription* acd_answer =
669 GetFirstAudioContentDescription(answer.get());
670 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
671 const VideoContentDescription* vcd_answer =
672 GetFirstVideoContentDescription(answer.get());
673 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
674 }
675
676 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800677 RTC_DCHECK(content);
678 RTC_CHECK(content->media_description());
679 const cricket::AudioContentDescription* audio_desc =
680 content->media_description()->as_audio();
681 RTC_CHECK(audio_desc);
682 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
683 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800685 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 }
687 return true;
688 }
689
Harald Alvestrand0d018412021-11-04 13:52:31 +0000690 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
691 MediaSessionOptions offer_opts;
692 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
693 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
694
695 MediaSessionOptions answer_opts;
696 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
697 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
698
699 f1_.set_secure(SEC_ENABLED);
700 f2_.set_secure(SEC_ENABLED);
701 std::unique_ptr<SessionDescription> offer =
702 f1_.CreateOffer(offer_opts, NULL);
703 ASSERT_TRUE(offer.get() != NULL);
704 if (gcm_offer && gcm_answer) {
705 for (cricket::ContentInfo& content : offer->contents()) {
706 auto cryptos = content.media_description()->cryptos();
707 PreferGcmCryptoParameters(&cryptos);
708 content.media_description()->set_cryptos(cryptos);
709 }
710 }
711 std::unique_ptr<SessionDescription> answer =
712 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
713 const ContentInfo* ac = answer->GetContentByName("audio");
714 const ContentInfo* vc = answer->GetContentByName("video");
715 ASSERT_TRUE(ac != NULL);
716 ASSERT_TRUE(vc != NULL);
717 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
718 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
719 const AudioContentDescription* acd = ac->media_description()->as_audio();
720 const VideoContentDescription* vcd = vc->media_description()->as_video();
721 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
722 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
723 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
724 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
725 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
726 if (gcm_offer && gcm_answer) {
727 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
728 } else {
729 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
730 }
731 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
732 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
733 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
734 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
735 if (gcm_offer && gcm_answer) {
736 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
737 } else {
738 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
739 }
740 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
741 }
742
Johannes Kronce8e8672019-02-22 13:06:44 +0100743 void TestTransportSequenceNumberNegotiation(
744 const cricket::RtpHeaderExtensions& local,
745 const cricket::RtpHeaderExtensions& offered,
746 const cricket::RtpHeaderExtensions& expectedAnswer) {
747 MediaSessionOptions opts;
748 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +0200749 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100750 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
751 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +0200752 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100753 std::unique_ptr<SessionDescription> answer =
754 f2_.CreateAnswer(offer.get(), opts, NULL);
755
756 EXPECT_EQ(
757 expectedAnswer,
758 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
759 EXPECT_EQ(
760 expectedAnswer,
761 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
762 }
763
Markus Handell755c65d2020-06-24 01:06:10 +0200764 std::vector<webrtc::RtpHeaderExtensionCapability>
765 HeaderExtensionCapabilitiesFromRtpExtensions(
766 cricket::RtpHeaderExtensions extensions) {
767 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
768 for (const auto& extension : extensions) {
769 webrtc::RtpHeaderExtensionCapability capability(
770 extension.uri, extension.id,
771 webrtc::RtpTransceiverDirection::kSendRecv);
772 capabilities.push_back(capability);
773 }
774 return capabilities;
775 }
776
777 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
778 cricket::RtpHeaderExtensions video_exts,
779 MediaSessionOptions* opts) {
780 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
781 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
782 for (auto& entry : opts->media_description_options) {
783 switch (entry.type) {
784 case MEDIA_TYPE_AUDIO:
785 entry.header_extensions = audio_caps;
786 break;
787 case MEDIA_TYPE_VIDEO:
788 entry.header_extensions = video_caps;
789 break;
790 default:
791 break;
792 }
793 }
794 }
795
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 protected:
Jonas Orelanded99dae2022-03-09 09:28:10 +0100797 webrtc::test::ScopedKeyValueConfig field_trials;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800798 UniqueRandomIdGenerator ssrc_generator1;
799 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 TransportDescriptionFactory tdf1_;
801 TransportDescriptionFactory tdf2_;
Jonas Orelanded99dae2022-03-09 09:28:10 +0100802 MediaSessionDescriptionFactory f1_;
803 MediaSessionDescriptionFactory f2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804};
805
806// Create a typical audio offer, and ensure it matches what we expect.
807TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000808 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800809 std::unique_ptr<SessionDescription> offer =
810 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 ASSERT_TRUE(offer.get() != NULL);
812 const ContentInfo* ac = offer->GetContentByName("audio");
813 const ContentInfo* vc = offer->GetContentByName("video");
814 ASSERT_TRUE(ac != NULL);
815 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800816 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800817 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700819 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700820 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
822 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000823 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
824 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825}
826
827// Create a typical video offer, and ensure it matches what we expect.
828TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
829 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800830 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000831 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800832 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 ASSERT_TRUE(offer.get() != NULL);
834 const ContentInfo* ac = offer->GetContentByName("audio");
835 const ContentInfo* vc = offer->GetContentByName("video");
836 ASSERT_TRUE(ac != NULL);
837 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800838 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
839 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800840 const AudioContentDescription* acd = ac->media_description()->as_audio();
841 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700843 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700844 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
846 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000847 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
848 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200850 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700851 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
853 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000854 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
855 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856}
857
858// Test creating an offer with bundle where the Codecs have the same dynamic
859// RTP playlod type. The test verifies that the offer don't contain the
860// duplicate RTP payload types.
861TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200862 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700863 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865
866 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800867 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800869 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 const VideoContentDescription* vcd =
871 GetFirstVideoContentDescription(offer.get());
872 const AudioContentDescription* acd =
873 GetFirstAudioContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874 ASSERT_TRUE(NULL != vcd);
875 ASSERT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
878 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879}
880
zhihuang1c378ed2017-08-17 14:10:50 -0700881// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882// after an audio only session has been negotiated.
883TEST_F(MediaSessionDescriptionFactoryTest,
884 TestCreateUpdatedVideoOfferWithBundle) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000885 f1_.set_secure(SEC_ENABLED);
886 f2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800888 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
889 RtpTransceiverDirection::kRecvOnly, kActive,
890 &opts);
891 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
892 RtpTransceiverDirection::kInactive, kStopped,
893 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800895 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
896 std::unique_ptr<SessionDescription> answer =
897 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000898
899 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800900 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800902 std::unique_ptr<SessionDescription> updated_offer(
903 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904
905 const AudioContentDescription* acd =
906 GetFirstAudioContentDescription(updated_offer.get());
907 const VideoContentDescription* vcd =
908 GetFirstVideoContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909 EXPECT_TRUE(NULL != vcd);
910 EXPECT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911
Harald Alvestrand0d018412021-11-04 13:52:31 +0000912 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
913 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
914 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
915 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916}
917
wu@webrtc.org78187522013-10-07 23:32:02 +0000918// Create an SCTP data offer with bundle without error.
919TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
920 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000921 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200922 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000923 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800924 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000925 EXPECT_TRUE(offer.get() != NULL);
926 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000927 auto dcd = GetFirstSctpDataContentDescription(offer.get());
928 ASSERT_TRUE(dcd);
929 // Since this transport is insecure, the protocol should be "SCTP".
930 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
931}
932
933// Create an SCTP data offer with bundle without error.
934TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
935 MediaSessionOptions opts;
936 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200937 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000938 f1_.set_secure(SEC_ENABLED);
939 tdf1_.set_secure(SEC_ENABLED);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
941 EXPECT_TRUE(offer.get() != NULL);
942 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
943 auto dcd = GetFirstSctpDataContentDescription(offer.get());
944 ASSERT_TRUE(dcd);
945 // The protocol should now be "UDP/DTLS/SCTP"
946 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000947}
948
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000949// Test creating an sctp data channel from an already generated offer.
950TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
951 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000952 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200953 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000954 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800955 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000956 ASSERT_TRUE(offer1.get() != NULL);
957 const ContentInfo* data = offer1->GetContentByName("data");
958 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800959 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000960
kwiberg31022942016-03-11 14:18:21 -0800961 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000962 f1_.CreateOffer(opts, offer1.get()));
963 data = offer2->GetContentByName("data");
964 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800965 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000966}
967
Steve Anton2bed3972019-01-04 17:04:30 -0800968// Test that if BUNDLE is enabled and all media sections are rejected then the
969// BUNDLE group is not present in the re-offer.
970TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
971 MediaSessionOptions opts;
972 opts.bundle_enabled = true;
973 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
974 RtpTransceiverDirection::kSendRecv, kActive,
975 &opts);
976 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
977
978 opts.media_description_options[0].stopped = true;
979 std::unique_ptr<SessionDescription> reoffer =
980 f1_.CreateOffer(opts, offer.get());
981
982 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
983}
984
985// Test that if BUNDLE is enabled and the remote re-offer does not include a
986// BUNDLE group since all media sections are rejected, then the re-answer also
987// does not include a BUNDLE group.
988TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
989 MediaSessionOptions opts;
990 opts.bundle_enabled = true;
991 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
992 RtpTransceiverDirection::kSendRecv, kActive,
993 &opts);
994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
995 std::unique_ptr<SessionDescription> answer =
996 f2_.CreateAnswer(offer.get(), opts, nullptr);
997
998 opts.media_description_options[0].stopped = true;
999 std::unique_ptr<SessionDescription> reoffer =
1000 f1_.CreateOffer(opts, offer.get());
1001 std::unique_ptr<SessionDescription> reanswer =
1002 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1003
1004 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1005}
1006
1007// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1008// was rejected then the new offerer-tagged media section is the non-rejected
1009// media section.
1010TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1011 MediaSessionOptions opts;
1012 opts.bundle_enabled = true;
1013 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1014 RtpTransceiverDirection::kSendRecv, kActive,
1015 &opts);
1016 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1017
1018 // Reject the audio m= section and add a video m= section.
1019 opts.media_description_options[0].stopped = true;
1020 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1021 RtpTransceiverDirection::kSendRecv, kActive,
1022 &opts);
1023 std::unique_ptr<SessionDescription> reoffer =
1024 f1_.CreateOffer(opts, offer.get());
1025
1026 const cricket::ContentGroup* bundle_group =
1027 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1028 ASSERT_TRUE(bundle_group);
1029 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1030 EXPECT_TRUE(bundle_group->HasContentName("video"));
1031}
1032
1033// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1034// was rejected and a new media section is added, then the re-answer BUNDLE
1035// group will contain only the non-rejected media section.
1036TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1037 MediaSessionOptions opts;
1038 opts.bundle_enabled = true;
1039 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1040 RtpTransceiverDirection::kSendRecv, kActive,
1041 &opts);
1042 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1043 std::unique_ptr<SessionDescription> answer =
1044 f2_.CreateAnswer(offer.get(), opts, nullptr);
1045
1046 // Reject the audio m= section and add a video m= section.
1047 opts.media_description_options[0].stopped = true;
1048 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1049 RtpTransceiverDirection::kSendRecv, kActive,
1050 &opts);
1051 std::unique_ptr<SessionDescription> reoffer =
1052 f1_.CreateOffer(opts, offer.get());
1053 std::unique_ptr<SessionDescription> reanswer =
1054 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1055
1056 const cricket::ContentGroup* bundle_group =
1057 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1058 ASSERT_TRUE(bundle_group);
1059 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1060 EXPECT_TRUE(bundle_group->HasContentName("video"));
1061}
1062
Henrik Boströmf8187e02021-04-26 21:04:26 +02001063TEST_F(MediaSessionDescriptionFactoryTest,
1064 CreateAnswerForOfferWithMultipleBundleGroups) {
1065 // Create an offer with 4 m= sections, initially without BUNDLE groups.
1066 MediaSessionOptions opts;
1067 opts.bundle_enabled = false;
1068 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "1",
1069 RtpTransceiverDirection::kSendRecv, kActive,
1070 &opts);
1071 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "2",
1072 RtpTransceiverDirection::kSendRecv, kActive,
1073 &opts);
1074 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "3",
1075 RtpTransceiverDirection::kSendRecv, kActive,
1076 &opts);
1077 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "4",
1078 RtpTransceiverDirection::kSendRecv, kActive,
1079 &opts);
1080 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1081 ASSERT_TRUE(offer->groups().empty());
1082
1083 // Munge the offer to have two groups. Offers like these cannot be generated
1084 // without munging, but it is valid to receive such offers from remote
1085 // endpoints.
1086 cricket::ContentGroup bundle_group1(cricket::GROUP_TYPE_BUNDLE);
1087 bundle_group1.AddContentName("1");
1088 bundle_group1.AddContentName("2");
1089 cricket::ContentGroup bundle_group2(cricket::GROUP_TYPE_BUNDLE);
1090 bundle_group2.AddContentName("3");
1091 bundle_group2.AddContentName("4");
1092 offer->AddGroup(bundle_group1);
1093 offer->AddGroup(bundle_group2);
1094
1095 // If BUNDLE is enabled, the answer to this offer should accept both BUNDLE
1096 // groups.
1097 opts.bundle_enabled = true;
1098 std::unique_ptr<SessionDescription> answer =
1099 f2_.CreateAnswer(offer.get(), opts, nullptr);
1100
1101 std::vector<const cricket::ContentGroup*> answer_groups =
1102 answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1103 ASSERT_EQ(answer_groups.size(), 2u);
1104 EXPECT_EQ(answer_groups[0]->content_names().size(), 2u);
1105 EXPECT_TRUE(answer_groups[0]->HasContentName("1"));
1106 EXPECT_TRUE(answer_groups[0]->HasContentName("2"));
1107 EXPECT_EQ(answer_groups[1]->content_names().size(), 2u);
1108 EXPECT_TRUE(answer_groups[1]->HasContentName("3"));
1109 EXPECT_TRUE(answer_groups[1]->HasContentName("4"));
1110
1111 // If BUNDLE is disabled, the answer to this offer should reject both BUNDLE
1112 // groups.
1113 opts.bundle_enabled = false;
1114 answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1115
1116 answer_groups = answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1117 // Rejected groups are still listed, but they are empty.
1118 ASSERT_EQ(answer_groups.size(), 2u);
1119 EXPECT_TRUE(answer_groups[0]->content_names().empty());
1120 EXPECT_TRUE(answer_groups[1]->content_names().empty());
1121}
1122
Steve Anton2bed3972019-01-04 17:04:30 -08001123// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1124// and there is still a non-rejected media section that was in the initial
1125// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1126// media section.
1127TEST_F(MediaSessionDescriptionFactoryTest,
1128 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1129 MediaSessionOptions opts;
1130 opts.bundle_enabled = true;
1131 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1132 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1133 std::unique_ptr<SessionDescription> answer =
1134 f2_.CreateAnswer(offer.get(), opts, nullptr);
1135
1136 // Reject the audio m= section.
1137 opts.media_description_options[0].stopped = true;
1138 std::unique_ptr<SessionDescription> reoffer =
1139 f1_.CreateOffer(opts, offer.get());
1140
1141 const TransportDescription* offer_tagged =
1142 offer->GetTransportDescriptionByName("audio");
1143 ASSERT_TRUE(offer_tagged);
1144 const TransportDescription* reoffer_tagged =
1145 reoffer->GetTransportDescriptionByName("video");
1146 ASSERT_TRUE(reoffer_tagged);
1147 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1148 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1149}
1150
1151// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1152// and there is still a non-rejected media section that was in the initial
1153// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1154// media section.
1155TEST_F(MediaSessionDescriptionFactoryTest,
1156 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1157 MediaSessionOptions opts;
1158 opts.bundle_enabled = true;
1159 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1160 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1161 std::unique_ptr<SessionDescription> answer =
1162 f2_.CreateAnswer(offer.get(), opts, nullptr);
1163
1164 // Reject the audio m= section.
1165 opts.media_description_options[0].stopped = true;
1166 std::unique_ptr<SessionDescription> reoffer =
1167 f1_.CreateOffer(opts, offer.get());
1168 std::unique_ptr<SessionDescription> reanswer =
1169 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1170
1171 const TransportDescription* answer_tagged =
1172 answer->GetTransportDescriptionByName("audio");
1173 ASSERT_TRUE(answer_tagged);
1174 const TransportDescription* reanswer_tagged =
1175 reanswer->GetTransportDescriptionByName("video");
1176 ASSERT_TRUE(reanswer_tagged);
1177 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1178 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1179}
1180
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181// Create an audio, video offer without legacy StreamParams.
1182TEST_F(MediaSessionDescriptionFactoryTest,
1183 TestCreateOfferWithoutLegacyStreams) {
1184 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001185 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001186 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001187 ASSERT_TRUE(offer.get() != NULL);
1188 const ContentInfo* ac = offer->GetContentByName("audio");
1189 const ContentInfo* vc = offer->GetContentByName("video");
1190 ASSERT_TRUE(ac != NULL);
1191 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001192 const AudioContentDescription* acd = ac->media_description()->as_audio();
1193 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194
Yves Gerey665174f2018-06-19 15:03:05 +02001195 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1196 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197}
1198
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001199// Creates an audio+video sendonly offer.
1200TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001201 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001202 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001203 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1204 {kMediaStream1}, 1, &opts);
1205 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1206 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001207
Steve Anton6fe1fba2018-12-11 10:15:23 -08001208 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001209 ASSERT_TRUE(offer.get() != NULL);
1210 EXPECT_EQ(2u, offer->contents().size());
1211 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1212 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1213
Steve Anton4e70a722017-11-28 14:57:10 -08001214 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1215 GetMediaDirection(&offer->contents()[0]));
1216 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1217 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001218}
1219
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001220// Verifies that the order of the media contents in the current
1221// SessionDescription is preserved in the new SessionDescription.
1222TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1223 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001224 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001225
kwiberg31022942016-03-11 14:18:21 -08001226 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001227 ASSERT_TRUE(offer1.get() != NULL);
1228 EXPECT_EQ(1u, offer1->contents().size());
1229 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1230
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001231 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1232 RtpTransceiverDirection::kRecvOnly, kActive,
1233 &opts);
kwiberg31022942016-03-11 14:18:21 -08001234 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001235 f1_.CreateOffer(opts, offer1.get()));
1236 ASSERT_TRUE(offer2.get() != NULL);
1237 EXPECT_EQ(2u, offer2->contents().size());
1238 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1239 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1240
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001241 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1242 RtpTransceiverDirection::kRecvOnly, kActive,
1243 &opts);
kwiberg31022942016-03-11 14:18:21 -08001244 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001245 f1_.CreateOffer(opts, offer2.get()));
1246 ASSERT_TRUE(offer3.get() != NULL);
1247 EXPECT_EQ(3u, offer3->contents().size());
1248 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1249 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1250 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001251}
1252
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253// Create a typical audio answer, and ensure it matches what we expect.
1254TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001255 f1_.set_secure(SEC_ENABLED);
1256 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001257 std::unique_ptr<SessionDescription> offer =
1258 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001260 std::unique_ptr<SessionDescription> answer =
1261 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 const ContentInfo* ac = answer->GetContentByName("audio");
1263 const ContentInfo* vc = answer->GetContentByName("video");
1264 ASSERT_TRUE(ac != NULL);
1265 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001266 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001267 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001269 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001270 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1272 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001273 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1274 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
1275}
1276
1277// Create a typical audio answer with GCM ciphers enabled, and ensure it
1278// matches what we expect.
1279TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1280 f1_.set_secure(SEC_ENABLED);
1281 f2_.set_secure(SEC_ENABLED);
1282 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1283 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
1284 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1285 ASSERT_TRUE(offer.get() != NULL);
1286 for (cricket::ContentInfo& content : offer->contents()) {
1287 auto cryptos = content.media_description()->cryptos();
1288 PreferGcmCryptoParameters(&cryptos);
1289 content.media_description()->set_cryptos(cryptos);
1290 }
1291 std::unique_ptr<SessionDescription> answer =
1292 f2_.CreateAnswer(offer.get(), opts, NULL);
1293 const ContentInfo* ac = answer->GetContentByName("audio");
1294 const ContentInfo* vc = answer->GetContentByName("video");
1295 ASSERT_TRUE(ac != NULL);
1296 ASSERT_TRUE(vc == NULL);
1297 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1298 const AudioContentDescription* acd = ac->media_description()->as_audio();
1299 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1300 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
1301 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
1302 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1303 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1304 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
1305 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001306}
1307
Philipp Hancke2f3168f2022-05-16 14:41:32 +02001308// Create an audio answer with no common codecs, and ensure it is rejected.
1309TEST_F(MediaSessionDescriptionFactoryTest,
1310 TestCreateAudioAnswerWithNoCommonCodecs) {
1311 MediaSessionOptions opts;
1312 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1313 RtpTransceiverDirection::kSendRecv, kActive,
1314 &opts);
1315 std::vector f1_codecs = {AudioCodec(96, "opus", 48000, -1, 1)};
1316 f1_.set_audio_codecs(f1_codecs, f1_codecs);
1317
1318 std::vector f2_codecs = {AudioCodec(0, "PCMU", 8000, -1, 1)};
1319 f2_.set_audio_codecs(f2_codecs, f2_codecs);
1320
1321 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1322 std::unique_ptr<SessionDescription> answer =
1323 f2_.CreateAnswer(offer.get(), opts, NULL);
1324 const ContentInfo* ac = answer->GetContentByName("audio");
1325 ASSERT_TRUE(ac != NULL);
1326 EXPECT_TRUE(ac->rejected);
1327}
1328
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001329// Create a typical video answer, and ensure it matches what we expect.
1330TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1331 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001332 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00001333 f1_.set_secure(SEC_ENABLED);
1334 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001335 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001336 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001337 std::unique_ptr<SessionDescription> answer =
1338 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339 const ContentInfo* ac = answer->GetContentByName("audio");
1340 const ContentInfo* vc = answer->GetContentByName("video");
1341 ASSERT_TRUE(ac != NULL);
1342 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001343 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1344 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001345 const AudioContentDescription* acd = ac->media_description()->as_audio();
1346 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001347 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001348 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001349 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001350 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001352 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001353 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001354 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001355 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1356 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001357 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1358 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
1359}
1360
1361// Create a typical video answer with GCM ciphers enabled, and ensure it
1362// matches what we expect.
1363TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1364 TestVideoGcmCipher(true, true);
1365}
1366
1367// Create a typical video answer with GCM ciphers enabled for the offer only,
1368// and ensure it matches what we expect.
1369TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1370 TestVideoGcmCipher(true, false);
1371}
1372
1373// Create a typical video answer with GCM ciphers enabled for the answer only,
1374// and ensure it matches what we expect.
1375TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1376 TestVideoGcmCipher(false, true);
jbauchcb560652016-08-04 05:20:32 -07001377}
1378
Philipp Hancke2f3168f2022-05-16 14:41:32 +02001379// Create a video answer with no common codecs, and ensure it is rejected.
1380TEST_F(MediaSessionDescriptionFactoryTest,
1381 TestCreateVideoAnswerWithNoCommonCodecs) {
1382 MediaSessionOptions opts;
1383 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1384 RtpTransceiverDirection::kSendRecv, kActive,
1385 &opts);
1386 std::vector f1_codecs = {VideoCodec(96, "H264")};
1387 f1_.set_video_codecs(f1_codecs, f1_codecs);
1388
1389 std::vector f2_codecs = {VideoCodec(97, "VP8")};
1390 f2_.set_video_codecs(f2_codecs, f2_codecs);
1391
1392 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1393 std::unique_ptr<SessionDescription> answer =
1394 f2_.CreateAnswer(offer.get(), opts, NULL);
1395 const ContentInfo* vc = answer->GetContentByName("video");
1396 ASSERT_TRUE(vc != NULL);
1397 EXPECT_TRUE(vc->rejected);
1398}
1399
1400// Create a video answer with no common codecs (but a common FEC codec), and
1401// ensure it is rejected.
1402TEST_F(MediaSessionDescriptionFactoryTest,
1403 TestCreateVideoAnswerWithOnlyFecCodecsCommon) {
1404 MediaSessionOptions opts;
1405 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1406 RtpTransceiverDirection::kSendRecv, kActive,
1407 &opts);
1408 std::vector f1_codecs = {VideoCodec(96, "H264"),
1409 VideoCodec(118, "flexfec-03")};
1410 f1_.set_video_codecs(f1_codecs, f1_codecs);
1411
1412 std::vector f2_codecs = {VideoCodec(97, "VP8"),
1413 VideoCodec(118, "flexfec-03")};
1414 f2_.set_video_codecs(f2_codecs, f2_codecs);
1415
1416 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1417 std::unique_ptr<SessionDescription> answer =
1418 f2_.CreateAnswer(offer.get(), opts, NULL);
1419 const ContentInfo* vc = answer->GetContentByName("video");
1420 ASSERT_TRUE(vc != NULL);
1421 EXPECT_TRUE(vc->rejected);
1422}
1423
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001424// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1425// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001426TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1427 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001428 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001429 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001430 ASSERT_TRUE(offer.get() != NULL);
1431 ContentInfo* dc_offer = offer->GetContentByName("data");
1432 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001433 SctpDataContentDescription* dcd_offer =
1434 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001435 EXPECT_TRUE(dcd_offer->use_sctpmap());
1436
Steve Anton6fe1fba2018-12-11 10:15:23 -08001437 std::unique_ptr<SessionDescription> answer =
1438 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001439 const ContentInfo* dc_answer = answer->GetContentByName("data");
1440 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001441 const SctpDataContentDescription* dcd_answer =
1442 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001443 EXPECT_TRUE(dcd_answer->use_sctpmap());
1444}
1445
1446// The answer's use_sctpmap flag should match the offer's.
1447TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1448 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001449 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001450 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001451 ASSERT_TRUE(offer.get() != NULL);
1452 ContentInfo* dc_offer = offer->GetContentByName("data");
1453 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001454 SctpDataContentDescription* dcd_offer =
1455 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001456 dcd_offer->set_use_sctpmap(false);
1457
Steve Anton6fe1fba2018-12-11 10:15:23 -08001458 std::unique_ptr<SessionDescription> answer =
1459 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001460 const ContentInfo* dc_answer = answer->GetContentByName("data");
1461 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001462 const SctpDataContentDescription* dcd_answer =
1463 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001464 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001465}
1466
deadbeef8b7e9ad2017-05-25 09:38:55 -07001467// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1468// and "TCP/DTLS/SCTP" offers.
1469TEST_F(MediaSessionDescriptionFactoryTest,
1470 TestCreateDataAnswerToDifferentOfferedProtos) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001471 // Need to enable DTLS offer/answer generation (disabled by default in this
1472 // test).
1473 f1_.set_secure(SEC_ENABLED);
1474 f2_.set_secure(SEC_ENABLED);
1475 tdf1_.set_secure(SEC_ENABLED);
1476 tdf2_.set_secure(SEC_ENABLED);
1477
deadbeef8b7e9ad2017-05-25 09:38:55 -07001478 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001479 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001480 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001481 ASSERT_TRUE(offer.get() != nullptr);
1482 ContentInfo* dc_offer = offer->GetContentByName("data");
1483 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001484 SctpDataContentDescription* dcd_offer =
1485 dc_offer->media_description()->as_sctp();
1486 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001487
1488 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1489 "TCP/DTLS/SCTP"};
1490 for (const std::string& proto : protos) {
1491 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001492 std::unique_ptr<SessionDescription> answer =
1493 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001494 const ContentInfo* dc_answer = answer->GetContentByName("data");
1495 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001496 const SctpDataContentDescription* dcd_answer =
1497 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001498 EXPECT_FALSE(dc_answer->rejected);
1499 EXPECT_EQ(proto, dcd_answer->protocol());
1500 }
1501}
1502
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001503TEST_F(MediaSessionDescriptionFactoryTest,
1504 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001505 // Need to enable DTLS offer/answer generation (disabled by default in this
1506 // test).
1507 f1_.set_secure(SEC_ENABLED);
1508 f2_.set_secure(SEC_ENABLED);
1509 tdf1_.set_secure(SEC_ENABLED);
1510 tdf2_.set_secure(SEC_ENABLED);
1511
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001512 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001513 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001514 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1515 ASSERT_TRUE(offer.get() != nullptr);
1516 ContentInfo* dc_offer = offer->GetContentByName("data");
1517 ASSERT_TRUE(dc_offer != nullptr);
1518 SctpDataContentDescription* dcd_offer =
1519 dc_offer->media_description()->as_sctp();
1520 ASSERT_TRUE(dcd_offer);
1521 dcd_offer->set_max_message_size(1234);
1522 std::unique_ptr<SessionDescription> answer =
1523 f2_.CreateAnswer(offer.get(), opts, nullptr);
1524 const ContentInfo* dc_answer = answer->GetContentByName("data");
1525 ASSERT_TRUE(dc_answer != nullptr);
1526 const SctpDataContentDescription* dcd_answer =
1527 dc_answer->media_description()->as_sctp();
1528 EXPECT_FALSE(dc_answer->rejected);
1529 EXPECT_EQ(1234, dcd_answer->max_message_size());
1530}
1531
1532TEST_F(MediaSessionDescriptionFactoryTest,
1533 TestCreateDataAnswerToOfferWithZeroMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001534 // Need to enable DTLS offer/answer generation (disabled by default in this
1535 // test).
1536 f1_.set_secure(SEC_ENABLED);
1537 f2_.set_secure(SEC_ENABLED);
1538 tdf1_.set_secure(SEC_ENABLED);
1539 tdf2_.set_secure(SEC_ENABLED);
1540
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001541 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001542 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001543 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1544 ASSERT_TRUE(offer.get() != nullptr);
1545 ContentInfo* dc_offer = offer->GetContentByName("data");
1546 ASSERT_TRUE(dc_offer != nullptr);
1547 SctpDataContentDescription* dcd_offer =
1548 dc_offer->media_description()->as_sctp();
1549 ASSERT_TRUE(dcd_offer);
1550 dcd_offer->set_max_message_size(0);
1551 std::unique_ptr<SessionDescription> answer =
1552 f2_.CreateAnswer(offer.get(), opts, nullptr);
1553 const ContentInfo* dc_answer = answer->GetContentByName("data");
1554 ASSERT_TRUE(dc_answer != nullptr);
1555 const SctpDataContentDescription* dcd_answer =
1556 dc_answer->media_description()->as_sctp();
1557 EXPECT_FALSE(dc_answer->rejected);
1558 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1559}
1560
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001561// Verifies that the order of the media contents in the offer is preserved in
1562// the answer.
1563TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1564 MediaSessionOptions opts;
1565
1566 // Creates a data only offer.
Florent Castelli516e2842021-04-19 15:29:50 +02001567 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001568 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001569 ASSERT_TRUE(offer1.get() != NULL);
1570
1571 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001572 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1573 RtpTransceiverDirection::kRecvOnly, kActive,
1574 &opts);
kwiberg31022942016-03-11 14:18:21 -08001575 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001576 f1_.CreateOffer(opts, offer1.get()));
1577 ASSERT_TRUE(offer2.get() != NULL);
1578
1579 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001580 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1581 RtpTransceiverDirection::kRecvOnly, kActive,
1582 &opts);
kwiberg31022942016-03-11 14:18:21 -08001583 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001584 f1_.CreateOffer(opts, offer2.get()));
1585 ASSERT_TRUE(offer3.get() != NULL);
1586
Steve Anton6fe1fba2018-12-11 10:15:23 -08001587 std::unique_ptr<SessionDescription> answer =
1588 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001589 ASSERT_TRUE(answer.get() != NULL);
1590 EXPECT_EQ(3u, answer->contents().size());
1591 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1592 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1593 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1594}
1595
ossu075af922016-06-14 03:29:38 -07001596// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1597// answerer settings.
1598
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001599// This test that the media direction is set to send/receive in an answer if
1600// the offer is send receive.
1601TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001602 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1603 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604}
1605
1606// This test that the media direction is set to receive only in an answer if
1607// the offer is send only.
1608TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001609 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1610 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611}
1612
1613// This test that the media direction is set to send only in an answer if
1614// the offer is recv only.
1615TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001616 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1617 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001618}
1619
1620// This test that the media direction is set to inactive in an answer if
1621// the offer is inactive.
1622TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001623 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1624 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001625}
1626
Harald Alvestrand0d018412021-11-04 13:52:31 +00001627// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001628TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001629 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Harald Alvestrand0d018412021-11-04 13:52:31 +00001630 f1_.set_secure(SEC_DISABLED);
1631 f2_.set_secure(SEC_DISABLED);
1632 tdf1_.set_secure(SEC_DISABLED);
1633 tdf2_.set_secure(SEC_DISABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634
Steve Anton6fe1fba2018-12-11 10:15:23 -08001635 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001636 const AudioContentDescription* offer_acd =
1637 GetFirstAudioContentDescription(offer.get());
1638 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001639 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640
Steve Anton6fe1fba2018-12-11 10:15:23 -08001641 std::unique_ptr<SessionDescription> answer =
1642 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001643
1644 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1645 ASSERT_TRUE(ac_answer != NULL);
1646 EXPECT_FALSE(ac_answer->rejected);
1647
1648 const AudioContentDescription* answer_acd =
1649 GetFirstAudioContentDescription(answer.get());
1650 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001651 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001652}
1653
1654// Create a video offer and answer and ensure the RTP header extensions
1655// matches what we expect.
1656TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1657 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001658 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +02001659 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1660 MAKE_VECTOR(kVideoRtpExtension1), &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001661
Steve Anton6fe1fba2018-12-11 10:15:23 -08001662 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001663 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001664 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1665 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001666 std::unique_ptr<SessionDescription> answer =
1667 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668
Yves Gerey665174f2018-06-19 15:03:05 +02001669 EXPECT_EQ(
1670 MAKE_VECTOR(kAudioRtpExtension1),
1671 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1672 EXPECT_EQ(
1673 MAKE_VECTOR(kVideoRtpExtension1),
1674 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1675 EXPECT_EQ(
1676 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1677 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1678 EXPECT_EQ(
1679 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1680 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001681}
1682
Johannes Kronce8e8672019-02-22 13:06:44 +01001683// Create a audio/video offer and answer and ensure that the
1684// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1685// supported and should take precedence even though not listed among locally
1686// supported extensions.
1687TEST_F(MediaSessionDescriptionFactoryTest,
1688 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1689 TestTransportSequenceNumberNegotiation(
1690 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1691 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1692 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1693}
1694TEST_F(MediaSessionDescriptionFactoryTest,
1695 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1696 TestTransportSequenceNumberNegotiation(
1697 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1698 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1699 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1700}
1701TEST_F(MediaSessionDescriptionFactoryTest,
1702 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1703 TestTransportSequenceNumberNegotiation(
1704 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1705 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1706 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1707}
1708
jbauch5869f502017-06-29 12:31:36 -07001709TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001710 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1711 MediaSessionOptions opts;
1712 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1713
Markus Handell755c65d2020-06-24 01:06:10 +02001714 SetAudioVideoRtpHeaderExtensions(
1715 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1716 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001717 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001718 SetAudioVideoRtpHeaderExtensions(
1719 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1720 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001721 std::unique_ptr<SessionDescription> answer =
1722 f2_.CreateAnswer(offer.get(), opts, nullptr);
1723 EXPECT_THAT(
1724 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001725 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001726 EXPECT_THAT(
1727 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001728 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001729}
1730
1731TEST_F(MediaSessionDescriptionFactoryTest,
1732 TestNegotiateFrameDescriptorWhenExposedLocally) {
1733 MediaSessionOptions opts;
1734 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1735
Markus Handell755c65d2020-06-24 01:06:10 +02001736 SetAudioVideoRtpHeaderExtensions(
1737 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1738 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001739 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1740 std::unique_ptr<SessionDescription> answer =
1741 f2_.CreateAnswer(offer.get(), opts, nullptr);
1742 EXPECT_THAT(
1743 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001744 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001745 EXPECT_THAT(
1746 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001747 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001748}
1749
1750TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001751 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1752 MediaSessionOptions opts;
1753 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1754
1755 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell755c65d2020-06-24 01:06:10 +02001756 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +00001757 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001758 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1759 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001760 std::unique_ptr<SessionDescription> answer =
1761 f2_.CreateAnswer(offer.get(), opts, nullptr);
1762 EXPECT_THAT(
1763 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1764 ElementsAre(offer_dd));
1765}
1766
1767TEST_F(MediaSessionDescriptionFactoryTest,
1768 NegotiateDependencyDescriptorWhenExposedLocally) {
1769 MediaSessionOptions opts;
1770 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1771
1772 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1773 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell755c65d2020-06-24 01:06:10 +02001774 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001776 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001777 std::unique_ptr<SessionDescription> answer =
1778 f2_.CreateAnswer(offer.get(), opts, nullptr);
1779 EXPECT_THAT(
1780 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1781 ElementsAre(offer_dd));
1782}
1783
1784TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001785 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1786 MediaSessionOptions opts;
1787 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1788
1789 const cricket::RtpHeaderExtensions offered_extensions = {
1790 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1791 const cricket::RtpHeaderExtensions local_extensions = {
1792 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001793 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1794 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001795 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001796 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001797 std::unique_ptr<SessionDescription> answer =
1798 f2_.CreateAnswer(offer.get(), opts, nullptr);
1799 EXPECT_THAT(
1800 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1801 ElementsAreArray(offered_extensions));
1802 EXPECT_THAT(
1803 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1804 ElementsAreArray(offered_extensions));
1805}
1806
1807TEST_F(MediaSessionDescriptionFactoryTest,
1808 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1809 MediaSessionOptions opts;
1810 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1811
1812 const cricket::RtpHeaderExtensions offered_extensions = {
1813 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1814 const cricket::RtpHeaderExtensions local_extensions = {
1815 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001816 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1817 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001818 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001819 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001820 std::unique_ptr<SessionDescription> answer =
1821 f2_.CreateAnswer(offer.get(), opts, nullptr);
1822 EXPECT_THAT(
1823 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1824 ElementsAreArray(offered_extensions));
1825 EXPECT_THAT(
1826 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1827 ElementsAreArray(offered_extensions));
1828}
1829
1830TEST_F(MediaSessionDescriptionFactoryTest,
1831 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1832 MediaSessionOptions opts;
1833 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1834
1835 const cricket::RtpHeaderExtensions offered_extensions = {
1836 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1837 const cricket::RtpHeaderExtensions local_extensions = {
1838 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001839 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1840 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001841 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001842 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001843 std::unique_ptr<SessionDescription> answer =
1844 f2_.CreateAnswer(offer.get(), opts, nullptr);
1845 EXPECT_THAT(
1846 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1847 IsEmpty());
1848 EXPECT_THAT(
1849 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1850 IsEmpty());
1851}
1852
1853TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handell755c65d2020-06-24 01:06:10 +02001854 OffersUnstoppedExtensionsWithAudioVideoExtensionStopped) {
1855 MediaSessionOptions opts;
1856 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1857 RtpTransceiverDirection::kSendRecv, kActive,
1858 &opts);
1859 opts.media_description_options.back().header_extensions = {
1860 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1861 RtpTransceiverDirection::kStopped),
1862 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1863 RtpTransceiverDirection::kSendOnly)};
1864 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1865 RtpTransceiverDirection::kSendRecv, kActive,
1866 &opts);
1867 opts.media_description_options.back().header_extensions = {
1868 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1869 RtpTransceiverDirection::kStopped),
1870 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1871 RtpTransceiverDirection::kSendOnly)};
1872 auto offer = f1_.CreateOffer(opts, nullptr);
1873 EXPECT_THAT(
1874 offer->contents(),
1875 ElementsAre(
1876 Property(&ContentInfo::media_description,
1877 Pointee(Property(
1878 &MediaContentDescription::rtp_header_extensions,
1879 ElementsAre(Field(&RtpExtension::uri, "uri2"))))),
1880 Property(&ContentInfo::media_description,
1881 Pointee(Property(
1882 &MediaContentDescription::rtp_header_extensions,
1883 ElementsAre(Field(&RtpExtension::uri, "uri3")))))));
1884}
1885
1886TEST_F(MediaSessionDescriptionFactoryTest,
1887 OffersUnstoppedExtensionsWithAudioExtensionStopped) {
1888 MediaSessionOptions opts;
1889 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1890 RtpTransceiverDirection::kSendRecv, kActive,
1891 &opts);
1892 opts.media_description_options.back().header_extensions = {
1893 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1894 RtpTransceiverDirection::kSendOnly),
1895 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1896 RtpTransceiverDirection::kStopped)};
1897 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1898 RtpTransceiverDirection::kSendRecv, kActive,
1899 &opts);
1900 opts.media_description_options.back().header_extensions = {
1901 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1902 RtpTransceiverDirection::kSendRecv),
1903 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1904 RtpTransceiverDirection::kSendOnly)};
1905 auto offer = f1_.CreateOffer(opts, nullptr);
1906 EXPECT_THAT(
1907 offer->contents(),
1908 ElementsAre(
1909 Property(&ContentInfo::media_description,
1910 Pointee(Property(
1911 &MediaContentDescription::rtp_header_extensions,
1912 ElementsAre(Field(&RtpExtension::uri, "uri1"))))),
1913 Property(
1914 &ContentInfo::media_description,
1915 Pointee(Property(
1916 &MediaContentDescription::rtp_header_extensions,
1917 UnorderedElementsAre(Field(&RtpExtension::uri, "uri3"),
1918 Field(&RtpExtension::uri, "uri42")))))));
1919}
1920
1921TEST_F(MediaSessionDescriptionFactoryTest,
1922 OffersUnstoppedExtensionsWithVideoExtensionStopped) {
1923 MediaSessionOptions opts;
1924 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1925 RtpTransceiverDirection::kSendRecv, kActive,
1926 &opts);
1927 opts.media_description_options.back().header_extensions = {
1928 webrtc::RtpHeaderExtensionCapability("uri1", 5,
1929 RtpTransceiverDirection::kSendOnly),
1930 webrtc::RtpHeaderExtensionCapability("uri2", 7,
1931 RtpTransceiverDirection::kSendRecv)};
1932 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1933 RtpTransceiverDirection::kSendRecv, kActive,
1934 &opts);
1935 opts.media_description_options.back().header_extensions = {
1936 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1937 RtpTransceiverDirection::kSendRecv),
1938 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1939 RtpTransceiverDirection::kStopped)};
1940 auto offer = f1_.CreateOffer(opts, nullptr);
1941 EXPECT_THAT(
1942 offer->contents(),
1943 ElementsAre(
1944 Property(
1945 &ContentInfo::media_description,
1946 Pointee(Property(
1947 &MediaContentDescription::rtp_header_extensions,
1948 UnorderedElementsAre(Field(&RtpExtension::uri, "uri1"),
1949 Field(&RtpExtension::uri, "uri2"))))),
1950 Property(&ContentInfo::media_description,
1951 Pointee(Property(
1952 &MediaContentDescription::rtp_header_extensions,
1953 ElementsAre(Field(&RtpExtension::uri, "uri42")))))));
1954}
1955
1956TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1957 MediaSessionOptions opts;
1958 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1959 RtpTransceiverDirection::kSendRecv, kActive,
1960 &opts);
1961 opts.media_description_options.back().header_extensions = {
1962 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1963 RtpTransceiverDirection::kStopped),
1964 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1965 RtpTransceiverDirection::kSendOnly),
1966 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1967 RtpTransceiverDirection::kRecvOnly),
1968 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1969 RtpTransceiverDirection::kSendRecv)};
1970 auto offer = f1_.CreateOffer(opts, nullptr);
1971 opts.media_description_options.back().header_extensions = {
1972 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1973 RtpTransceiverDirection::kSendOnly),
1974 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1975 RtpTransceiverDirection::kRecvOnly),
1976 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1977 RtpTransceiverDirection::kStopped),
1978 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1979 RtpTransceiverDirection::kSendRecv)};
1980 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1981 EXPECT_THAT(
1982 answer->contents(),
1983 ElementsAre(Property(
1984 &ContentInfo::media_description,
1985 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1986 ElementsAre(Field(&RtpExtension::uri, "uri2"),
1987 Field(&RtpExtension::uri, "uri4")))))));
1988}
1989
1990TEST_F(MediaSessionDescriptionFactoryTest,
1991 AppendsUnstoppedExtensionsToCurrentDescription) {
1992 MediaSessionOptions opts;
1993 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1994 RtpTransceiverDirection::kSendRecv, kActive,
1995 &opts);
1996 opts.media_description_options.back().header_extensions = {
1997 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1998 RtpTransceiverDirection::kSendRecv)};
1999 auto offer = f1_.CreateOffer(opts, nullptr);
2000 opts.media_description_options.back().header_extensions = {
2001 webrtc::RtpHeaderExtensionCapability("uri1", 2,
2002 RtpTransceiverDirection::kSendRecv),
2003 webrtc::RtpHeaderExtensionCapability("uri2", 3,
2004 RtpTransceiverDirection::kRecvOnly),
2005 webrtc::RtpHeaderExtensionCapability("uri3", 5,
2006 RtpTransceiverDirection::kStopped),
2007 webrtc::RtpHeaderExtensionCapability("uri4", 6,
2008 RtpTransceiverDirection::kSendRecv)};
2009 auto offer2 = f1_.CreateOffer(opts, offer.get());
2010 EXPECT_THAT(
2011 offer2->contents(),
2012 ElementsAre(Property(
2013 &ContentInfo::media_description,
2014 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2015 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2016 Field(&RtpExtension::uri, "uri2"),
2017 Field(&RtpExtension::uri, "uri4")))))));
2018}
2019
2020TEST_F(MediaSessionDescriptionFactoryTest,
2021 AppendsStoppedExtensionIfKnownAndPresentInTheOffer) {
2022 MediaSessionOptions opts;
2023 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2024 RtpTransceiverDirection::kSendRecv, kActive,
2025 &opts);
2026 opts.media_description_options.back().header_extensions = {
2027 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2028 RtpTransceiverDirection::kSendRecv),
2029 webrtc::RtpHeaderExtensionCapability("uri2", 1,
2030 RtpTransceiverDirection::kSendRecv)};
2031 auto offer = f1_.CreateOffer(opts, nullptr);
2032
2033 // Now add "uri2" as stopped to the options verify that the offer contains
2034 // uri2 since it's already present since before.
2035 opts.media_description_options.back().header_extensions = {
2036 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2037 RtpTransceiverDirection::kSendRecv),
2038 webrtc::RtpHeaderExtensionCapability("uri2", 2,
2039 RtpTransceiverDirection::kStopped)};
2040 auto offer2 = f1_.CreateOffer(opts, offer.get());
2041 EXPECT_THAT(
2042 offer2->contents(),
2043 ElementsAre(Property(
2044 &ContentInfo::media_description,
2045 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2046 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2047 Field(&RtpExtension::uri, "uri2")))))));
2048}
2049
2050TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002051 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07002052 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002053 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002054
2055 f1_.set_enable_encrypted_rtp_header_extensions(true);
2056 f2_.set_enable_encrypted_rtp_header_extensions(true);
2057
Markus Handell755c65d2020-06-24 01:06:10 +02002058 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2059 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002060 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002061 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002062 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2063 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002064 std::unique_ptr<SessionDescription> answer =
2065 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002066
Yves Gerey665174f2018-06-19 15:03:05 +02002067 EXPECT_EQ(
2068 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2069 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2070 EXPECT_EQ(
2071 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2072 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2073 EXPECT_EQ(
2074 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
2075 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2076 EXPECT_EQ(
2077 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
2078 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002079}
2080
2081TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002082 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07002083 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002084 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002085
2086 f1_.set_enable_encrypted_rtp_header_extensions(true);
2087
Markus Handell755c65d2020-06-24 01:06:10 +02002088 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2089 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002090 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002091 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002092 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2093 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002094 std::unique_ptr<SessionDescription> answer =
2095 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002096
Yves Gerey665174f2018-06-19 15:03:05 +02002097 EXPECT_EQ(
2098 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2099 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2100 EXPECT_EQ(
2101 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2102 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2103 EXPECT_EQ(
2104 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2105 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2106 EXPECT_EQ(
2107 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2108 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002109}
2110
2111TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002112 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07002113 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002114 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002115
2116 f2_.set_enable_encrypted_rtp_header_extensions(true);
2117
Markus Handell755c65d2020-06-24 01:06:10 +02002118 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2119 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002120 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002121 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002122 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2123 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002124 std::unique_ptr<SessionDescription> answer =
2125 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002126
Yves Gerey665174f2018-06-19 15:03:05 +02002127 EXPECT_EQ(
2128 MAKE_VECTOR(kAudioRtpExtension1),
2129 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2130 EXPECT_EQ(
2131 MAKE_VECTOR(kVideoRtpExtension1),
2132 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2133 EXPECT_EQ(
2134 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2135 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2136 EXPECT_EQ(
2137 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2138 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002139}
2140
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002141// Create an audio, video, data answer without legacy StreamParams.
2142TEST_F(MediaSessionDescriptionFactoryTest,
2143 TestCreateAnswerWithoutLegacyStreams) {
2144 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002145 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002146 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002147 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002148 std::unique_ptr<SessionDescription> answer =
2149 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002150 const ContentInfo* ac = answer->GetContentByName("audio");
2151 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002152 ASSERT_TRUE(ac != NULL);
2153 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002154 const AudioContentDescription* acd = ac->media_description()->as_audio();
2155 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002156
2157 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2158 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002159}
2160
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002161// Create a typical video answer, and ensure it matches what we expect.
2162TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2163 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002164 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002165
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002166 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002167 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002168
kwiberg31022942016-03-11 14:18:21 -08002169 std::unique_ptr<SessionDescription> offer;
2170 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171
2172 offer_opts.rtcp_mux_enabled = true;
2173 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002174 offer = f1_.CreateOffer(offer_opts, NULL);
2175 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002176 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2177 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2179 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002180 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2181 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002182 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2183 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002184
2185 offer_opts.rtcp_mux_enabled = true;
2186 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002187 offer = f1_.CreateOffer(offer_opts, NULL);
2188 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002189 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2190 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002191 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2192 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002193 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2194 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002195 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2196 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197
2198 offer_opts.rtcp_mux_enabled = false;
2199 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002200 offer = f1_.CreateOffer(offer_opts, NULL);
2201 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002202 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2203 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002204 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2205 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002206 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2207 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002208 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2209 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002210
2211 offer_opts.rtcp_mux_enabled = false;
2212 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002213 offer = f1_.CreateOffer(offer_opts, NULL);
2214 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002215 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2216 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002217 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2218 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002219 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2220 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002221 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2222 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002223}
2224
2225// Create an audio-only answer to a video offer.
2226TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2227 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002228 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2229 RtpTransceiverDirection::kRecvOnly, kActive,
2230 &opts);
2231 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2232 RtpTransceiverDirection::kRecvOnly, kActive,
2233 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002234 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002235 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002236
2237 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002238 std::unique_ptr<SessionDescription> answer =
2239 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002240 const ContentInfo* ac = answer->GetContentByName("audio");
2241 const ContentInfo* vc = answer->GetContentByName("video");
2242 ASSERT_TRUE(ac != NULL);
2243 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002244 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002245 EXPECT_TRUE(vc->rejected);
2246}
2247
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002248// Create an answer that rejects the contents which are rejected in the offer.
2249TEST_F(MediaSessionDescriptionFactoryTest,
2250 CreateAnswerToOfferWithRejectedMedia) {
2251 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002252 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002253 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002254 ASSERT_TRUE(offer.get() != NULL);
2255 ContentInfo* ac = offer->GetContentByName("audio");
2256 ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002257 ASSERT_TRUE(ac != NULL);
2258 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002259 ac->rejected = true;
2260 vc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002261 std::unique_ptr<SessionDescription> answer =
2262 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002263 ac = answer->GetContentByName("audio");
2264 vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002265 ASSERT_TRUE(ac != NULL);
2266 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002267 EXPECT_TRUE(ac->rejected);
2268 EXPECT_TRUE(vc->rejected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002269}
2270
Johannes Kron0854eb62018-10-10 22:33:20 +02002271TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002272 OfferAndAnswerDoesNotHaveMixedByteSessionAttribute) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002273 MediaSessionOptions opts;
Emil Lundmark801c9992021-01-19 13:06:32 +01002274 std::unique_ptr<SessionDescription> offer =
2275 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002276 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002277
Emil Lundmark801c9992021-01-19 13:06:32 +01002278 std::unique_ptr<SessionDescription> answer(
2279 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2280
2281 EXPECT_FALSE(answer->extmap_allow_mixed());
2282}
2283
2284TEST_F(MediaSessionDescriptionFactoryTest,
2285 OfferAndAnswerHaveMixedByteSessionAttribute) {
2286 MediaSessionOptions opts;
2287 std::unique_ptr<SessionDescription> offer =
2288 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002289 offer->set_extmap_allow_mixed(true);
Emil Lundmark801c9992021-01-19 13:06:32 +01002290
Johannes Kron0854eb62018-10-10 22:33:20 +02002291 std::unique_ptr<SessionDescription> answer_support(
Emil Lundmark801c9992021-01-19 13:06:32 +01002292 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2293
Johannes Kron9581bc42018-10-23 10:17:39 +02002294 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002295}
2296
2297TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002298 OfferAndAnswerDoesNotHaveMixedByteMediaAttributes) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002299 MediaSessionOptions opts;
2300 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Emil Lundmark801c9992021-01-19 13:06:32 +01002301 std::unique_ptr<SessionDescription> offer =
2302 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2303 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002304 MediaContentDescription* audio_offer =
2305 offer->GetContentDescriptionByName("audio");
Emil Lundmark801c9992021-01-19 13:06:32 +01002306 MediaContentDescription* video_offer =
2307 offer->GetContentDescriptionByName("video");
2308 ASSERT_EQ(MediaContentDescription::kNo,
2309 audio_offer->extmap_allow_mixed_enum());
2310 ASSERT_EQ(MediaContentDescription::kNo,
2311 video_offer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002312
Emil Lundmark801c9992021-01-19 13:06:32 +01002313 std::unique_ptr<SessionDescription> answer(
2314 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
Johannes Kron0854eb62018-10-10 22:33:20 +02002315
Johannes Kron0854eb62018-10-10 22:33:20 +02002316 MediaContentDescription* audio_answer =
Emil Lundmark801c9992021-01-19 13:06:32 +01002317 answer->GetContentDescriptionByName("audio");
2318 MediaContentDescription* video_answer =
2319 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002320 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002321 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002322 EXPECT_EQ(MediaContentDescription::kNo,
2323 video_answer->extmap_allow_mixed_enum());
2324}
Johannes Kron0854eb62018-10-10 22:33:20 +02002325
Emil Lundmark801c9992021-01-19 13:06:32 +01002326TEST_F(MediaSessionDescriptionFactoryTest,
2327 OfferAndAnswerHaveSameMixedByteMediaAttributes) {
2328 MediaSessionOptions opts;
2329 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2330 std::unique_ptr<SessionDescription> offer =
2331 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2332 offer->set_extmap_allow_mixed(false);
2333 MediaContentDescription* audio_offer =
2334 offer->GetContentDescriptionByName("audio");
Johannes Kron9581bc42018-10-23 10:17:39 +02002335 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Emil Lundmark801c9992021-01-19 13:06:32 +01002336 MediaContentDescription* video_offer =
2337 offer->GetContentDescriptionByName("video");
2338 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2339
2340 std::unique_ptr<SessionDescription> answer(
2341 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2342
2343 MediaContentDescription* audio_answer =
2344 answer->GetContentDescriptionByName("audio");
2345 MediaContentDescription* video_answer =
2346 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002347 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002348 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002349 EXPECT_EQ(MediaContentDescription::kMedia,
2350 video_answer->extmap_allow_mixed_enum());
2351}
2352
2353TEST_F(MediaSessionDescriptionFactoryTest,
2354 OfferAndAnswerHaveDifferentMixedByteMediaAttributes) {
2355 MediaSessionOptions opts;
2356 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2357 std::unique_ptr<SessionDescription> offer =
2358 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2359 offer->set_extmap_allow_mixed(false);
2360 MediaContentDescription* audio_offer =
2361 offer->GetContentDescriptionByName("audio");
2362 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2363 MediaContentDescription* video_offer =
2364 offer->GetContentDescriptionByName("video");
2365 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2366
2367 std::unique_ptr<SessionDescription> answer(
2368 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2369
2370 MediaContentDescription* audio_answer =
2371 answer->GetContentDescriptionByName("audio");
2372 MediaContentDescription* video_answer =
2373 answer->GetContentDescriptionByName("video");
2374 EXPECT_EQ(MediaContentDescription::kNo,
2375 audio_answer->extmap_allow_mixed_enum());
2376 EXPECT_EQ(MediaContentDescription::kMedia,
2377 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002378}
2379
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002380// Create an audio and video offer with:
2381// - one video track
2382// - two audio tracks
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383// and ensure it matches what we expect. Also updates the initial offer by
2384// adding a new video track and replaces one of the audio tracks.
2385TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2386 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002387 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002388 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2389 {kMediaStream1}, 1, &opts);
2390 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2391 {kMediaStream1}, 1, &opts);
2392 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2393 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002394
Harald Alvestrand0d018412021-11-04 13:52:31 +00002395 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002396 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002397
2398 ASSERT_TRUE(offer.get() != NULL);
2399 const ContentInfo* ac = offer->GetContentByName("audio");
2400 const ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002401 ASSERT_TRUE(ac != NULL);
2402 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002403 const AudioContentDescription* acd = ac->media_description()->as_audio();
2404 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002405 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002406 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002407
2408 const StreamParamsVec& audio_streams = acd->streams();
2409 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002410 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002411 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2412 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2413 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2414 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2415 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2416 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2417
2418 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2419 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +00002420 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002421
2422 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002423 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002424 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002425
2426 const StreamParamsVec& video_streams = vcd->streams();
2427 ASSERT_EQ(1U, video_streams.size());
2428 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2429 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2430 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2431 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2432
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002433 // Update the offer. Add a new video track that is not synched to the
2434 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002435 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2436 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002437 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002438 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2439 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002440 std::unique_ptr<SessionDescription> updated_offer(
2441 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002442
2443 ASSERT_TRUE(updated_offer.get() != NULL);
2444 ac = updated_offer->GetContentByName("audio");
2445 vc = updated_offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002446 ASSERT_TRUE(ac != NULL);
2447 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002448 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002449 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002450 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002451 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002452
2453 EXPECT_EQ(acd->type(), updated_acd->type());
2454 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2455 EXPECT_EQ(vcd->type(), updated_vcd->type());
2456 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002457 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2458 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2459 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2460 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002461
2462 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2463 ASSERT_EQ(2U, updated_audio_streams.size());
2464 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2465 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2466 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2467 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2468 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2469
2470 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2471 ASSERT_EQ(2U, updated_video_streams.size());
2472 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2473 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002474 // All the media streams in one PeerConnection share one RTCP CNAME.
2475 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002476}
2477
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002478// Create an offer with simulcast video stream.
2479TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2480 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002481 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2482 RtpTransceiverDirection::kRecvOnly, kActive,
2483 &opts);
2484 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2485 RtpTransceiverDirection::kSendRecv, kActive,
2486 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002487 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002488 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2489 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002490 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002491
2492 ASSERT_TRUE(offer.get() != NULL);
2493 const ContentInfo* vc = offer->GetContentByName("video");
2494 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002495 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002496
2497 const StreamParamsVec& video_streams = vcd->streams();
2498 ASSERT_EQ(1U, video_streams.size());
2499 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2500 const SsrcGroup* sim_ssrc_group =
2501 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2502 ASSERT_TRUE(sim_ssrc_group != NULL);
2503 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2504}
2505
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002506MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2507 const RidDescription& rid1 = ::testing::get<0>(arg);
2508 const RidDescription& rid2 = ::testing::get<1>(arg);
2509 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2510}
2511
2512static void CheckSimulcastInSessionDescription(
2513 const SessionDescription* description,
2514 const std::string& content_name,
2515 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002516 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002517 ASSERT_NE(description, nullptr);
2518 const ContentInfo* content = description->GetContentByName(content_name);
2519 ASSERT_NE(content, nullptr);
2520 const MediaContentDescription* cd = content->media_description();
2521 ASSERT_NE(cd, nullptr);
2522 const StreamParamsVec& streams = cd->streams();
2523 ASSERT_THAT(streams, SizeIs(1));
2524 const StreamParams& stream = streams[0];
2525 ASSERT_THAT(stream.ssrcs, IsEmpty());
2526 EXPECT_TRUE(stream.has_rids());
2527 const std::vector<RidDescription> rids = stream.rids();
2528
2529 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2530
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002531 EXPECT_TRUE(cd->HasSimulcast());
2532 const SimulcastDescription& simulcast = cd->simulcast_description();
2533 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2534 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2535
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002536 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002537}
2538
2539// Create an offer with spec-compliant simulcast video stream.
2540TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2541 MediaSessionOptions opts;
2542 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2543 RtpTransceiverDirection::kSendRecv, kActive,
2544 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002545 std::vector<RidDescription> send_rids;
2546 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2547 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2548 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2549 SimulcastLayerList simulcast_layers;
2550 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2551 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2552 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2553 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2554 {kMediaStream1}, send_rids,
2555 simulcast_layers, 0, &opts);
2556 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2557
2558 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002559 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002560}
2561
2562// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2563// In this scenario, RIDs do not need to be negotiated (there is only one).
2564TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2565 MediaSessionOptions opts;
2566 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2567 RtpTransceiverDirection::kSendRecv, kActive,
2568 &opts);
2569 RidDescription rid("f", RidDirection::kSend);
2570 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2571 {kMediaStream1}, {rid},
2572 SimulcastLayerList(), 0, &opts);
2573 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2574
2575 ASSERT_NE(offer.get(), nullptr);
2576 const ContentInfo* content = offer->GetContentByName("video");
2577 ASSERT_NE(content, nullptr);
2578 const MediaContentDescription* cd = content->media_description();
2579 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002580 const StreamParamsVec& streams = cd->streams();
2581 ASSERT_THAT(streams, SizeIs(1));
2582 const StreamParams& stream = streams[0];
2583 ASSERT_THAT(stream.ssrcs, IsEmpty());
2584 EXPECT_FALSE(stream.has_rids());
2585 EXPECT_FALSE(cd->HasSimulcast());
2586}
2587
2588// Create an answer with spec-compliant simulcast video stream.
2589// In this scenario, the SFU is the caller requesting that we send Simulcast.
2590TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2591 MediaSessionOptions offer_opts;
2592 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2593 RtpTransceiverDirection::kSendRecv, kActive,
2594 &offer_opts);
2595 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2596 {kMediaStream1}, 1, &offer_opts);
2597 std::unique_ptr<SessionDescription> offer =
2598 f1_.CreateOffer(offer_opts, nullptr);
2599
2600 MediaSessionOptions answer_opts;
2601 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2602 RtpTransceiverDirection::kSendRecv, kActive,
2603 &answer_opts);
2604
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002605 std::vector<RidDescription> rid_descriptions{
2606 RidDescription("f", RidDirection::kSend),
2607 RidDescription("h", RidDirection::kSend),
2608 RidDescription("q", RidDirection::kSend),
2609 };
2610 SimulcastLayerList simulcast_layers;
2611 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2612 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2613 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2614 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2615 {kMediaStream1}, rid_descriptions,
2616 simulcast_layers, 0, &answer_opts);
2617 std::unique_ptr<SessionDescription> answer =
2618 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2619
2620 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002621 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002622}
2623
2624// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2625// In this scenario, RIDs do not need to be negotiated (there is only one).
2626// Note that RID Direction is not the same as the transceiver direction.
2627TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2628 MediaSessionOptions offer_opts;
2629 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2630 RtpTransceiverDirection::kSendRecv, kActive,
2631 &offer_opts);
2632 RidDescription rid_offer("f", RidDirection::kSend);
2633 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2634 {kMediaStream1}, {rid_offer},
2635 SimulcastLayerList(), 0, &offer_opts);
2636 std::unique_ptr<SessionDescription> offer =
2637 f1_.CreateOffer(offer_opts, nullptr);
2638
2639 MediaSessionOptions answer_opts;
2640 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2641 RtpTransceiverDirection::kSendRecv, kActive,
2642 &answer_opts);
2643
2644 RidDescription rid_answer("f", RidDirection::kReceive);
2645 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2646 {kMediaStream1}, {rid_answer},
2647 SimulcastLayerList(), 0, &answer_opts);
2648 std::unique_ptr<SessionDescription> answer =
2649 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2650
2651 ASSERT_NE(answer.get(), nullptr);
2652 const ContentInfo* content = offer->GetContentByName("video");
2653 ASSERT_NE(content, nullptr);
2654 const MediaContentDescription* cd = content->media_description();
2655 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002656 const StreamParamsVec& streams = cd->streams();
2657 ASSERT_THAT(streams, SizeIs(1));
2658 const StreamParams& stream = streams[0];
2659 ASSERT_THAT(stream.ssrcs, IsEmpty());
2660 EXPECT_FALSE(stream.has_rids());
2661 EXPECT_FALSE(cd->HasSimulcast());
2662}
2663
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002664// Create an audio and video answer to a standard video offer with:
2665// - one video track
2666// - two audio tracks
2667// - two data tracks
2668// and ensure it matches what we expect. Also updates the initial answer by
2669// adding a new video track and removes one of the audio tracks.
2670TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2671 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002672 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2673 RtpTransceiverDirection::kRecvOnly, kActive,
2674 &offer_opts);
2675 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2676 RtpTransceiverDirection::kRecvOnly, kActive,
2677 &offer_opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00002678 f1_.set_secure(SEC_ENABLED);
2679 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002680 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002681
zhihuang1c378ed2017-08-17 14:10:50 -07002682 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002683 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2684 RtpTransceiverDirection::kSendRecv, kActive,
2685 &answer_opts);
2686 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2687 RtpTransceiverDirection::kSendRecv, kActive,
2688 &answer_opts);
2689 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2690 {kMediaStream1}, 1, &answer_opts);
2691 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2692 {kMediaStream1}, 1, &answer_opts);
2693 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2694 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002695
Steve Anton6fe1fba2018-12-11 10:15:23 -08002696 std::unique_ptr<SessionDescription> answer =
2697 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002698
2699 ASSERT_TRUE(answer.get() != NULL);
2700 const ContentInfo* ac = answer->GetContentByName("audio");
2701 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002702 ASSERT_TRUE(ac != NULL);
2703 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002704 const AudioContentDescription* acd = ac->media_description()->as_audio();
2705 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand0d018412021-11-04 13:52:31 +00002706 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2707 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002708
2709 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002710 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711
2712 const StreamParamsVec& audio_streams = acd->streams();
2713 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002714 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002715 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2716 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2717 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2718 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2719 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2720 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2721
2722 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2723 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2724
2725 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002726 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002727
2728 const StreamParamsVec& video_streams = vcd->streams();
2729 ASSERT_EQ(1U, video_streams.size());
2730 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2731 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2732 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2733 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2734
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002735 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002736 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002737 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2738 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002739 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002740 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002741 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002742
2743 ASSERT_TRUE(updated_answer.get() != NULL);
2744 ac = updated_answer->GetContentByName("audio");
2745 vc = updated_answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002746 ASSERT_TRUE(ac != NULL);
2747 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002748 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002749 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002750 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002751 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002752
Harald Alvestrand0d018412021-11-04 13:52:31 +00002753 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2754 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2755 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2756 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
2757
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758 EXPECT_EQ(acd->type(), updated_acd->type());
2759 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2760 EXPECT_EQ(vcd->type(), updated_vcd->type());
2761 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002762
2763 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2764 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002765 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002766
2767 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2768 ASSERT_EQ(2U, updated_video_streams.size());
2769 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2770 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002771 // All media streams in one PeerConnection share one CNAME.
2772 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002773}
2774
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002775// Create an updated offer after creating an answer to the original offer and
2776// verify that the codecs that were part of the original answer are not changed
2777// in the updated offer.
2778TEST_F(MediaSessionDescriptionFactoryTest,
2779 RespondentCreatesOfferAfterCreatingAnswer) {
2780 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002781 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002782
Steve Anton6fe1fba2018-12-11 10:15:23 -08002783 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2784 std::unique_ptr<SessionDescription> answer =
2785 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786
2787 const AudioContentDescription* acd =
2788 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002789 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002790
2791 const VideoContentDescription* vcd =
2792 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002793 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002794
kwiberg31022942016-03-11 14:18:21 -08002795 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002796 f2_.CreateOffer(opts, answer.get()));
2797
2798 // The expected audio codecs are the common audio codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002799 // offer/answer exchange plus the audio codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002800 // preference order.
Artem Titov880fa812021-07-30 22:30:23 +02002801 // TODO(wu): `updated_offer` should not include the codec
Artem Titovcfea2182021-08-10 01:22:31 +02002802 // (i.e. `kAudioCodecs2[0]`) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002803 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002804 kAudioCodecsAnswer[0],
2805 kAudioCodecsAnswer[1],
2806 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002807 };
2808
2809 // The expected video codecs are the common video codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002810 // offer/answer exchange plus the video codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002811 // preference order.
2812 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002813 kVideoCodecsAnswer[0],
2814 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002815 };
2816
2817 const AudioContentDescription* updated_acd =
2818 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002819 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002820
2821 const VideoContentDescription* updated_vcd =
2822 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002823 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002824}
2825
Steve Anton5c72e712018-12-10 14:25:30 -08002826// Test that a reoffer does not reuse audio codecs from a previous media section
2827// that is being recycled.
2828TEST_F(MediaSessionDescriptionFactoryTest,
2829 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002830 f1_.set_video_codecs({}, {});
2831 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002832
2833 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002834 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2835 RtpTransceiverDirection::kSendRecv, kActive,
2836 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002837 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2838 std::unique_ptr<SessionDescription> answer =
2839 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002840
2841 // Recycle the media section by changing its mid.
2842 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002843 std::unique_ptr<SessionDescription> reoffer =
2844 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002845
2846 // Expect that the results of the first negotiation are ignored. If the m=
2847 // section was not recycled the payload types would match the initial offerer.
2848 const AudioContentDescription* acd =
2849 GetFirstAudioContentDescription(reoffer.get());
2850 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2851}
2852
2853// Test that a reoffer does not reuse video codecs from a previous media section
2854// that is being recycled.
2855TEST_F(MediaSessionDescriptionFactoryTest,
2856 ReOfferDoesNotReUseRecycledVideoCodecs) {
2857 f1_.set_audio_codecs({}, {});
2858 f2_.set_audio_codecs({}, {});
2859
2860 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002861 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2862 RtpTransceiverDirection::kSendRecv, kActive,
2863 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002864 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2865 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002866
2867 // Recycle the media section by changing its mid.
2868 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002869 std::unique_ptr<SessionDescription> reoffer =
2870 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002871
2872 // Expect that the results of the first negotiation are ignored. If the m=
2873 // section was not recycled the payload types would match the initial offerer.
2874 const VideoContentDescription* vcd =
2875 GetFirstVideoContentDescription(reoffer.get());
2876 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2877}
2878
2879// Test that a reanswer does not reuse audio codecs from a previous media
2880// section that is being recycled.
2881TEST_F(MediaSessionDescriptionFactoryTest,
2882 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002883 f1_.set_video_codecs({}, {});
2884 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002885
Artem Titov880fa812021-07-30 22:30:23 +02002886 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2887 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002888 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002889 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2890 RtpTransceiverDirection::kSendRecv, kActive,
2891 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002892 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2893 std::unique_ptr<SessionDescription> answer =
2894 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002895
2896 // Recycle the media section by changing its mid.
2897 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002898 std::unique_ptr<SessionDescription> reoffer =
2899 f1_.CreateOffer(opts, answer.get());
2900 std::unique_ptr<SessionDescription> reanswer =
2901 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002902
2903 // Expect that the results of the first negotiation are ignored. If the m=
2904 // section was not recycled the payload types would match the initial offerer.
2905 const AudioContentDescription* acd =
2906 GetFirstAudioContentDescription(reanswer.get());
2907 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2908}
2909
2910// Test that a reanswer does not reuse video codecs from a previous media
2911// section that is being recycled.
2912TEST_F(MediaSessionDescriptionFactoryTest,
2913 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2914 f1_.set_audio_codecs({}, {});
2915 f2_.set_audio_codecs({}, {});
2916
Artem Titov880fa812021-07-30 22:30:23 +02002917 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2918 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002919 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002920 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2921 RtpTransceiverDirection::kSendRecv, kActive,
2922 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002923 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2924 std::unique_ptr<SessionDescription> answer =
2925 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002926
2927 // Recycle the media section by changing its mid.
2928 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002929 std::unique_ptr<SessionDescription> reoffer =
2930 f1_.CreateOffer(opts, answer.get());
2931 std::unique_ptr<SessionDescription> reanswer =
2932 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002933
2934 // Expect that the results of the first negotiation are ignored. If the m=
2935 // section was not recycled the payload types would match the initial offerer.
2936 const VideoContentDescription* vcd =
2937 GetFirstVideoContentDescription(reanswer.get());
2938 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2939}
2940
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002941// Create an updated offer after creating an answer to the original offer and
2942// verify that the codecs that were part of the original answer are not changed
2943// in the updated offer. In this test Rtx is enabled.
2944TEST_F(MediaSessionDescriptionFactoryTest,
2945 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2946 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002947 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2948 RtpTransceiverDirection::kRecvOnly, kActive,
2949 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002950 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02002951 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002952 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002953 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002954
2955 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02002956 // This creates rtx for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002957 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002958 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002959
Steve Anton6fe1fba2018-12-11 10:15:23 -08002960 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002961 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002962 std::unique_ptr<SessionDescription> answer =
2963 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002964
2965 const VideoContentDescription* vcd =
2966 GetFirstVideoContentDescription(answer.get());
2967
2968 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002969 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2970 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002971
2972 EXPECT_EQ(expected_codecs, vcd->codecs());
2973
Artem Titov880fa812021-07-30 22:30:23 +02002974 // Now, make sure we get same result (except for the order) if `f2_` creates
2975 // an updated offer even though the default payload types between `f1_` and
2976 // `f2_` are different.
kwiberg31022942016-03-11 14:18:21 -08002977 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002978 f2_.CreateOffer(opts, answer.get()));
2979 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002980 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002981 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2982
2983 const VideoContentDescription* updated_vcd =
2984 GetFirstVideoContentDescription(updated_answer.get());
2985
2986 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2987}
2988
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002989// Regression test for:
2990// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2991// Existing codecs should always appear before new codecs in re-offers. But
2992// under a specific set of circumstances, the existing RTX codec was ending up
2993// added to the end of the list.
2994TEST_F(MediaSessionDescriptionFactoryTest,
2995 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2996 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002997 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2998 RtpTransceiverDirection::kRecvOnly, kActive,
2999 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003000 // We specifically choose different preferred payload types for VP8 to
3001 // trigger the issue.
3002 cricket::VideoCodec vp8_offerer(100, "VP8");
3003 cricket::VideoCodec vp8_offerer_rtx =
3004 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
3005 cricket::VideoCodec vp8_answerer(110, "VP8");
3006 cricket::VideoCodec vp8_answerer_rtx =
3007 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
3008 cricket::VideoCodec vp9(120, "VP9");
3009 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
3010
3011 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
3012 // We also specifically cause the answerer to prefer VP9, such that if it
3013 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
3014 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
3015 vp8_answerer_rtx};
3016
Johannes Kron3e983682020-03-29 22:17:00 +02003017 f1_.set_video_codecs(f1_codecs, f1_codecs);
3018 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003019 std::vector<AudioCodec> audio_codecs;
3020 f1_.set_audio_codecs(audio_codecs, audio_codecs);
3021 f2_.set_audio_codecs(audio_codecs, audio_codecs);
3022
3023 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003024 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003025 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003026 std::unique_ptr<SessionDescription> answer =
3027 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003028
3029 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
3030 // But if the bug is triggered, RTX for VP8 ends up last.
3031 std::unique_ptr<SessionDescription> updated_offer(
3032 f2_.CreateOffer(opts, answer.get()));
3033
3034 const VideoContentDescription* vcd =
3035 GetFirstVideoContentDescription(updated_offer.get());
3036 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
3037 ASSERT_EQ(4u, codecs.size());
3038 EXPECT_EQ(vp8_offerer, codecs[0]);
3039 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
3040 EXPECT_EQ(vp9, codecs[2]);
3041 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003042}
3043
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003044// Create an updated offer that adds video after creating an audio only answer
3045// to the original offer. This test verifies that if a video codec and the RTX
3046// codec have the same default payload type as an audio codec that is already in
3047// use, the added codecs payload types are changed.
3048TEST_F(MediaSessionDescriptionFactoryTest,
3049 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
3050 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02003051 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003052 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003053 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003054
3055 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003056 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3057 RtpTransceiverDirection::kRecvOnly, kActive,
3058 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003059
Steve Anton6fe1fba2018-12-11 10:15:23 -08003060 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3061 std::unique_ptr<SessionDescription> answer =
3062 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003063
3064 const AudioContentDescription* acd =
3065 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003066 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003067
Artem Titov880fa812021-07-30 22:30:23 +02003068 // Now - let `f2_` add video with RTX and let the payload type the RTX codec
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003069 // reference be the same as an audio codec that was negotiated in the
3070 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07003071 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08003072 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003073
3074 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3075 int used_pl_type = acd->codecs()[0].id;
3076 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003077 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003078 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003079
kwiberg31022942016-03-11 14:18:21 -08003080 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003081 f2_.CreateOffer(opts, answer.get()));
3082 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003083 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003084 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3085
3086 const AudioContentDescription* updated_acd =
3087 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003088 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003089
3090 const VideoContentDescription* updated_vcd =
3091 GetFirstVideoContentDescription(updated_answer.get());
3092
3093 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003094 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003095 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003096 EXPECT_NE(used_pl_type, new_h264_pl_type);
3097 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003098 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003099 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3100 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3101}
3102
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003103// Create an updated offer with RTX after creating an answer to an offer
3104// without RTX, and with different default payload types.
3105// Verify that the added RTX codec references the correct payload type.
3106TEST_F(MediaSessionDescriptionFactoryTest,
3107 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3108 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003109 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003110
3111 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003112 // This creates rtx for H264 with the payload type `f2_` uses.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003113 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003114 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003115
Steve Anton6fe1fba2018-12-11 10:15:23 -08003116 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003117 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003118 std::unique_ptr<SessionDescription> answer =
3119 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003120
3121 const VideoContentDescription* vcd =
3122 GetFirstVideoContentDescription(answer.get());
3123
3124 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3125 EXPECT_EQ(expected_codecs, vcd->codecs());
3126
Artem Titov880fa812021-07-30 22:30:23 +02003127 // Now, ensure that the RTX codec is created correctly when `f2_` creates an
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003128 // updated offer, even though the default payload types are different from
Artem Titov880fa812021-07-30 22:30:23 +02003129 // those of `f1_`.
kwiberg31022942016-03-11 14:18:21 -08003130 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003131 f2_.CreateOffer(opts, answer.get()));
3132 ASSERT_TRUE(updated_offer);
3133
3134 const VideoContentDescription* updated_vcd =
3135 GetFirstVideoContentDescription(updated_offer.get());
3136
3137 // New offer should attempt to add H263, and RTX for H264.
3138 expected_codecs.push_back(kVideoCodecs2[1]);
3139 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3140 &expected_codecs);
3141 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3142}
3143
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003144// Test that RTX is ignored when there is no associated payload type parameter.
3145TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3146 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003147 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3148 RtpTransceiverDirection::kRecvOnly, kActive,
3149 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003150 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003151 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003152 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003153 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003154
3155 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003156 // This creates RTX for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003157 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003158 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003159
Steve Anton6fe1fba2018-12-11 10:15:23 -08003160 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003161 ASSERT_TRUE(offer.get() != NULL);
3162 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3163 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3164 // is possible to test that that RTX is dropped when
3165 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003166 MediaContentDescription* media_desc =
3167 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3168 ASSERT_TRUE(media_desc);
3169 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003170 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003171 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003172 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003173 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003174 }
3175 }
3176 desc->set_codecs(codecs);
3177
Steve Anton6fe1fba2018-12-11 10:15:23 -08003178 std::unique_ptr<SessionDescription> answer =
3179 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003180
Steve Anton64b626b2019-01-28 17:25:26 -08003181 EXPECT_THAT(
3182 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3183 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003184}
3185
3186// Test that RTX will be filtered out in the answer if its associated payload
3187// type doesn't match the local value.
3188TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3189 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003190 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3191 RtpTransceiverDirection::kRecvOnly, kActive,
3192 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003193 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3194 // This creates RTX for H264 in sender.
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);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003197
3198 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3199 // This creates RTX for H263 in receiver.
3200 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003201 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003202
Steve Anton6fe1fba2018-12-11 10:15:23 -08003203 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003204 ASSERT_TRUE(offer.get() != NULL);
3205 // Associated payload type doesn't match, therefore, RTX codec is removed in
3206 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003207 std::unique_ptr<SessionDescription> answer =
3208 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003209
Steve Anton64b626b2019-01-28 17:25:26 -08003210 EXPECT_THAT(
3211 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3212 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003213}
3214
3215// Test that when multiple RTX codecs are offered, only the matched RTX codec
3216// is added in the answer, and the unsupported RTX codec is filtered out.
3217TEST_F(MediaSessionDescriptionFactoryTest,
3218 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3219 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003220 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3221 RtpTransceiverDirection::kRecvOnly, kActive,
3222 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003223 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3224 // This creates RTX for H264-SVC in sender.
3225 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003226 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003227
3228 // This creates RTX for H264 in sender.
3229 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003230 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003231
3232 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3233 // This creates RTX for H264 in receiver.
3234 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003235 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003236
3237 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3238 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003239 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003240 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003241 std::unique_ptr<SessionDescription> answer =
3242 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003243 const VideoContentDescription* vcd =
3244 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003245 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3246 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3247 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003248
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003249 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003250}
3251
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003252// Test that after one RTX codec has been negotiated, a new offer can attempt
3253// to add another.
3254TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3255 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003256 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3257 RtpTransceiverDirection::kRecvOnly, kActive,
3258 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003259 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3260 // This creates RTX for H264 for the offerer.
3261 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003262 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003263
Steve Anton6fe1fba2018-12-11 10:15:23 -08003264 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003265 ASSERT_TRUE(offer);
3266 const VideoContentDescription* vcd =
3267 GetFirstVideoContentDescription(offer.get());
3268
3269 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3270 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3271 &expected_codecs);
3272 EXPECT_EQ(expected_codecs, vcd->codecs());
3273
3274 // Now, attempt to add RTX for H264-SVC.
3275 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003276 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003277
kwiberg31022942016-03-11 14:18:21 -08003278 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003279 f1_.CreateOffer(opts, offer.get()));
3280 ASSERT_TRUE(updated_offer);
3281 vcd = GetFirstVideoContentDescription(updated_offer.get());
3282
3283 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3284 &expected_codecs);
3285 EXPECT_EQ(expected_codecs, vcd->codecs());
3286}
3287
Noah Richards2e7a0982015-05-18 14:02:54 -07003288// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3289// generated for each simulcast ssrc and correctly grouped.
3290TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3291 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003292 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3293 RtpTransceiverDirection::kSendRecv, kActive,
3294 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003295 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003296 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3297 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003298
3299 // Use a single real codec, and then add RTX for it.
3300 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003301 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003302 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003303 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003304
3305 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3306 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003307 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003308 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003309 MediaContentDescription* media_desc =
3310 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3311 ASSERT_TRUE(media_desc);
3312 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003313 const StreamParamsVec& streams = desc->streams();
3314 // Single stream.
3315 ASSERT_EQ(1u, streams.size());
3316 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3317 EXPECT_EQ(6u, streams[0].ssrcs.size());
3318 // And should have a SIM group for the simulcast.
3319 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3320 // And a FID group for RTX.
3321 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003322 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003323 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3324 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003325 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003326 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3327 EXPECT_EQ(3u, fid_ssrcs.size());
3328}
3329
brandtr03d5fb12016-11-22 03:37:59 -08003330// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003331// together with a FEC-FR grouping. Guarded by WebRTC-FlexFEC-03 trial.
brandtr03d5fb12016-11-22 03:37:59 -08003332TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01003333 webrtc::test::ScopedKeyValueConfig override_field_trials(
3334 field_trials, "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003335 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003336 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3337 RtpTransceiverDirection::kSendRecv, kActive,
3338 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003339 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003340 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3341 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003342
3343 // Use a single real codec, and then add FlexFEC for it.
3344 std::vector<VideoCodec> f1_codecs;
3345 f1_codecs.push_back(VideoCodec(97, "H264"));
3346 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003347 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003348
3349 // Ensure that the offer has a single FlexFEC ssrc and that
3350 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003351 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003352 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003353 MediaContentDescription* media_desc =
3354 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3355 ASSERT_TRUE(media_desc);
3356 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003357 const StreamParamsVec& streams = desc->streams();
3358 // Single stream.
3359 ASSERT_EQ(1u, streams.size());
3360 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3361 EXPECT_EQ(2u, streams[0].ssrcs.size());
3362 // And should have a FEC-FR group for FlexFEC.
3363 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3364 std::vector<uint32_t> primary_ssrcs;
3365 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3366 ASSERT_EQ(1u, primary_ssrcs.size());
3367 uint32_t flexfec_ssrc;
3368 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3369 EXPECT_NE(flexfec_ssrc, 0u);
3370}
3371
3372// Test that FlexFEC is disabled for simulcast.
3373// TODO(brandtr): Remove this test when we support simulcast, either through
3374// multiple FlexfecSenders, or through multistream protection.
3375TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01003376 webrtc::test::ScopedKeyValueConfig override_field_trials(
3377 field_trials, "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003378 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003379 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3380 RtpTransceiverDirection::kSendRecv, kActive,
3381 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003382 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003383 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3384 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003385
3386 // Use a single real codec, and then add FlexFEC for it.
3387 std::vector<VideoCodec> f1_codecs;
3388 f1_codecs.push_back(VideoCodec(97, "H264"));
3389 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003390 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003391
3392 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3393 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003394 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003395 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003396 MediaContentDescription* media_desc =
3397 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3398 ASSERT_TRUE(media_desc);
3399 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003400 const StreamParamsVec& streams = desc->streams();
3401 // Single stream.
3402 ASSERT_EQ(1u, streams.size());
3403 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3404 EXPECT_EQ(3u, streams[0].ssrcs.size());
3405 // And should have a SIM group for the simulcast.
3406 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3407 // And not a FEC-FR group for FlexFEC.
3408 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3409 std::vector<uint32_t> primary_ssrcs;
3410 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3411 EXPECT_EQ(3u, primary_ssrcs.size());
3412 for (uint32_t primary_ssrc : primary_ssrcs) {
3413 uint32_t flexfec_ssrc;
3414 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3415 }
3416}
3417
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003418// Create an updated offer after creating an answer to the original offer and
3419// verify that the RTP header extensions that were part of the original answer
3420// are not changed in the updated offer.
3421TEST_F(MediaSessionDescriptionFactoryTest,
3422 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3423 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003424 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003425
Markus Handell755c65d2020-06-24 01:06:10 +02003426 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3427 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003428 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02003429 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3430 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003431 std::unique_ptr<SessionDescription> answer =
3432 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003433
Yves Gerey665174f2018-06-19 15:03:05 +02003434 EXPECT_EQ(
3435 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3436 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3437 EXPECT_EQ(
3438 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3439 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003440
kwiberg31022942016-03-11 14:18:21 -08003441 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003442 f2_.CreateOffer(opts, answer.get()));
3443
3444 // The expected RTP header extensions in the new offer are the resulting
3445 // extensions from the first offer/answer exchange plus the extensions only
Artem Titov880fa812021-07-30 22:30:23 +02003446 // `f2_` offer.
3447 // Since the default local extension id `f2_` uses has already been used by
3448 // `f1_` for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003449 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003450 kAudioRtpExtensionAnswer[0],
3451 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003452 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003453 };
3454
Artem Titov880fa812021-07-30 22:30:23 +02003455 // Since the default local extension id `f2_` uses has already been used by
3456 // `f1_` for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003457 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003458 kVideoRtpExtensionAnswer[0],
3459 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003460 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003461 };
3462
3463 const AudioContentDescription* updated_acd =
3464 GetFirstAudioContentDescription(updated_offer.get());
3465 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3466 updated_acd->rtp_header_extensions());
3467
3468 const VideoContentDescription* updated_vcd =
3469 GetFirstVideoContentDescription(updated_offer.get());
3470 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3471 updated_vcd->rtp_header_extensions());
3472}
3473
deadbeefa5b273a2015-08-20 17:30:13 -07003474// Verify that if the same RTP extension URI is used for audio and video, the
3475// same ID is used. Also verify that the ID isn't changed when creating an
3476// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003477TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003478 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003479 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003480
Markus Handell755c65d2020-06-24 01:06:10 +02003481 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3482 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003483 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003484
3485 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3486 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003487 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003488 kVideoRtpExtension3[0],
3489 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003490 };
3491
Yves Gerey665174f2018-06-19 15:03:05 +02003492 EXPECT_EQ(
3493 MAKE_VECTOR(kAudioRtpExtension3),
3494 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3495 EXPECT_EQ(
3496 MAKE_VECTOR(kExpectedVideoRtpExtension),
3497 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003498
3499 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003500 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003501 f1_.CreateOffer(opts, offer.get()));
3502
3503 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003504 GetFirstAudioContentDescription(updated_offer.get())
3505 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003506 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003507 GetFirstVideoContentDescription(updated_offer.get())
3508 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003509}
3510
jbauch5869f502017-06-29 12:31:36 -07003511// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3512TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3513 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003514 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003515
3516 f1_.set_enable_encrypted_rtp_header_extensions(true);
3517 f2_.set_enable_encrypted_rtp_header_extensions(true);
3518
Markus Handell755c65d2020-06-24 01:06:10 +02003519 SetAudioVideoRtpHeaderExtensions(
3520 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3521 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003522 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003523
Yves Gerey665174f2018-06-19 15:03:05 +02003524 EXPECT_EQ(
3525 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3526 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3527 EXPECT_EQ(
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003528 MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003529 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003530
3531 // Nothing should change when creating a new offer
3532 std::unique_ptr<SessionDescription> updated_offer(
3533 f1_.CreateOffer(opts, offer.get()));
3534
3535 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003536 GetFirstAudioContentDescription(updated_offer.get())
3537 ->rtp_header_extensions());
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003538 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003539 GetFirstVideoContentDescription(updated_offer.get())
3540 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003541}
3542
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003543TEST(MediaSessionDescription, CopySessionDescription) {
3544 SessionDescription source;
3545 cricket::ContentGroup group(cricket::CN_AUDIO);
3546 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003547 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003548 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003549 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3550 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003551 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003552 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003553 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003554 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3555 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003556 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003557
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003558 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003559 ASSERT_TRUE(copy.get() != NULL);
3560 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3561 const ContentInfo* ac = copy->GetContentByName("audio");
3562 const ContentInfo* vc = copy->GetContentByName("video");
3563 ASSERT_TRUE(ac != NULL);
3564 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003565 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003566 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003567 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3568 EXPECT_EQ(1u, acd->first_ssrc());
3569
Steve Anton5adfafd2017-12-20 16:34:00 -08003570 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003571 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003572 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3573 EXPECT_EQ(2u, vcd->first_ssrc());
3574}
3575
3576// The below TestTransportInfoXXX tests create different offers/answers, and
3577// ensure the TransportInfo in the SessionDescription matches what we expect.
3578TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3579 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003580 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3581 RtpTransceiverDirection::kRecvOnly, kActive,
3582 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003583 TestTransportInfo(true, options, false);
3584}
3585
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003586TEST_F(MediaSessionDescriptionFactoryTest,
3587 TestTransportInfoOfferIceRenomination) {
3588 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003589 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3590 RtpTransceiverDirection::kRecvOnly, kActive,
3591 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003592 options.media_description_options[0]
3593 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003594 TestTransportInfo(true, options, false);
3595}
3596
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003597TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3598 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003599 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3600 RtpTransceiverDirection::kRecvOnly, kActive,
3601 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003602 TestTransportInfo(true, options, true);
3603}
3604
3605TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3606 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003607 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003608 TestTransportInfo(true, options, false);
3609}
3610
3611TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003612 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003613 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003614 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003615 TestTransportInfo(true, options, true);
3616}
3617
3618TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3619 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003620 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003621 options.bundle_enabled = true;
3622 TestTransportInfo(true, options, false);
3623}
3624
3625TEST_F(MediaSessionDescriptionFactoryTest,
3626 TestTransportInfoOfferBundleCurrent) {
3627 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003628 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003629 options.bundle_enabled = true;
3630 TestTransportInfo(true, options, true);
3631}
3632
3633TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3634 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003635 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3636 RtpTransceiverDirection::kRecvOnly, kActive,
3637 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003638 TestTransportInfo(false, options, false);
3639}
3640
3641TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003642 TestTransportInfoAnswerIceRenomination) {
3643 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003644 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3645 RtpTransceiverDirection::kRecvOnly, kActive,
3646 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003647 options.media_description_options[0]
3648 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003649 TestTransportInfo(false, options, false);
3650}
3651
3652TEST_F(MediaSessionDescriptionFactoryTest,
3653 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003654 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003655 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3656 RtpTransceiverDirection::kRecvOnly, kActive,
3657 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003658 TestTransportInfo(false, options, true);
3659}
3660
3661TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3662 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003663 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003664 TestTransportInfo(false, options, false);
3665}
3666
3667TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003668 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003669 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003670 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003671 TestTransportInfo(false, options, true);
3672}
3673
3674TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3675 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003676 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003677 options.bundle_enabled = true;
3678 TestTransportInfo(false, options, false);
3679}
3680
3681TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003682 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003683 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003684 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003685 options.bundle_enabled = true;
3686 TestTransportInfo(false, options, true);
3687}
3688
Harald Alvestrand0d018412021-11-04 13:52:31 +00003689// Create an offer with bundle enabled and verify the crypto parameters are
3690// the common set of the available cryptos.
3691TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3692 TestCryptoWithBundle(true);
3693}
3694
3695// Create an answer with bundle enabled and verify the crypto parameters are
3696// the common set of the available cryptos.
3697TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3698 TestCryptoWithBundle(false);
3699}
3700
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003701// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3702// DTLS is not enabled locally.
3703TEST_F(MediaSessionDescriptionFactoryTest,
3704 TestOfferDtlsSavpfWithoutDtlsFailed) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003705 f1_.set_secure(SEC_ENABLED);
3706 f2_.set_secure(SEC_ENABLED);
3707 tdf1_.set_secure(SEC_DISABLED);
3708 tdf2_.set_secure(SEC_DISABLED);
3709
Steve Anton6fe1fba2018-12-11 10:15:23 -08003710 std::unique_ptr<SessionDescription> offer =
3711 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003712 ASSERT_TRUE(offer.get() != NULL);
3713 ContentInfo* offer_content = offer->GetContentByName("audio");
3714 ASSERT_TRUE(offer_content != NULL);
3715 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003716 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003717 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3718
Steve Anton6fe1fba2018-12-11 10:15:23 -08003719 std::unique_ptr<SessionDescription> answer =
3720 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003721 ASSERT_TRUE(answer != NULL);
3722 ContentInfo* answer_content = answer->GetContentByName("audio");
3723 ASSERT_TRUE(answer_content != NULL);
3724
3725 ASSERT_TRUE(answer_content->rejected);
3726}
3727
3728// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3729// UDP/TLS/RTP/SAVPF.
3730TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003731 f1_.set_secure(SEC_ENABLED);
3732 f2_.set_secure(SEC_ENABLED);
3733 tdf1_.set_secure(SEC_ENABLED);
3734 tdf2_.set_secure(SEC_ENABLED);
3735
Steve Anton6fe1fba2018-12-11 10:15:23 -08003736 std::unique_ptr<SessionDescription> offer =
3737 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003738 ASSERT_TRUE(offer.get() != NULL);
3739 ContentInfo* offer_content = offer->GetContentByName("audio");
3740 ASSERT_TRUE(offer_content != NULL);
3741 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003742 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003743 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3744
Steve Anton6fe1fba2018-12-11 10:15:23 -08003745 std::unique_ptr<SessionDescription> answer =
3746 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003747 ASSERT_TRUE(answer != NULL);
3748
3749 const ContentInfo* answer_content = answer->GetContentByName("audio");
3750 ASSERT_TRUE(answer_content != NULL);
3751 ASSERT_FALSE(answer_content->rejected);
3752
3753 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003754 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003755 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003756}
3757
Harald Alvestrand0d018412021-11-04 13:52:31 +00003758// Test that we include both SDES and DTLS in the offer, but only include SDES
3759// in the answer if DTLS isn't negotiated.
3760TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3761 f1_.set_secure(SEC_ENABLED);
3762 f2_.set_secure(SEC_ENABLED);
3763 tdf1_.set_secure(SEC_ENABLED);
3764 tdf2_.set_secure(SEC_DISABLED);
3765 MediaSessionOptions options;
3766 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3767 std::unique_ptr<SessionDescription> offer, answer;
3768 const cricket::MediaContentDescription* audio_media_desc;
3769 const cricket::MediaContentDescription* video_media_desc;
3770 const cricket::TransportDescription* audio_trans_desc;
3771 const cricket::TransportDescription* video_trans_desc;
3772
3773 // Generate an offer with SDES and DTLS support.
3774 offer = f1_.CreateOffer(options, NULL);
3775 ASSERT_TRUE(offer.get() != NULL);
3776
3777 audio_media_desc = offer->GetContentDescriptionByName("audio");
3778 ASSERT_TRUE(audio_media_desc != NULL);
3779 video_media_desc = offer->GetContentDescriptionByName("video");
3780 ASSERT_TRUE(video_media_desc != NULL);
3781 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3782 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3783
3784 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3785 ASSERT_TRUE(audio_trans_desc != NULL);
3786 video_trans_desc = offer->GetTransportDescriptionByName("video");
3787 ASSERT_TRUE(video_trans_desc != NULL);
3788 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3789 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3790
3791 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
3792 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3793 ASSERT_TRUE(answer.get() != NULL);
3794
3795 audio_media_desc = answer->GetContentDescriptionByName("audio");
3796 ASSERT_TRUE(audio_media_desc != NULL);
3797 video_media_desc = answer->GetContentDescriptionByName("video");
3798 ASSERT_TRUE(video_media_desc != NULL);
3799 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3800 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3801
3802 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3803 ASSERT_TRUE(audio_trans_desc != NULL);
3804 video_trans_desc = answer->GetTransportDescriptionByName("video");
3805 ASSERT_TRUE(video_trans_desc != NULL);
3806 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3807 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3808
3809 // Enable DTLS; the answer should now only have DTLS support.
3810 tdf2_.set_secure(SEC_ENABLED);
3811 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3812 ASSERT_TRUE(answer.get() != NULL);
3813
3814 audio_media_desc = answer->GetContentDescriptionByName("audio");
3815 ASSERT_TRUE(audio_media_desc != NULL);
3816 video_media_desc = answer->GetContentDescriptionByName("video");
3817 ASSERT_TRUE(video_media_desc != NULL);
3818 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3819 EXPECT_TRUE(video_media_desc->cryptos().empty());
3820 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3821 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
3822
3823 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3824 ASSERT_TRUE(audio_trans_desc != NULL);
3825 video_trans_desc = answer->GetTransportDescriptionByName("video");
3826 ASSERT_TRUE(video_trans_desc != NULL);
3827 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3828 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3829
3830 // Try creating offer again. DTLS enabled now, crypto's should be empty
3831 // in new offer.
3832 offer = f1_.CreateOffer(options, offer.get());
3833 ASSERT_TRUE(offer.get() != NULL);
3834 audio_media_desc = offer->GetContentDescriptionByName("audio");
3835 ASSERT_TRUE(audio_media_desc != NULL);
3836 video_media_desc = offer->GetContentDescriptionByName("video");
3837 ASSERT_TRUE(video_media_desc != NULL);
3838 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3839 EXPECT_TRUE(video_media_desc->cryptos().empty());
3840
3841 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3842 ASSERT_TRUE(audio_trans_desc != NULL);
3843 video_trans_desc = offer->GetTransportDescriptionByName("video");
3844 ASSERT_TRUE(video_trans_desc != NULL);
3845 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3846 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3847}
3848
3849// Test that an answer can't be created if cryptos are required but the offer is
3850// unsecure.
3851TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
3852 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
3853 f1_.set_secure(SEC_DISABLED);
3854 tdf1_.set_secure(SEC_DISABLED);
3855 f2_.set_secure(SEC_REQUIRED);
3856 tdf1_.set_secure(SEC_ENABLED);
3857
3858 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
3859 ASSERT_TRUE(offer.get() != NULL);
3860 std::unique_ptr<SessionDescription> answer =
3861 f2_.CreateAnswer(offer.get(), options, NULL);
3862 EXPECT_TRUE(answer.get() == NULL);
3863}
3864
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003865// Test that we accept a DTLS offer without SDES and create an appropriate
3866// answer.
3867TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003868 f1_.set_secure(SEC_DISABLED);
3869 f2_.set_secure(SEC_ENABLED);
3870 tdf1_.set_secure(SEC_ENABLED);
3871 tdf2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003872 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003873 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003874
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003875 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003876 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003877 ASSERT_TRUE(offer.get() != NULL);
3878
Harald Alvestrand0d018412021-11-04 13:52:31 +00003879 const AudioContentDescription* audio_offer =
3880 GetFirstAudioContentDescription(offer.get());
3881 ASSERT_TRUE(audio_offer->cryptos().empty());
3882 const VideoContentDescription* video_offer =
3883 GetFirstVideoContentDescription(offer.get());
3884 ASSERT_TRUE(video_offer->cryptos().empty());
3885
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003886 const cricket::TransportDescription* audio_offer_trans_desc =
3887 offer->GetTransportDescriptionByName("audio");
3888 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3889 const cricket::TransportDescription* video_offer_trans_desc =
3890 offer->GetTransportDescriptionByName("video");
3891 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003892
3893 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003894 std::unique_ptr<SessionDescription> answer =
3895 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003896 ASSERT_TRUE(answer.get() != NULL);
3897
3898 const cricket::TransportDescription* audio_answer_trans_desc =
3899 answer->GetTransportDescriptionByName("audio");
3900 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3901 const cricket::TransportDescription* video_answer_trans_desc =
3902 answer->GetTransportDescriptionByName("video");
3903 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003904}
3905
3906// Verifies if vad_enabled option is set to false, CN codecs are not present in
3907// offer or answer.
3908TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3909 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003910 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003911 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003912 ASSERT_TRUE(offer.get() != NULL);
3913 const ContentInfo* audio_content = offer->GetContentByName("audio");
3914 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3915
3916 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003917 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003918 ASSERT_TRUE(offer.get() != NULL);
3919 audio_content = offer->GetContentByName("audio");
3920 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003921 std::unique_ptr<SessionDescription> answer =
3922 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003923 ASSERT_TRUE(answer.get() != NULL);
3924 audio_content = answer->GetContentByName("audio");
3925 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3926}
deadbeef44f08192015-12-15 16:20:09 -08003927
zhihuang1c378ed2017-08-17 14:10:50 -07003928// Test that the generated MIDs match the existing offer.
3929TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003930 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003931 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3932 RtpTransceiverDirection::kRecvOnly, kActive,
3933 &opts);
3934 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3935 RtpTransceiverDirection::kRecvOnly, kActive,
3936 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003937 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3938 RtpTransceiverDirection::kSendRecv, kActive,
3939 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003940 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003941 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003942 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003943 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003944
deadbeef44f08192015-12-15 16:20:09 -08003945 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3946 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3947 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3948 ASSERT_TRUE(audio_content != nullptr);
3949 ASSERT_TRUE(video_content != nullptr);
3950 ASSERT_TRUE(data_content != nullptr);
3951 EXPECT_EQ("audio_modified", audio_content->name);
3952 EXPECT_EQ("video_modified", video_content->name);
3953 EXPECT_EQ("data_modified", data_content->name);
3954}
zhihuangcf5b37c2016-05-05 11:44:35 -07003955
zhihuang1c378ed2017-08-17 14:10:50 -07003956// The following tests verify that the unified plan SDP is supported.
3957// Test that we can create an offer with multiple media sections of same media
3958// type.
3959TEST_F(MediaSessionDescriptionFactoryTest,
3960 CreateOfferWithMultipleAVMediaSections) {
3961 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003962 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3963 RtpTransceiverDirection::kSendRecv, kActive,
3964 &opts);
3965 AttachSenderToMediaDescriptionOptions(
3966 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003967
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003968 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3969 RtpTransceiverDirection::kSendRecv, kActive,
3970 &opts);
3971 AttachSenderToMediaDescriptionOptions(
3972 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003973
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003974 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3975 RtpTransceiverDirection::kSendRecv, kActive,
3976 &opts);
3977 AttachSenderToMediaDescriptionOptions(
3978 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003979
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003980 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3981 RtpTransceiverDirection::kSendRecv, kActive,
3982 &opts);
3983 AttachSenderToMediaDescriptionOptions(
3984 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003985 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003986 ASSERT_TRUE(offer);
3987
3988 ASSERT_EQ(4u, offer->contents().size());
3989 EXPECT_FALSE(offer->contents()[0].rejected);
3990 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003991 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003992 ASSERT_EQ(1u, acd->streams().size());
3993 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003994 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003995
3996 EXPECT_FALSE(offer->contents()[1].rejected);
3997 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003998 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003999 ASSERT_EQ(1u, vcd->streams().size());
4000 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004001 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004002
4003 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004004 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004005 ASSERT_EQ(1u, acd->streams().size());
4006 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004007 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004008
4009 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004010 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004011 ASSERT_EQ(1u, vcd->streams().size());
4012 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004013 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004014}
4015
4016// Test that we can create an answer with multiple media sections of same media
4017// type.
4018TEST_F(MediaSessionDescriptionFactoryTest,
4019 CreateAnswerWithMultipleAVMediaSections) {
4020 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004021 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4022 RtpTransceiverDirection::kSendRecv, kActive,
4023 &opts);
4024 AttachSenderToMediaDescriptionOptions(
4025 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004026
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004027 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4028 RtpTransceiverDirection::kSendRecv, kActive,
4029 &opts);
4030 AttachSenderToMediaDescriptionOptions(
4031 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004032
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004033 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4034 RtpTransceiverDirection::kSendRecv, kActive,
4035 &opts);
4036 AttachSenderToMediaDescriptionOptions(
4037 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004038
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004039 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4040 RtpTransceiverDirection::kSendRecv, kActive,
4041 &opts);
4042 AttachSenderToMediaDescriptionOptions(
4043 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004044
Steve Anton6fe1fba2018-12-11 10:15:23 -08004045 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004046 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004047 std::unique_ptr<SessionDescription> answer =
4048 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004049
4050 ASSERT_EQ(4u, answer->contents().size());
4051 EXPECT_FALSE(answer->contents()[0].rejected);
4052 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004053 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004054 ASSERT_EQ(1u, acd->streams().size());
4055 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004056 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004057
4058 EXPECT_FALSE(answer->contents()[1].rejected);
4059 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004060 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004061 ASSERT_EQ(1u, vcd->streams().size());
4062 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004063 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004064
4065 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004066 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004067 ASSERT_EQ(1u, acd->streams().size());
4068 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004069 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004070
4071 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004072 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004073 ASSERT_EQ(1u, vcd->streams().size());
4074 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004075 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004076}
4077
4078// Test that the media section will be rejected in offer if the corresponding
4079// MediaDescriptionOptions is stopped by the offerer.
4080TEST_F(MediaSessionDescriptionFactoryTest,
4081 CreateOfferWithMediaSectionStoppedByOfferer) {
4082 // Create an offer with two audio sections and one of them is stopped.
4083 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004084 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4085 RtpTransceiverDirection::kSendRecv, kActive,
4086 &offer_opts);
4087 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4088 RtpTransceiverDirection::kInactive, kStopped,
4089 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004090 std::unique_ptr<SessionDescription> offer =
4091 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004092 ASSERT_TRUE(offer);
4093 ASSERT_EQ(2u, offer->contents().size());
4094 EXPECT_FALSE(offer->contents()[0].rejected);
4095 EXPECT_TRUE(offer->contents()[1].rejected);
4096}
4097
4098// Test that the media section will be rejected in answer if the corresponding
4099// MediaDescriptionOptions is stopped by the offerer.
4100TEST_F(MediaSessionDescriptionFactoryTest,
4101 CreateAnswerWithMediaSectionStoppedByOfferer) {
4102 // Create an offer with two audio sections and one of them is stopped.
4103 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004104 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4105 RtpTransceiverDirection::kSendRecv, kActive,
4106 &offer_opts);
4107 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4108 RtpTransceiverDirection::kInactive, kStopped,
4109 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004110 std::unique_ptr<SessionDescription> offer =
4111 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004112 ASSERT_TRUE(offer);
4113 ASSERT_EQ(2u, offer->contents().size());
4114 EXPECT_FALSE(offer->contents()[0].rejected);
4115 EXPECT_TRUE(offer->contents()[1].rejected);
4116
4117 // Create an answer based on the offer.
4118 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004119 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4120 RtpTransceiverDirection::kSendRecv, kActive,
4121 &answer_opts);
4122 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4123 RtpTransceiverDirection::kSendRecv, kActive,
4124 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004125 std::unique_ptr<SessionDescription> answer =
4126 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004127 ASSERT_EQ(2u, answer->contents().size());
4128 EXPECT_FALSE(answer->contents()[0].rejected);
4129 EXPECT_TRUE(answer->contents()[1].rejected);
4130}
4131
4132// Test that the media section will be rejected in answer if the corresponding
4133// MediaDescriptionOptions is stopped by the answerer.
4134TEST_F(MediaSessionDescriptionFactoryTest,
4135 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4136 // Create an offer with two audio sections.
4137 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004138 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4139 RtpTransceiverDirection::kSendRecv, kActive,
4140 &offer_opts);
4141 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4142 RtpTransceiverDirection::kSendRecv, kActive,
4143 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004144 std::unique_ptr<SessionDescription> offer =
4145 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004146 ASSERT_TRUE(offer);
4147 ASSERT_EQ(2u, offer->contents().size());
4148 ASSERT_FALSE(offer->contents()[0].rejected);
4149 ASSERT_FALSE(offer->contents()[1].rejected);
4150
4151 // The answerer rejects one of the audio sections.
4152 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004153 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4154 RtpTransceiverDirection::kSendRecv, kActive,
4155 &answer_opts);
4156 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4157 RtpTransceiverDirection::kInactive, kStopped,
4158 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004159 std::unique_ptr<SessionDescription> answer =
4160 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004161 ASSERT_EQ(2u, answer->contents().size());
4162 EXPECT_FALSE(answer->contents()[0].rejected);
4163 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004164
4165 // The TransportInfo of the rejected m= section is expected to be added in the
4166 // answer.
4167 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004168}
4169
4170// Test the generated media sections has the same order of the
4171// corresponding MediaDescriptionOptions.
4172TEST_F(MediaSessionDescriptionFactoryTest,
4173 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4174 MediaSessionOptions opts;
4175 // This tests put video section first because normally audio comes first by
4176 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004177 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4178 RtpTransceiverDirection::kSendRecv, kActive,
4179 &opts);
4180 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4181 RtpTransceiverDirection::kSendRecv, kActive,
4182 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004183 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004184
4185 ASSERT_TRUE(offer);
4186 ASSERT_EQ(2u, offer->contents().size());
4187 EXPECT_EQ("video", offer->contents()[0].name);
4188 EXPECT_EQ("audio", offer->contents()[1].name);
4189}
4190
4191// Test that different media sections using the same codec have same payload
4192// type.
4193TEST_F(MediaSessionDescriptionFactoryTest,
4194 PayloadTypesSharedByMediaSectionsOfSameType) {
4195 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004196 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4197 RtpTransceiverDirection::kSendRecv, kActive,
4198 &opts);
4199 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4200 RtpTransceiverDirection::kSendRecv, kActive,
4201 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004202 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004203 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004204 ASSERT_TRUE(offer);
4205 ASSERT_EQ(2u, offer->contents().size());
4206 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004207 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004208 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004209 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004210 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4211 ASSERT_EQ(2u, vcd1->codecs().size());
4212 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4213 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4214 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4215 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4216
4217 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004218 std::unique_ptr<SessionDescription> answer =
4219 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004220 ASSERT_TRUE(answer);
4221 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004222 vcd1 = answer->contents()[0].media_description()->as_video();
4223 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004224 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4225 ASSERT_EQ(1u, vcd1->codecs().size());
4226 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4227 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4228}
4229
4230// Test that the codec preference order per media section is respected in
4231// subsequent offer.
4232TEST_F(MediaSessionDescriptionFactoryTest,
4233 CreateOfferRespectsCodecPreferenceOrder) {
4234 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004235 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4236 RtpTransceiverDirection::kSendRecv, kActive,
4237 &opts);
4238 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4239 RtpTransceiverDirection::kSendRecv, kActive,
4240 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004241 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004242 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004243 ASSERT_TRUE(offer);
4244 ASSERT_EQ(2u, offer->contents().size());
4245 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004246 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004247 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004248 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004249 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4250 EXPECT_EQ(video_codecs, vcd1->codecs());
4251 EXPECT_EQ(video_codecs, vcd2->codecs());
4252
4253 // Change the codec preference of the first video section and create a
4254 // follow-up offer.
4255 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4256 vcd1->set_codecs(video_codecs_reverse);
4257 std::unique_ptr<SessionDescription> updated_offer(
4258 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004259 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4260 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004261 // The video codec preference order should be respected.
4262 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4263 EXPECT_EQ(video_codecs, vcd2->codecs());
4264}
4265
4266// Test that the codec preference order per media section is respected in
4267// the answer.
4268TEST_F(MediaSessionDescriptionFactoryTest,
4269 CreateAnswerRespectsCodecPreferenceOrder) {
4270 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004271 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4272 RtpTransceiverDirection::kSendRecv, kActive,
4273 &opts);
4274 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4275 RtpTransceiverDirection::kSendRecv, kActive,
4276 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004277 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004278 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004279 ASSERT_TRUE(offer);
4280 ASSERT_EQ(2u, offer->contents().size());
4281 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004282 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004283 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004284 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004285 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4286 EXPECT_EQ(video_codecs, vcd1->codecs());
4287 EXPECT_EQ(video_codecs, vcd2->codecs());
4288
4289 // Change the codec preference of the first video section and create an
4290 // answer.
4291 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4292 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004293 std::unique_ptr<SessionDescription> answer =
4294 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004295 vcd1 = answer->contents()[0].media_description()->as_video();
4296 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004297 // The video codec preference order should be respected.
4298 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4299 EXPECT_EQ(video_codecs, vcd2->codecs());
4300}
4301
Zhi Huang6f367472017-11-22 13:20:02 -08004302// Test that when creating an answer, the codecs use local parameters instead of
4303// the remote ones.
4304TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4305 const std::string audio_param_name = "audio_param";
4306 const std::string audio_value1 = "audio_v1";
4307 const std::string audio_value2 = "audio_v2";
4308 const std::string video_param_name = "video_param";
4309 const std::string video_value1 = "video_v1";
4310 const std::string video_value2 = "video_v2";
4311
4312 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4313 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4314 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4315 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4316
4317 // Set the parameters for codecs.
4318 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4319 video_codecs1[0].SetParam(video_param_name, video_value1);
4320 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4321 video_codecs2[0].SetParam(video_param_name, video_value2);
4322
4323 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004324 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004325 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004326 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004327
4328 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004329 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4330 RtpTransceiverDirection::kSendRecv, kActive,
4331 &opts);
4332 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4333 RtpTransceiverDirection::kSendRecv, kActive,
4334 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004335
Steve Anton6fe1fba2018-12-11 10:15:23 -08004336 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004337 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004338 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4339 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004340 std::string value;
4341 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4342 EXPECT_EQ(audio_value1, value);
4343 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4344 EXPECT_EQ(video_value1, value);
4345
Steve Anton6fe1fba2018-12-11 10:15:23 -08004346 std::unique_ptr<SessionDescription> answer =
4347 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004348 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004349 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4350 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004351 // Use the parameters from the local codecs.
4352 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4353 EXPECT_EQ(audio_value2, value);
4354 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4355 EXPECT_EQ(video_value2, value);
4356}
4357
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004358// Test that matching packetization-mode is part of the criteria for matching
4359// H264 codecs (in addition to profile-level-id). Previously, this was not the
4360// case, so the first H264 codec with the same profile-level-id would match and
4361// the payload type in the answer would be incorrect.
4362// This is a regression test for bugs.webrtc.org/8808
4363TEST_F(MediaSessionDescriptionFactoryTest,
4364 H264MatchCriteriaIncludesPacketizationMode) {
4365 // Create two H264 codecs with the same profile level ID and different
4366 // packetization modes.
4367 VideoCodec h264_pm0(96, "H264");
4368 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4369 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4370 VideoCodec h264_pm1(97, "H264");
4371 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4372 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4373
4374 // Offerer will send both codecs, answerer should choose the one with matching
4375 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004376 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4377 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004378
4379 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004380 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4381 RtpTransceiverDirection::kSendRecv, kActive,
4382 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004383
Steve Anton6fe1fba2018-12-11 10:15:23 -08004384 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004385 ASSERT_TRUE(offer);
4386
Steve Anton6fe1fba2018-12-11 10:15:23 -08004387 std::unique_ptr<SessionDescription> answer =
4388 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004389 ASSERT_TRUE(answer);
4390
4391 // Answer should have one negotiated codec with packetization-mode=1 using the
4392 // offered payload type.
4393 ASSERT_EQ(1u, answer->contents().size());
4394 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4395 ASSERT_EQ(1u, answer_vcd->codecs().size());
4396 auto answer_codec = answer_vcd->codecs()[0];
4397 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4398}
4399
zhihuangcf5b37c2016-05-05 11:44:35 -07004400class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4401 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004402 MediaProtocolTest()
Jonas Orelanded99dae2022-03-09 09:28:10 +01004403 : tdf1_(field_trials_),
4404 tdf2_(field_trials_),
4405 f1_(&tdf1_, &ssrc_generator1),
4406 f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004407 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4408 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004409 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4410 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -07004411 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4412 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004413 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4414 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004415 f1_.set_secure(SEC_ENABLED);
4416 f2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004417 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004418 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004419 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004420 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004421 tdf1_.set_secure(SEC_ENABLED);
4422 tdf2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004423 }
4424
4425 protected:
Jonas Orelanded99dae2022-03-09 09:28:10 +01004426 webrtc::test::ScopedKeyValueConfig field_trials_;
zhihuangcf5b37c2016-05-05 11:44:35 -07004427 TransportDescriptionFactory tdf1_;
4428 TransportDescriptionFactory tdf2_;
Jonas Orelanded99dae2022-03-09 09:28:10 +01004429 MediaSessionDescriptionFactory f1_;
4430 MediaSessionDescriptionFactory f2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004431 UniqueRandomIdGenerator ssrc_generator1;
4432 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004433};
4434
4435TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4436 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004437 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004438 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004439 ASSERT_TRUE(offer.get() != nullptr);
4440 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004441 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004442 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004443 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004444 std::unique_ptr<SessionDescription> answer =
4445 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004446 const ContentInfo* ac = answer->GetContentByName("audio");
4447 const ContentInfo* vc = answer->GetContentByName("video");
4448 ASSERT_TRUE(ac != nullptr);
4449 ASSERT_TRUE(vc != nullptr);
4450 EXPECT_FALSE(ac->rejected); // the offer is accepted
4451 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004452 const AudioContentDescription* acd = ac->media_description()->as_audio();
4453 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004454 EXPECT_EQ(GetParam(), acd->protocol());
4455 EXPECT_EQ(GetParam(), vcd->protocol());
4456}
4457
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004458INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4459 MediaProtocolTest,
4460 ::testing::ValuesIn(kMediaProtocols));
4461INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4462 MediaProtocolTest,
4463 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004464
4465TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004466 webrtc::test::ScopedKeyValueConfig field_trials;
4467 TransportDescriptionFactory tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004468 UniqueRandomIdGenerator ssrc_generator;
4469 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004470 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4471 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4472
4473 // The merged list of codecs should contain any send codecs that are also
Niels Möllerbe74b802022-03-18 14:10:15 +01004474 // nominally in the receive codecs list. Payload types should be picked from
ossu075af922016-06-14 03:29:38 -07004475 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4476 // (set to 1). This equals what happens when the send codecs are used in an
4477 // offer and the receive codecs are used in the following answer.
4478 const std::vector<AudioCodec> sendrecv_codecs =
4479 MAKE_VECTOR(kAudioCodecsAnswer);
4480 const std::vector<AudioCodec> no_codecs;
4481
4482 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4483 << "Please don't change shared test data!";
4484 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4485 << "Please don't change shared test data!";
4486 // Alter iLBC send codec to have zero channels, to test that that is handled
4487 // properly.
4488 send_codecs[1].channels = 0;
4489
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004490 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004491 // are handled properly.
4492 recv_codecs[2].name = "ilbc";
4493
4494 // Test proper merge
4495 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004496 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4497 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4498 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004499
4500 // Test empty send codecs list
4501 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004502 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4503 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4504 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004505
4506 // Test empty recv codecs list
4507 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004508 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4509 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4510 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004511
4512 // Test all empty codec lists
4513 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004514 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4515 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4516 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004517}
4518
4519namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004520// Compare the two vectors of codecs ignoring the payload type.
4521template <class Codec>
4522bool CodecsMatch(const std::vector<Codec>& codecs1,
Jonas Oreland4476b822022-03-10 15:21:28 +01004523 const std::vector<Codec>& codecs2,
Jonas Orelande62c2f22022-03-29 11:04:48 +02004524 const webrtc::FieldTrialsView* field_trials) {
zhihuang1c378ed2017-08-17 14:10:50 -07004525 if (codecs1.size() != codecs2.size()) {
4526 return false;
4527 }
4528
4529 for (size_t i = 0; i < codecs1.size(); ++i) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004530 if (!codecs1[i].Matches(codecs2[i], field_trials)) {
zhihuang1c378ed2017-08-17 14:10:50 -07004531 return false;
4532 }
4533 }
4534 return true;
4535}
4536
Steve Anton4e70a722017-11-28 14:57:10 -08004537void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004538 webrtc::test::ScopedKeyValueConfig field_trials;
4539 TransportDescriptionFactory tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004540 UniqueRandomIdGenerator ssrc_generator;
4541 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004542 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4543 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4544 const std::vector<AudioCodec> sendrecv_codecs =
4545 MAKE_VECTOR(kAudioCodecsAnswer);
4546 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004547
4548 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004549 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4550 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004551
Steve Anton4e70a722017-11-28 14:57:10 -08004552 if (direction == RtpTransceiverDirection::kSendRecv ||
4553 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004554 AttachSenderToMediaDescriptionOptions(
4555 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004556 }
ossu075af922016-06-14 03:29:38 -07004557
Steve Anton6fe1fba2018-12-11 10:15:23 -08004558 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004559 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004560 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004561
4562 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004563 // that the codecs put in are right. This happens when we neither want to
4564 // send nor receive audio. The checks are still in place if at some point
4565 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004566 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004567 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004568 // sendrecv and inactive should both present lists as if the channel was
4569 // to be used for sending and receiving. Inactive essentially means it
4570 // might eventually be used anything, but we don't know more at this
4571 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004572 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004573 EXPECT_TRUE(
4574 CodecsMatch<AudioCodec>(send_codecs, acd->codecs(), &field_trials));
Steve Anton4e70a722017-11-28 14:57:10 -08004575 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
Jonas Oreland4476b822022-03-10 15:21:28 +01004576 EXPECT_TRUE(
4577 CodecsMatch<AudioCodec>(recv_codecs, acd->codecs(), &field_trials));
ossu075af922016-06-14 03:29:38 -07004578 } else {
Jonas Oreland4476b822022-03-10 15:21:28 +01004579 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs(),
4580 &field_trials));
ossu075af922016-06-14 03:29:38 -07004581 }
4582 }
4583}
4584
4585static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004586 AudioCodec(0, "codec0", 16000, -1, 1),
4587 AudioCodec(1, "codec1", 8000, 13300, 1),
4588 AudioCodec(2, "codec2", 8000, 64000, 1),
4589 AudioCodec(3, "codec3", 8000, 64000, 1),
4590 AudioCodec(4, "codec4", 8000, 0, 2),
4591 AudioCodec(5, "codec5", 32000, 0, 1),
4592 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004593
zhihuang1c378ed2017-08-17 14:10:50 -07004594/* The codecs groups below are chosen as per the matrix below. The objective
4595 * is to have different sets of codecs in the inputs, to get unique sets of
4596 * codecs after negotiation, depending on offer and answer communication
4597 * directions. One-way directions in the offer should either result in the
4598 * opposite direction in the answer, or an inactive answer. Regardless, the
4599 * choice of codecs should be as if the answer contained the opposite
4600 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004601 *
4602 * | Offer | Answer | Result
4603 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4604 * 0 | x - - | - x - | x - - - -
4605 * 1 | x x x | - x - | x - - x -
4606 * 2 | - x - | x - - | - x - - -
4607 * 3 | x x x | x - - | - x x - -
4608 * 4 | - x - | x x x | - x - - -
4609 * 5 | x - - | x x x | x - - - -
4610 * 6 | x x x | x x x | x x x x x
4611 */
4612// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004613static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4614static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004615// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4616// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004617static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4618static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004619// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004620static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4621static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4622static const int kResultSendrecv_SendCodecs[] = {3, 6};
4623static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4624static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004625
4626template <typename T, int IDXS>
4627std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4628 std::vector<T> out;
4629 out.reserve(IDXS);
4630 for (int idx : indices)
4631 out.push_back(array[idx]);
4632
4633 return out;
4634}
4635
Steve Anton4e70a722017-11-28 14:57:10 -08004636void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4637 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004638 bool add_legacy_stream) {
Jonas Orelanded99dae2022-03-09 09:28:10 +01004639 webrtc::test::ScopedKeyValueConfig field_trials;
4640 TransportDescriptionFactory offer_tdf(field_trials);
4641 TransportDescriptionFactory answer_tdf(field_trials);
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004642 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4643 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4644 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
Jonas Orelanded99dae2022-03-09 09:28:10 +01004645
ossu075af922016-06-14 03:29:38 -07004646 offer_factory.set_audio_codecs(
4647 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4648 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4649 answer_factory.set_audio_codecs(
4650 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4651 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4652
ossu075af922016-06-14 03:29:38 -07004653 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004654 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4655 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004656
Steve Anton4e70a722017-11-28 14:57:10 -08004657 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004658 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4659 kAudioTrack1, {kMediaStream1}, 1,
4660 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004661 }
4662
Steve Anton6fe1fba2018-12-11 10:15:23 -08004663 std::unique_ptr<SessionDescription> offer =
4664 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004665 ASSERT_TRUE(offer.get() != NULL);
4666
4667 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004668 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4669 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004670
Steve Anton4e70a722017-11-28 14:57:10 -08004671 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004672 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4673 kAudioTrack1, {kMediaStream1}, 1,
4674 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004675 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004676 std::unique_ptr<SessionDescription> answer =
4677 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004678 const ContentInfo* ac = answer->GetContentByName("audio");
4679
zhihuang1c378ed2017-08-17 14:10:50 -07004680 // If the factory didn't add any audio content to the answer, we cannot
4681 // check that the codecs put in are right. This happens when we neither want
4682 // to send nor receive audio. The checks are still in place if at some point
4683 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004684 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004685 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4686 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004687
ossu075af922016-06-14 03:29:38 -07004688 std::vector<AudioCodec> target_codecs;
4689 // For offers with sendrecv or inactive, we should never reply with more
4690 // codecs than offered, with these codec sets.
4691 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004692 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004693 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4694 kResultSendrecv_SendrecvCodecs);
4695 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004696 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004697 target_codecs =
4698 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004699 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004700 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004701 target_codecs =
4702 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004703 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004704 case RtpTransceiverDirection::kSendRecv:
4705 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004706 target_codecs =
4707 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004708 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004709 target_codecs =
4710 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004711 } else {
4712 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4713 kResultSendrecv_SendrecvCodecs);
4714 }
4715 break;
Harald Alvestrand6060df52020-08-11 09:54:02 +02004716 case RtpTransceiverDirection::kStopped:
4717 // This does not happen in any current test.
Artem Titovd3251962021-11-15 16:57:07 +01004718 RTC_DCHECK_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004719 }
4720
zhihuang1c378ed2017-08-17 14:10:50 -07004721 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004722 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004723 bool first = true;
4724 os << "{";
4725 for (const auto& c : codecs) {
4726 os << (first ? " " : ", ") << c.id;
4727 first = false;
4728 }
4729 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004730 return os.Release();
ossu075af922016-06-14 03:29:38 -07004731 };
4732
4733 EXPECT_TRUE(acd->codecs() == target_codecs)
4734 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004735 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4736 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004737 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004738 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4739 << "; got: "
4740 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004741 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004742 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004743 << "Only inactive offers are allowed to not generate any audio "
4744 "content";
ossu075af922016-06-14 03:29:38 -07004745 }
4746}
brandtr03d5fb12016-11-22 03:37:59 -08004747
4748} // namespace
ossu075af922016-06-14 03:29:38 -07004749
4750class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004751 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004752
4753TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004754 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004755}
4756
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004757INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4758 AudioCodecsOfferTest,
4759 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4760 RtpTransceiverDirection::kRecvOnly,
4761 RtpTransceiverDirection::kSendRecv,
4762 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004763
4764class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004765 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4766 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004767 bool>> {};
ossu075af922016-06-14 03:29:38 -07004768
4769TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004770 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4771 ::testing::get<1>(GetParam()),
4772 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004773}
4774
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004775INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004776 MediaSessionDescriptionFactoryTest,
4777 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004778 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4779 RtpTransceiverDirection::kRecvOnly,
4780 RtpTransceiverDirection::kSendRecv,
4781 RtpTransceiverDirection::kInactive),
4782 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4783 RtpTransceiverDirection::kRecvOnly,
4784 RtpTransceiverDirection::kSendRecv,
4785 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004786 ::testing::Bool()));