blob: cfe9ac8a3109553ce58209d70443ad74111ba902 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/media_session.h"
12
Amit Hilbuch77938e62018-12-21 09:23:38 -080013#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080014#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <string>
Harald Alvestrand1716d392019-06-03 20:35:45 +020016#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <vector>
18
Steve Anton64b626b2019-01-28 17:25:26 -080019#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080020#include "absl/memory/memory.h"
Mirko Bonadei57cabed2020-04-01 12:03:11 +020021#include "absl/strings/match.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020024#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "p2p/base/p2p_constants.h"
26#include "p2p/base/transport_description.h"
27#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "pc/rtp_media_utils.h"
Harald Alvestrand0d018412021-11-04 13:52:31 +000029#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080033#include "rtc_base/message_digest.h"
34#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020035#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080036#include "rtc_base/unique_id_generator.h"
Philipp Hanckefedc7ab2020-11-17 21:59:12 +010037#include "test/field_trial.h"
Steve Antone38a5a12018-11-21 16:05:15 -080038#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
Harald Alvestrand0d018412021-11-04 13:52:31 +000040#define ASSERT_CRYPTO(cd, s, cs) \
41 ASSERT_EQ(s, cd->cryptos().size()); \
42 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
43
henrike@webrtc.org28e20752013-07-10 00:45:36 +000044typedef std::vector<cricket::Candidate> Candidates;
45
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080046using cricket::AudioCodec;
47using cricket::AudioContentDescription;
48using cricket::ContentInfo;
Harald Alvestrand0d018412021-11-04 13:52:31 +000049using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080050using cricket::GetFirstAudioContent;
51using cricket::GetFirstAudioContentDescription;
52using cricket::GetFirstDataContent;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080053using cricket::GetFirstVideoContent;
54using cricket::GetFirstVideoContentDescription;
55using cricket::kAutoBandwidth;
56using cricket::MEDIA_TYPE_AUDIO;
57using cricket::MEDIA_TYPE_DATA;
58using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070060using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080061using cricket::MediaProtocolType;
62using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000063using cricket::MediaSessionOptions;
64using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080065using cricket::RidDescription;
66using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020067using cricket::SctpDataContentDescription;
Harald Alvestrand0d018412021-11-04 13:52:31 +000068using cricket::SEC_DISABLED;
69using cricket::SEC_ENABLED;
70using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080072using cricket::SimulcastDescription;
73using cricket::SimulcastLayer;
74using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075using cricket::SsrcGroup;
76using cricket::StreamParams;
77using cricket::StreamParamsVec;
78using cricket::TransportDescription;
79using cricket::TransportDescriptionFactory;
80using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080082using cricket::VideoContentDescription;
Mirko Bonadei7750d802021-07-26 17:27:42 +020083using rtc::kCsAeadAes128Gcm;
84using rtc::kCsAeadAes256Gcm;
85using rtc::kCsAesCm128HmacSha1_32;
86using rtc::kCsAesCm128HmacSha1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080087using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020088using ::testing::Contains;
89using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +010090using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020091using ::testing::ElementsAreArray;
92using ::testing::Eq;
93using ::testing::Field;
94using ::testing::IsEmpty;
95using ::testing::IsFalse;
96using ::testing::Ne;
97using ::testing::Not;
98using ::testing::Pointwise;
99using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700100using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800101using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102
103static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700104 AudioCodec(103, "ISAC", 16000, -1, 1),
105 AudioCodec(102, "iLBC", 8000, 13300, 1),
106 AudioCodec(0, "PCMU", 8000, 64000, 1),
107 AudioCodec(8, "PCMA", 8000, 64000, 1),
108 AudioCodec(117, "red", 8000, 0, 1),
109 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110
111static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200112 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700113 AudioCodec(0, "PCMU", 8000, 64000, 1),
114 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115};
116
117static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700118 AudioCodec(102, "iLBC", 8000, 13300, 1),
119 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120};
121
perkj26752742016-10-24 01:21:16 -0700122static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
123 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000124
zhihuang1c378ed2017-08-17 14:10:50 -0700125static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
126 VideoCodec(96, "H264-SVC")};
127
perkj26752742016-10-24 01:21:16 -0700128static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
129 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130
perkj26752742016-10-24 01:21:16 -0700131static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132
isheriff6f8d6862016-05-26 11:24:55 -0700133static const RtpExtension kAudioRtpExtension1[] = {
134 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
135 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136};
137
jbauch5869f502017-06-29 12:31:36 -0700138static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
139 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
140 RtpExtension("http://google.com/testing/audio_something", 10),
141 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200142 RtpExtension("http://google.com/testing/audio_something", 11, true),
jbauch5869f502017-06-29 12:31:36 -0700143};
144
isheriff6f8d6862016-05-26 11:24:55 -0700145static const RtpExtension kAudioRtpExtension2[] = {
146 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
147 RtpExtension("http://google.com/testing/audio_something_else", 8),
148 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000149};
150
isheriff6f8d6862016-05-26 11:24:55 -0700151static const RtpExtension kAudioRtpExtension3[] = {
152 RtpExtension("http://google.com/testing/audio_something", 2),
153 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700154};
155
jbauch5869f502017-06-29 12:31:36 -0700156static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
157 RtpExtension("http://google.com/testing/audio_something", 2),
158 // Use RTP extension that supports encryption.
159 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
160};
161
162static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
163 RtpExtension("http://google.com/testing/audio_something", 2),
164 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200165 RtpExtension("http://google.com/testing/audio_something", 14, true),
166 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
167};
168
169static const RtpExtension kVideoRtpExtension3ForEncryptionOffer[] = {
170 RtpExtension("http://google.com/testing/video_something", 4),
171 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
172 RtpExtension("http://google.com/testing/video_something", 12, true),
173 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
jbauch5869f502017-06-29 12:31:36 -0700174};
175
isheriff6f8d6862016-05-26 11:24:55 -0700176static const RtpExtension kAudioRtpExtensionAnswer[] = {
177 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000178};
179
jbauch5869f502017-06-29 12:31:36 -0700180static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
181 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
182};
183
isheriff6f8d6862016-05-26 11:24:55 -0700184static const RtpExtension kVideoRtpExtension1[] = {
185 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
186 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187};
188
jbauch5869f502017-06-29 12:31:36 -0700189static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
191 RtpExtension("http://google.com/testing/video_something", 13),
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200192 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
193 RtpExtension("http://google.com/testing/video_something", 7, true),
jbauch5869f502017-06-29 12:31:36 -0700194};
195
isheriff6f8d6862016-05-26 11:24:55 -0700196static const RtpExtension kVideoRtpExtension2[] = {
197 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
198 RtpExtension("http://google.com/testing/video_something_else", 14),
199 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200};
201
isheriff6f8d6862016-05-26 11:24:55 -0700202static const RtpExtension kVideoRtpExtension3[] = {
203 RtpExtension("http://google.com/testing/video_something", 4),
204 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700205};
206
jbauch5869f502017-06-29 12:31:36 -0700207static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
208 RtpExtension("http://google.com/testing/video_something", 4),
209 // Use RTP extension that supports encryption.
210 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
211};
212
isheriff6f8d6862016-05-26 11:24:55 -0700213static const RtpExtension kVideoRtpExtensionAnswer[] = {
214 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215};
216
jbauch5869f502017-06-29 12:31:36 -0700217static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
Lennart Grahl0d0ed762021-05-17 16:06:37 +0200218 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
jbauch5869f502017-06-29 12:31:36 -0700219};
220
Johannes Kronce8e8672019-02-22 13:06:44 +0100221static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
222 RtpExtension("http://www.ietf.org/id/"
223 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
224 1),
225};
226
227static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
228 RtpExtension("http://www.ietf.org/id/"
229 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
230 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100231 RtpExtension(
232 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
233 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100234};
235
236static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100237 RtpExtension(
238 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
239 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100240};
241
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100242static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
243 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
244 "generic-frame-descriptor-00",
245 3),
246};
247
Peter Boström0c4e06b2015-10-07 12:23:21 +0200248static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
249static const uint32_t kSimSsrc[] = {10, 20, 30};
250static const uint32_t kFec1Ssrc[] = {10, 11};
251static const uint32_t kFec2Ssrc[] = {20, 21};
252static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253
254static const char kMediaStream1[] = "stream_1";
255static const char kMediaStream2[] = "stream_2";
256static const char kVideoTrack1[] = "video_1";
257static const char kVideoTrack2[] = "video_2";
258static const char kAudioTrack1[] = "audio_1";
259static const char kAudioTrack2[] = "audio_2";
260static const char kAudioTrack3[] = "audio_3";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261
zhihuangcf5b37c2016-05-05 11:44:35 -0700262static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
263 "RTP/SAVPF"};
264static const char* kMediaProtocolsDtls[] = {
265 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
266 "UDP/TLS/RTP/SAVP"};
267
Harald Alvestrand0d018412021-11-04 13:52:31 +0000268// SRTP cipher name negotiated by the tests. This must be updated if the
269// default changes.
270static const char* kDefaultSrtpCryptoSuite = kCsAesCm128HmacSha1_80;
271static const char* kDefaultSrtpCryptoSuiteGcm = kCsAeadAes256Gcm;
272
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800273// These constants are used to make the code using "AddMediaDescriptionOptions"
274// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700275static constexpr bool kStopped = true;
276static constexpr bool kActive = false;
277
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000278static bool IsMediaContentOfType(const ContentInfo* content,
279 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800280 RTC_DCHECK(content);
281 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000282}
283
Steve Anton4e70a722017-11-28 14:57:10 -0800284static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800285 RTC_DCHECK(content);
286 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000287}
288
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000289static void AddRtxCodec(const VideoCodec& rtx_codec,
290 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800291 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000292 codecs->push_back(rtx_codec);
293}
294
295template <class T>
296static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
297 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100298 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000299 for (const auto& codec : codecs) {
300 codec_names.push_back(codec.name);
301 }
302 return codec_names;
303}
304
zhihuang1c378ed2017-08-17 14:10:50 -0700305// This is used for test only. MIDs are not the identification of the
306// MediaDescriptionOptions since some end points may not support MID and the SDP
307// may not contain 'mid'.
308std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
309 const std::string& mid,
310 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800311 return absl::c_find_if(
312 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700313 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
314}
315
316std::vector<MediaDescriptionOptions>::const_iterator
317FindFirstMediaDescriptionByMid(const std::string& mid,
318 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800319 return absl::c_find_if(
320 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700321 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700322}
323
Artem Titov880fa812021-07-30 22:30:23 +0200324// Add a media section to the `session_options`.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800325static void AddMediaDescriptionOptions(MediaType type,
326 const std::string& mid,
327 RtpTransceiverDirection direction,
328 bool stopped,
329 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800330 opts->media_description_options.push_back(
331 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700332}
333
Steve Anton4e70a722017-11-28 14:57:10 -0800334static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700335 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800336 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
337 opts);
338 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
339 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700340}
341
Florent Castelli516e2842021-04-19 15:29:50 +0200342static void AddDataSection(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700343 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800344 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700345}
346
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800347static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700348 const std::string& mid,
349 MediaType type,
350 const std::string& track_id,
351 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800352 const std::vector<RidDescription>& rids,
353 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700354 int num_sim_layer,
355 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700356 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
357 switch (type) {
358 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700359 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700360 break;
361 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800362 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
363 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700364 break;
zhihuang1c378ed2017-08-17 14:10:50 -0700365 default:
Artem Titovd3251962021-11-15 16:57:07 +0100366 RTC_DCHECK_NOTREACHED();
zhihuang1c378ed2017-08-17 14:10:50 -0700367 }
368}
369
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800370static void AttachSenderToMediaDescriptionOptions(
371 const std::string& mid,
372 MediaType type,
373 const std::string& track_id,
374 const std::vector<std::string>& stream_ids,
375 int num_sim_layer,
376 MediaSessionOptions* session_options) {
377 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
378 SimulcastLayerList(), num_sim_layer,
379 session_options);
380}
381
zhihuang1c378ed2017-08-17 14:10:50 -0700382static void DetachSenderFromMediaSection(const std::string& mid,
383 const std::string& track_id,
384 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700385 std::vector<cricket::SenderOptions>& sender_options_list =
386 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
387 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800388 absl::c_find_if(sender_options_list,
389 [track_id](const cricket::SenderOptions& sender_options) {
390 return sender_options.track_id == track_id;
391 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700392 RTC_DCHECK(sender_it != sender_options_list.end());
393 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700394}
395
396// Helper function used to create a default MediaSessionOptions for Plan B SDP.
397// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
398static MediaSessionOptions CreatePlanBMediaSessionOptions() {
399 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800400 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
401 RtpTransceiverDirection::kRecvOnly, kActive,
402 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700403 return session_options;
404}
405
Harald Alvestrand0d018412021-11-04 13:52:31 +0000406// prefers GCM SDES crypto suites by removing non-GCM defaults.
407void PreferGcmCryptoParameters(CryptoParamsVec* cryptos) {
408 cryptos->erase(
409 std::remove_if(cryptos->begin(), cryptos->end(),
410 [](const cricket::CryptoParams& crypto) {
411 return crypto.cipher_suite != kCsAeadAes256Gcm &&
412 crypto.cipher_suite != kCsAeadAes128Gcm;
413 }),
414 cryptos->end());
415}
416
zhihuang1c378ed2017-08-17 14:10:50 -0700417// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
418// was designed for Plan B SDP, where only one audio "m=" section and one video
419// "m=" section could be generated, and ordering couldn't be controlled. Many of
420// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200421class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800423 MediaSessionDescriptionFactoryTest()
424 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700425 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
426 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200427 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
428 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -0700429 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
430 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200431 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
432 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +0000433 tdf1_.set_certificate(rtc::RTCCertificate::Create(
434 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
435 tdf2_.set_certificate(rtc::RTCCertificate::Create(
436 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437 }
438
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000439 // Create a video StreamParamsVec object with:
440 // - one video stream with 3 simulcast streams and FEC,
441 StreamParamsVec CreateComplexVideoStreamParamsVec() {
442 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
443 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
444 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
445 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
446
447 std::vector<SsrcGroup> ssrc_groups;
448 ssrc_groups.push_back(sim_group);
449 ssrc_groups.push_back(fec_group1);
450 ssrc_groups.push_back(fec_group2);
451 ssrc_groups.push_back(fec_group3);
452
453 StreamParams simulcast_params;
454 simulcast_params.id = kVideoTrack1;
455 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
456 simulcast_params.ssrc_groups = ssrc_groups;
457 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800458 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000459
460 StreamParamsVec video_streams;
461 video_streams.push_back(simulcast_params);
462
463 return video_streams;
464 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465
Harald Alvestrand0d018412021-11-04 13:52:31 +0000466 bool CompareCryptoParams(const CryptoParamsVec& c1,
467 const CryptoParamsVec& c2) {
468 if (c1.size() != c2.size())
469 return false;
470 for (size_t i = 0; i < c1.size(); ++i)
471 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
472 c1[i].key_params != c2[i].key_params ||
473 c1[i].session_params != c2[i].session_params)
474 return false;
475 return true;
476 }
477
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700478 // Returns true if the transport info contains "renomination" as an
479 // ICE option.
480 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800481 return absl::c_linear_search(transport_info->description.transport_options,
482 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700483 }
484
zhihuang1c378ed2017-08-17 14:10:50 -0700485 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700486 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000487 bool has_current_desc) {
488 const std::string current_audio_ufrag = "current_audio_ufrag";
489 const std::string current_audio_pwd = "current_audio_pwd";
490 const std::string current_video_ufrag = "current_video_ufrag";
491 const std::string current_video_pwd = "current_video_pwd";
492 const std::string current_data_ufrag = "current_data_ufrag";
493 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800494 std::unique_ptr<SessionDescription> current_desc;
495 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200497 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800498 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200499 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800500 TransportDescription(current_audio_ufrag, current_audio_pwd)));
501 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200502 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800503 TransportDescription(current_video_ufrag, current_video_pwd)));
504 current_desc->AddTransportInfo(TransportInfo(
505 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 }
507 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800508 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 } else {
kwiberg31022942016-03-11 14:18:21 -0800510 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800511 offer = f1_.CreateOffer(options, NULL);
512 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513 }
514 ASSERT_TRUE(desc.get() != NULL);
515 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000516 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 EXPECT_TRUE(ti_audio != NULL);
518 if (has_current_desc) {
519 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
520 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
521 } else {
522 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
523 ti_audio->description.ice_ufrag.size());
524 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
525 ti_audio->description.ice_pwd.size());
526 }
zhihuang1c378ed2017-08-17 14:10:50 -0700527 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700528 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700529 EXPECT_EQ(
530 media_desc_options_it->transport_options.enable_ice_renomination,
531 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 } else {
533 EXPECT_TRUE(ti_audio == NULL);
534 }
535 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000536 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700538 auto media_desc_options_it =
539 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 if (options.bundle_enabled) {
541 EXPECT_EQ(ti_audio->description.ice_ufrag,
542 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200543 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 } else {
545 if (has_current_desc) {
546 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
547 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
548 } else {
549 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
550 ti_video->description.ice_ufrag.size());
551 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
552 ti_video->description.ice_pwd.size());
553 }
554 }
zhihuang1c378ed2017-08-17 14:10:50 -0700555 EXPECT_EQ(
556 media_desc_options_it->transport_options.enable_ice_renomination,
557 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558 } else {
559 EXPECT_TRUE(ti_video == NULL);
560 }
561 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
562 if (options.has_data()) {
563 EXPECT_TRUE(ti_data != NULL);
564 if (options.bundle_enabled) {
565 EXPECT_EQ(ti_audio->description.ice_ufrag,
566 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200567 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 } else {
569 if (has_current_desc) {
570 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
571 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
572 } else {
573 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
574 ti_data->description.ice_ufrag.size());
575 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
576 ti_data->description.ice_pwd.size());
577 }
578 }
zhihuang1c378ed2017-08-17 14:10:50 -0700579 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700580 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700581 EXPECT_EQ(
582 media_desc_options_it->transport_options.enable_ice_renomination,
583 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700584
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700586 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 }
588 }
589
Harald Alvestrand0d018412021-11-04 13:52:31 +0000590 void TestCryptoWithBundle(bool offer) {
591 f1_.set_secure(SEC_ENABLED);
592 MediaSessionOptions options;
593 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
594 std::unique_ptr<SessionDescription> ref_desc;
595 std::unique_ptr<SessionDescription> desc;
596 if (offer) {
597 options.bundle_enabled = false;
598 ref_desc = f1_.CreateOffer(options, NULL);
599 options.bundle_enabled = true;
600 desc = f1_.CreateOffer(options, ref_desc.get());
601 } else {
602 options.bundle_enabled = true;
603 ref_desc = f1_.CreateOffer(options, NULL);
604 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
605 }
606 ASSERT_TRUE(desc);
607 const cricket::MediaContentDescription* audio_media_desc =
608 desc->GetContentDescriptionByName("audio");
609 ASSERT_TRUE(audio_media_desc);
610 const cricket::MediaContentDescription* video_media_desc =
611 desc->GetContentDescriptionByName("video");
612 ASSERT_TRUE(video_media_desc);
613 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
614 video_media_desc->cryptos()));
615 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
616 EXPECT_EQ(kDefaultSrtpCryptoSuite,
617 audio_media_desc->cryptos()[0].cipher_suite);
618
619 // Verify the selected crypto is one from the reference audio
620 // media content.
621 const cricket::MediaContentDescription* ref_audio_media_desc =
622 ref_desc->GetContentDescriptionByName("audio");
623 bool found = false;
624 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
625 if (ref_audio_media_desc->cryptos()[i].Matches(
626 audio_media_desc->cryptos()[0])) {
627 found = true;
628 break;
629 }
630 }
631 EXPECT_TRUE(found);
632 }
633
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 // This test that the audio and video media direction is set to
Artem Titov880fa812021-07-30 22:30:23 +0200635 // `expected_direction_in_answer` in an answer if the offer direction is set
636 // to `direction_in_offer` and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000637 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800638 RtpTransceiverDirection direction_in_offer,
639 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700640 MediaSessionOptions offer_opts;
641 AddAudioVideoSections(direction_in_offer, &offer_opts);
642
Steve Anton6fe1fba2018-12-11 10:15:23 -0800643 std::unique_ptr<SessionDescription> offer =
644 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700646 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700648 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650
zhihuang1c378ed2017-08-17 14:10:50 -0700651 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800652 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800653 std::unique_ptr<SessionDescription> answer =
654 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 const AudioContentDescription* acd_answer =
656 GetFirstAudioContentDescription(answer.get());
657 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
658 const VideoContentDescription* vcd_answer =
659 GetFirstVideoContentDescription(answer.get());
660 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
661 }
662
663 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800664 RTC_DCHECK(content);
665 RTC_CHECK(content->media_description());
666 const cricket::AudioContentDescription* audio_desc =
667 content->media_description()->as_audio();
668 RTC_CHECK(audio_desc);
669 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
670 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800672 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 }
674 return true;
675 }
676
Harald Alvestrand0d018412021-11-04 13:52:31 +0000677 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
678 MediaSessionOptions offer_opts;
679 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
680 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
681
682 MediaSessionOptions answer_opts;
683 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
684 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
685
686 f1_.set_secure(SEC_ENABLED);
687 f2_.set_secure(SEC_ENABLED);
688 std::unique_ptr<SessionDescription> offer =
689 f1_.CreateOffer(offer_opts, NULL);
690 ASSERT_TRUE(offer.get() != NULL);
691 if (gcm_offer && gcm_answer) {
692 for (cricket::ContentInfo& content : offer->contents()) {
693 auto cryptos = content.media_description()->cryptos();
694 PreferGcmCryptoParameters(&cryptos);
695 content.media_description()->set_cryptos(cryptos);
696 }
697 }
698 std::unique_ptr<SessionDescription> answer =
699 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
700 const ContentInfo* ac = answer->GetContentByName("audio");
701 const ContentInfo* vc = answer->GetContentByName("video");
702 ASSERT_TRUE(ac != NULL);
703 ASSERT_TRUE(vc != NULL);
704 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
705 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
706 const AudioContentDescription* acd = ac->media_description()->as_audio();
707 const VideoContentDescription* vcd = vc->media_description()->as_video();
708 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
709 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
710 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
711 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
712 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
713 if (gcm_offer && gcm_answer) {
714 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
715 } else {
716 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
717 }
718 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
719 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
720 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
721 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
722 if (gcm_offer && gcm_answer) {
723 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
724 } else {
725 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
726 }
727 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
728 }
729
Johannes Kronce8e8672019-02-22 13:06:44 +0100730 void TestTransportSequenceNumberNegotiation(
731 const cricket::RtpHeaderExtensions& local,
732 const cricket::RtpHeaderExtensions& offered,
733 const cricket::RtpHeaderExtensions& expectedAnswer) {
734 MediaSessionOptions opts;
735 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +0200736 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100737 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
738 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +0200739 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100740 std::unique_ptr<SessionDescription> answer =
741 f2_.CreateAnswer(offer.get(), opts, NULL);
742
743 EXPECT_EQ(
744 expectedAnswer,
745 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
746 EXPECT_EQ(
747 expectedAnswer,
748 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
749 }
750
Markus Handell755c65d2020-06-24 01:06:10 +0200751 std::vector<webrtc::RtpHeaderExtensionCapability>
752 HeaderExtensionCapabilitiesFromRtpExtensions(
753 cricket::RtpHeaderExtensions extensions) {
754 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
755 for (const auto& extension : extensions) {
756 webrtc::RtpHeaderExtensionCapability capability(
757 extension.uri, extension.id,
758 webrtc::RtpTransceiverDirection::kSendRecv);
759 capabilities.push_back(capability);
760 }
761 return capabilities;
762 }
763
764 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
765 cricket::RtpHeaderExtensions video_exts,
766 MediaSessionOptions* opts) {
767 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
768 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
769 for (auto& entry : opts->media_description_options) {
770 switch (entry.type) {
771 case MEDIA_TYPE_AUDIO:
772 entry.header_extensions = audio_caps;
773 break;
774 case MEDIA_TYPE_VIDEO:
775 entry.header_extensions = video_caps;
776 break;
777 default:
778 break;
779 }
780 }
781 }
782
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800784 UniqueRandomIdGenerator ssrc_generator1;
785 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 MediaSessionDescriptionFactory f1_;
787 MediaSessionDescriptionFactory f2_;
788 TransportDescriptionFactory tdf1_;
789 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790};
791
792// Create a typical audio offer, and ensure it matches what we expect.
793TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000794 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800795 std::unique_ptr<SessionDescription> offer =
796 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 ASSERT_TRUE(offer.get() != NULL);
798 const ContentInfo* ac = offer->GetContentByName("audio");
799 const ContentInfo* vc = offer->GetContentByName("video");
800 ASSERT_TRUE(ac != NULL);
801 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800802 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800803 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700805 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700806 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
808 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000809 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
810 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811}
812
813// Create a typical video offer, and ensure it matches what we expect.
814TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
815 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800816 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000817 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800818 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 ASSERT_TRUE(offer.get() != NULL);
820 const ContentInfo* ac = offer->GetContentByName("audio");
821 const ContentInfo* vc = offer->GetContentByName("video");
822 ASSERT_TRUE(ac != NULL);
823 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800824 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
825 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800826 const AudioContentDescription* acd = ac->media_description()->as_audio();
827 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700829 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700830 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
832 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000833 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
834 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200836 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700837 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
839 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +0000840 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
841 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842}
843
844// Test creating an offer with bundle where the Codecs have the same dynamic
845// RTP playlod type. The test verifies that the offer don't contain the
846// duplicate RTP payload types.
847TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200848 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700849 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851
852 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800853 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800855 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856 const VideoContentDescription* vcd =
857 GetFirstVideoContentDescription(offer.get());
858 const AudioContentDescription* acd =
859 GetFirstAudioContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 ASSERT_TRUE(NULL != vcd);
861 ASSERT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
864 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865}
866
zhihuang1c378ed2017-08-17 14:10:50 -0700867// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868// after an audio only session has been negotiated.
869TEST_F(MediaSessionDescriptionFactoryTest,
870 TestCreateUpdatedVideoOfferWithBundle) {
Harald Alvestrand0d018412021-11-04 13:52:31 +0000871 f1_.set_secure(SEC_ENABLED);
872 f2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800874 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
875 RtpTransceiverDirection::kRecvOnly, kActive,
876 &opts);
877 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
878 RtpTransceiverDirection::kInactive, kStopped,
879 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800881 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
882 std::unique_ptr<SessionDescription> answer =
883 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000884
885 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800886 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800888 std::unique_ptr<SessionDescription> updated_offer(
889 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000890
891 const AudioContentDescription* acd =
892 GetFirstAudioContentDescription(updated_offer.get());
893 const VideoContentDescription* vcd =
894 GetFirstVideoContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000895 EXPECT_TRUE(NULL != vcd);
896 EXPECT_TRUE(NULL != acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897
Harald Alvestrand0d018412021-11-04 13:52:31 +0000898 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
899 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
900 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
901 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902}
903
wu@webrtc.org78187522013-10-07 23:32:02 +0000904// Create an SCTP data offer with bundle without error.
905TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
906 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000907 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200908 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000909 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800910 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000911 EXPECT_TRUE(offer.get() != NULL);
912 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000913 auto dcd = GetFirstSctpDataContentDescription(offer.get());
914 ASSERT_TRUE(dcd);
915 // Since this transport is insecure, the protocol should be "SCTP".
916 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
917}
918
919// Create an SCTP data offer with bundle without error.
920TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
921 MediaSessionOptions opts;
922 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200923 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000924 f1_.set_secure(SEC_ENABLED);
925 tdf1_.set_secure(SEC_ENABLED);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000926 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
927 EXPECT_TRUE(offer.get() != NULL);
928 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
929 auto dcd = GetFirstSctpDataContentDescription(offer.get());
930 ASSERT_TRUE(dcd);
931 // The protocol should now be "UDP/DTLS/SCTP"
932 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000933}
934
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000935// Test creating an sctp data channel from an already generated offer.
936TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
937 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000938 opts.bundle_enabled = true;
Florent Castelli516e2842021-04-19 15:29:50 +0200939 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +0000940 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800941 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000942 ASSERT_TRUE(offer1.get() != NULL);
943 const ContentInfo* data = offer1->GetContentByName("data");
944 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800945 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000946
kwiberg31022942016-03-11 14:18:21 -0800947 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000948 f1_.CreateOffer(opts, offer1.get()));
949 data = offer2->GetContentByName("data");
950 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800951 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000952}
953
Steve Anton2bed3972019-01-04 17:04:30 -0800954// Test that if BUNDLE is enabled and all media sections are rejected then the
955// BUNDLE group is not present in the re-offer.
956TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
957 MediaSessionOptions opts;
958 opts.bundle_enabled = true;
959 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
960 RtpTransceiverDirection::kSendRecv, kActive,
961 &opts);
962 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
963
964 opts.media_description_options[0].stopped = true;
965 std::unique_ptr<SessionDescription> reoffer =
966 f1_.CreateOffer(opts, offer.get());
967
968 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
969}
970
971// Test that if BUNDLE is enabled and the remote re-offer does not include a
972// BUNDLE group since all media sections are rejected, then the re-answer also
973// does not include a BUNDLE group.
974TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
975 MediaSessionOptions opts;
976 opts.bundle_enabled = true;
977 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
978 RtpTransceiverDirection::kSendRecv, kActive,
979 &opts);
980 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
981 std::unique_ptr<SessionDescription> answer =
982 f2_.CreateAnswer(offer.get(), opts, nullptr);
983
984 opts.media_description_options[0].stopped = true;
985 std::unique_ptr<SessionDescription> reoffer =
986 f1_.CreateOffer(opts, offer.get());
987 std::unique_ptr<SessionDescription> reanswer =
988 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
989
990 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
991}
992
993// Test that if BUNDLE is enabled and the previous offerer-tagged media section
994// was rejected then the new offerer-tagged media section is the non-rejected
995// media section.
996TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
997 MediaSessionOptions opts;
998 opts.bundle_enabled = true;
999 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1000 RtpTransceiverDirection::kSendRecv, kActive,
1001 &opts);
1002 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1003
1004 // Reject the audio m= section and add a video m= section.
1005 opts.media_description_options[0].stopped = true;
1006 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1007 RtpTransceiverDirection::kSendRecv, kActive,
1008 &opts);
1009 std::unique_ptr<SessionDescription> reoffer =
1010 f1_.CreateOffer(opts, offer.get());
1011
1012 const cricket::ContentGroup* bundle_group =
1013 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1014 ASSERT_TRUE(bundle_group);
1015 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1016 EXPECT_TRUE(bundle_group->HasContentName("video"));
1017}
1018
1019// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1020// was rejected and a new media section is added, then the re-answer BUNDLE
1021// group will contain only the non-rejected media section.
1022TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1023 MediaSessionOptions opts;
1024 opts.bundle_enabled = true;
1025 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1026 RtpTransceiverDirection::kSendRecv, kActive,
1027 &opts);
1028 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1029 std::unique_ptr<SessionDescription> answer =
1030 f2_.CreateAnswer(offer.get(), opts, nullptr);
1031
1032 // Reject the audio m= section and add a video m= section.
1033 opts.media_description_options[0].stopped = true;
1034 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1035 RtpTransceiverDirection::kSendRecv, kActive,
1036 &opts);
1037 std::unique_ptr<SessionDescription> reoffer =
1038 f1_.CreateOffer(opts, offer.get());
1039 std::unique_ptr<SessionDescription> reanswer =
1040 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1041
1042 const cricket::ContentGroup* bundle_group =
1043 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1044 ASSERT_TRUE(bundle_group);
1045 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1046 EXPECT_TRUE(bundle_group->HasContentName("video"));
1047}
1048
Henrik Boströmf8187e02021-04-26 21:04:26 +02001049TEST_F(MediaSessionDescriptionFactoryTest,
1050 CreateAnswerForOfferWithMultipleBundleGroups) {
1051 // Create an offer with 4 m= sections, initially without BUNDLE groups.
1052 MediaSessionOptions opts;
1053 opts.bundle_enabled = false;
1054 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "1",
1055 RtpTransceiverDirection::kSendRecv, kActive,
1056 &opts);
1057 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "2",
1058 RtpTransceiverDirection::kSendRecv, kActive,
1059 &opts);
1060 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "3",
1061 RtpTransceiverDirection::kSendRecv, kActive,
1062 &opts);
1063 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "4",
1064 RtpTransceiverDirection::kSendRecv, kActive,
1065 &opts);
1066 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1067 ASSERT_TRUE(offer->groups().empty());
1068
1069 // Munge the offer to have two groups. Offers like these cannot be generated
1070 // without munging, but it is valid to receive such offers from remote
1071 // endpoints.
1072 cricket::ContentGroup bundle_group1(cricket::GROUP_TYPE_BUNDLE);
1073 bundle_group1.AddContentName("1");
1074 bundle_group1.AddContentName("2");
1075 cricket::ContentGroup bundle_group2(cricket::GROUP_TYPE_BUNDLE);
1076 bundle_group2.AddContentName("3");
1077 bundle_group2.AddContentName("4");
1078 offer->AddGroup(bundle_group1);
1079 offer->AddGroup(bundle_group2);
1080
1081 // If BUNDLE is enabled, the answer to this offer should accept both BUNDLE
1082 // groups.
1083 opts.bundle_enabled = true;
1084 std::unique_ptr<SessionDescription> answer =
1085 f2_.CreateAnswer(offer.get(), opts, nullptr);
1086
1087 std::vector<const cricket::ContentGroup*> answer_groups =
1088 answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1089 ASSERT_EQ(answer_groups.size(), 2u);
1090 EXPECT_EQ(answer_groups[0]->content_names().size(), 2u);
1091 EXPECT_TRUE(answer_groups[0]->HasContentName("1"));
1092 EXPECT_TRUE(answer_groups[0]->HasContentName("2"));
1093 EXPECT_EQ(answer_groups[1]->content_names().size(), 2u);
1094 EXPECT_TRUE(answer_groups[1]->HasContentName("3"));
1095 EXPECT_TRUE(answer_groups[1]->HasContentName("4"));
1096
1097 // If BUNDLE is disabled, the answer to this offer should reject both BUNDLE
1098 // groups.
1099 opts.bundle_enabled = false;
1100 answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1101
1102 answer_groups = answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1103 // Rejected groups are still listed, but they are empty.
1104 ASSERT_EQ(answer_groups.size(), 2u);
1105 EXPECT_TRUE(answer_groups[0]->content_names().empty());
1106 EXPECT_TRUE(answer_groups[1]->content_names().empty());
1107}
1108
Steve Anton2bed3972019-01-04 17:04:30 -08001109// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1110// and there is still a non-rejected media section that was in the initial
1111// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1112// media section.
1113TEST_F(MediaSessionDescriptionFactoryTest,
1114 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1115 MediaSessionOptions opts;
1116 opts.bundle_enabled = true;
1117 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1118 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1119 std::unique_ptr<SessionDescription> answer =
1120 f2_.CreateAnswer(offer.get(), opts, nullptr);
1121
1122 // Reject the audio m= section.
1123 opts.media_description_options[0].stopped = true;
1124 std::unique_ptr<SessionDescription> reoffer =
1125 f1_.CreateOffer(opts, offer.get());
1126
1127 const TransportDescription* offer_tagged =
1128 offer->GetTransportDescriptionByName("audio");
1129 ASSERT_TRUE(offer_tagged);
1130 const TransportDescription* reoffer_tagged =
1131 reoffer->GetTransportDescriptionByName("video");
1132 ASSERT_TRUE(reoffer_tagged);
1133 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1134 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1135}
1136
1137// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1138// and there is still a non-rejected media section that was in the initial
1139// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1140// media section.
1141TEST_F(MediaSessionDescriptionFactoryTest,
1142 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1143 MediaSessionOptions opts;
1144 opts.bundle_enabled = true;
1145 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1146 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1147 std::unique_ptr<SessionDescription> answer =
1148 f2_.CreateAnswer(offer.get(), opts, nullptr);
1149
1150 // Reject the audio m= section.
1151 opts.media_description_options[0].stopped = true;
1152 std::unique_ptr<SessionDescription> reoffer =
1153 f1_.CreateOffer(opts, offer.get());
1154 std::unique_ptr<SessionDescription> reanswer =
1155 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1156
1157 const TransportDescription* answer_tagged =
1158 answer->GetTransportDescriptionByName("audio");
1159 ASSERT_TRUE(answer_tagged);
1160 const TransportDescription* reanswer_tagged =
1161 reanswer->GetTransportDescriptionByName("video");
1162 ASSERT_TRUE(reanswer_tagged);
1163 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1164 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1165}
1166
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001167// Create an audio, video offer without legacy StreamParams.
1168TEST_F(MediaSessionDescriptionFactoryTest,
1169 TestCreateOfferWithoutLegacyStreams) {
1170 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001171 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001172 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001173 ASSERT_TRUE(offer.get() != NULL);
1174 const ContentInfo* ac = offer->GetContentByName("audio");
1175 const ContentInfo* vc = offer->GetContentByName("video");
1176 ASSERT_TRUE(ac != NULL);
1177 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001178 const AudioContentDescription* acd = ac->media_description()->as_audio();
1179 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001180
Yves Gerey665174f2018-06-19 15:03:05 +02001181 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1182 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183}
1184
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001185// Creates an audio+video sendonly offer.
1186TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001187 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001188 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001189 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1190 {kMediaStream1}, 1, &opts);
1191 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1192 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001193
Steve Anton6fe1fba2018-12-11 10:15:23 -08001194 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001195 ASSERT_TRUE(offer.get() != NULL);
1196 EXPECT_EQ(2u, offer->contents().size());
1197 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1198 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1199
Steve Anton4e70a722017-11-28 14:57:10 -08001200 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1201 GetMediaDirection(&offer->contents()[0]));
1202 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1203 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001204}
1205
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001206// Verifies that the order of the media contents in the current
1207// SessionDescription is preserved in the new SessionDescription.
1208TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1209 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001210 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001211
kwiberg31022942016-03-11 14:18:21 -08001212 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001213 ASSERT_TRUE(offer1.get() != NULL);
1214 EXPECT_EQ(1u, offer1->contents().size());
1215 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1216
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001217 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1218 RtpTransceiverDirection::kRecvOnly, kActive,
1219 &opts);
kwiberg31022942016-03-11 14:18:21 -08001220 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001221 f1_.CreateOffer(opts, offer1.get()));
1222 ASSERT_TRUE(offer2.get() != NULL);
1223 EXPECT_EQ(2u, offer2->contents().size());
1224 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1225 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1226
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001227 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1228 RtpTransceiverDirection::kRecvOnly, kActive,
1229 &opts);
kwiberg31022942016-03-11 14:18:21 -08001230 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001231 f1_.CreateOffer(opts, offer2.get()));
1232 ASSERT_TRUE(offer3.get() != NULL);
1233 EXPECT_EQ(3u, offer3->contents().size());
1234 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1235 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1236 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001237}
1238
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239// Create a typical audio answer, and ensure it matches what we expect.
1240TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001241 f1_.set_secure(SEC_ENABLED);
1242 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001243 std::unique_ptr<SessionDescription> offer =
1244 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001246 std::unique_ptr<SessionDescription> answer =
1247 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248 const ContentInfo* ac = answer->GetContentByName("audio");
1249 const ContentInfo* vc = answer->GetContentByName("video");
1250 ASSERT_TRUE(ac != NULL);
1251 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001252 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001253 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001255 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001256 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1258 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001259 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1260 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
1261}
1262
1263// Create a typical audio answer with GCM ciphers enabled, and ensure it
1264// matches what we expect.
1265TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1266 f1_.set_secure(SEC_ENABLED);
1267 f2_.set_secure(SEC_ENABLED);
1268 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1269 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
1270 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1271 ASSERT_TRUE(offer.get() != NULL);
1272 for (cricket::ContentInfo& content : offer->contents()) {
1273 auto cryptos = content.media_description()->cryptos();
1274 PreferGcmCryptoParameters(&cryptos);
1275 content.media_description()->set_cryptos(cryptos);
1276 }
1277 std::unique_ptr<SessionDescription> answer =
1278 f2_.CreateAnswer(offer.get(), opts, NULL);
1279 const ContentInfo* ac = answer->GetContentByName("audio");
1280 const ContentInfo* vc = answer->GetContentByName("video");
1281 ASSERT_TRUE(ac != NULL);
1282 ASSERT_TRUE(vc == NULL);
1283 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1284 const AudioContentDescription* acd = ac->media_description()->as_audio();
1285 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1286 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
1287 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
1288 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1289 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1290 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
1291 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001292}
1293
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001294// Create a typical video answer, and ensure it matches what we expect.
1295TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1296 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001297 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00001298 f1_.set_secure(SEC_ENABLED);
1299 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001300 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001302 std::unique_ptr<SessionDescription> answer =
1303 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001304 const ContentInfo* ac = answer->GetContentByName("audio");
1305 const ContentInfo* vc = answer->GetContentByName("video");
1306 ASSERT_TRUE(ac != NULL);
1307 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001308 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1309 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001310 const AudioContentDescription* acd = ac->media_description()->as_audio();
1311 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001313 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001314 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001315 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001317 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001319 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001320 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1321 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Harald Alvestrand0d018412021-11-04 13:52:31 +00001322 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1323 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
1324}
1325
1326// Create a typical video answer with GCM ciphers enabled, and ensure it
1327// matches what we expect.
1328TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1329 TestVideoGcmCipher(true, true);
1330}
1331
1332// Create a typical video answer with GCM ciphers enabled for the offer only,
1333// and ensure it matches what we expect.
1334TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1335 TestVideoGcmCipher(true, false);
1336}
1337
1338// Create a typical video answer with GCM ciphers enabled for the answer only,
1339// and ensure it matches what we expect.
1340TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1341 TestVideoGcmCipher(false, true);
jbauchcb560652016-08-04 05:20:32 -07001342}
1343
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001344// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1345// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001346TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1347 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001348 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001349 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001350 ASSERT_TRUE(offer.get() != NULL);
1351 ContentInfo* dc_offer = offer->GetContentByName("data");
1352 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001353 SctpDataContentDescription* dcd_offer =
1354 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001355 EXPECT_TRUE(dcd_offer->use_sctpmap());
1356
Steve Anton6fe1fba2018-12-11 10:15:23 -08001357 std::unique_ptr<SessionDescription> answer =
1358 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001359 const ContentInfo* dc_answer = answer->GetContentByName("data");
1360 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001361 const SctpDataContentDescription* dcd_answer =
1362 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001363 EXPECT_TRUE(dcd_answer->use_sctpmap());
1364}
1365
1366// The answer's use_sctpmap flag should match the offer's.
1367TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1368 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001369 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001370 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001371 ASSERT_TRUE(offer.get() != NULL);
1372 ContentInfo* dc_offer = offer->GetContentByName("data");
1373 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001374 SctpDataContentDescription* dcd_offer =
1375 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001376 dcd_offer->set_use_sctpmap(false);
1377
Steve Anton6fe1fba2018-12-11 10:15:23 -08001378 std::unique_ptr<SessionDescription> answer =
1379 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001380 const ContentInfo* dc_answer = answer->GetContentByName("data");
1381 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001382 const SctpDataContentDescription* dcd_answer =
1383 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001384 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001385}
1386
deadbeef8b7e9ad2017-05-25 09:38:55 -07001387// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1388// and "TCP/DTLS/SCTP" offers.
1389TEST_F(MediaSessionDescriptionFactoryTest,
1390 TestCreateDataAnswerToDifferentOfferedProtos) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001391 // Need to enable DTLS offer/answer generation (disabled by default in this
1392 // test).
1393 f1_.set_secure(SEC_ENABLED);
1394 f2_.set_secure(SEC_ENABLED);
1395 tdf1_.set_secure(SEC_ENABLED);
1396 tdf2_.set_secure(SEC_ENABLED);
1397
deadbeef8b7e9ad2017-05-25 09:38:55 -07001398 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001399 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001400 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001401 ASSERT_TRUE(offer.get() != nullptr);
1402 ContentInfo* dc_offer = offer->GetContentByName("data");
1403 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001404 SctpDataContentDescription* dcd_offer =
1405 dc_offer->media_description()->as_sctp();
1406 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001407
1408 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1409 "TCP/DTLS/SCTP"};
1410 for (const std::string& proto : protos) {
1411 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001412 std::unique_ptr<SessionDescription> answer =
1413 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001414 const ContentInfo* dc_answer = answer->GetContentByName("data");
1415 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001416 const SctpDataContentDescription* dcd_answer =
1417 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001418 EXPECT_FALSE(dc_answer->rejected);
1419 EXPECT_EQ(proto, dcd_answer->protocol());
1420 }
1421}
1422
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001423TEST_F(MediaSessionDescriptionFactoryTest,
1424 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001425 // Need to enable DTLS offer/answer generation (disabled by default in this
1426 // test).
1427 f1_.set_secure(SEC_ENABLED);
1428 f2_.set_secure(SEC_ENABLED);
1429 tdf1_.set_secure(SEC_ENABLED);
1430 tdf2_.set_secure(SEC_ENABLED);
1431
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001432 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001433 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001434 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1435 ASSERT_TRUE(offer.get() != nullptr);
1436 ContentInfo* dc_offer = offer->GetContentByName("data");
1437 ASSERT_TRUE(dc_offer != nullptr);
1438 SctpDataContentDescription* dcd_offer =
1439 dc_offer->media_description()->as_sctp();
1440 ASSERT_TRUE(dcd_offer);
1441 dcd_offer->set_max_message_size(1234);
1442 std::unique_ptr<SessionDescription> answer =
1443 f2_.CreateAnswer(offer.get(), opts, nullptr);
1444 const ContentInfo* dc_answer = answer->GetContentByName("data");
1445 ASSERT_TRUE(dc_answer != nullptr);
1446 const SctpDataContentDescription* dcd_answer =
1447 dc_answer->media_description()->as_sctp();
1448 EXPECT_FALSE(dc_answer->rejected);
1449 EXPECT_EQ(1234, dcd_answer->max_message_size());
1450}
1451
1452TEST_F(MediaSessionDescriptionFactoryTest,
1453 TestCreateDataAnswerToOfferWithZeroMessageSize) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00001454 // Need to enable DTLS offer/answer generation (disabled by default in this
1455 // test).
1456 f1_.set_secure(SEC_ENABLED);
1457 f2_.set_secure(SEC_ENABLED);
1458 tdf1_.set_secure(SEC_ENABLED);
1459 tdf2_.set_secure(SEC_ENABLED);
1460
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001461 MediaSessionOptions opts;
Florent Castelli516e2842021-04-19 15:29:50 +02001462 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001463 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1464 ASSERT_TRUE(offer.get() != nullptr);
1465 ContentInfo* dc_offer = offer->GetContentByName("data");
1466 ASSERT_TRUE(dc_offer != nullptr);
1467 SctpDataContentDescription* dcd_offer =
1468 dc_offer->media_description()->as_sctp();
1469 ASSERT_TRUE(dcd_offer);
1470 dcd_offer->set_max_message_size(0);
1471 std::unique_ptr<SessionDescription> answer =
1472 f2_.CreateAnswer(offer.get(), opts, nullptr);
1473 const ContentInfo* dc_answer = answer->GetContentByName("data");
1474 ASSERT_TRUE(dc_answer != nullptr);
1475 const SctpDataContentDescription* dcd_answer =
1476 dc_answer->media_description()->as_sctp();
1477 EXPECT_FALSE(dc_answer->rejected);
1478 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1479}
1480
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001481// Verifies that the order of the media contents in the offer is preserved in
1482// the answer.
1483TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1484 MediaSessionOptions opts;
1485
1486 // Creates a data only offer.
Florent Castelli516e2842021-04-19 15:29:50 +02001487 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001488 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001489 ASSERT_TRUE(offer1.get() != NULL);
1490
1491 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001492 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1493 RtpTransceiverDirection::kRecvOnly, kActive,
1494 &opts);
kwiberg31022942016-03-11 14:18:21 -08001495 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001496 f1_.CreateOffer(opts, offer1.get()));
1497 ASSERT_TRUE(offer2.get() != NULL);
1498
1499 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001500 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1501 RtpTransceiverDirection::kRecvOnly, kActive,
1502 &opts);
kwiberg31022942016-03-11 14:18:21 -08001503 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001504 f1_.CreateOffer(opts, offer2.get()));
1505 ASSERT_TRUE(offer3.get() != NULL);
1506
Steve Anton6fe1fba2018-12-11 10:15:23 -08001507 std::unique_ptr<SessionDescription> answer =
1508 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001509 ASSERT_TRUE(answer.get() != NULL);
1510 EXPECT_EQ(3u, answer->contents().size());
1511 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1512 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1513 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1514}
1515
ossu075af922016-06-14 03:29:38 -07001516// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1517// answerer settings.
1518
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001519// This test that the media direction is set to send/receive in an answer if
1520// the offer is send receive.
1521TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001522 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1523 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001524}
1525
1526// This test that the media direction is set to receive only in an answer if
1527// the offer is send only.
1528TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001529 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1530 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001531}
1532
1533// This test that the media direction is set to send only in an answer if
1534// the offer is recv only.
1535TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001536 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1537 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538}
1539
1540// This test that the media direction is set to inactive in an answer if
1541// the offer is inactive.
1542TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001543 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1544 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001545}
1546
Harald Alvestrand0d018412021-11-04 13:52:31 +00001547// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001548TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001549 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Harald Alvestrand0d018412021-11-04 13:52:31 +00001550 f1_.set_secure(SEC_DISABLED);
1551 f2_.set_secure(SEC_DISABLED);
1552 tdf1_.set_secure(SEC_DISABLED);
1553 tdf2_.set_secure(SEC_DISABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554
Steve Anton6fe1fba2018-12-11 10:15:23 -08001555 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001556 const AudioContentDescription* offer_acd =
1557 GetFirstAudioContentDescription(offer.get());
1558 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001559 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560
Steve Anton6fe1fba2018-12-11 10:15:23 -08001561 std::unique_ptr<SessionDescription> answer =
1562 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563
1564 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1565 ASSERT_TRUE(ac_answer != NULL);
1566 EXPECT_FALSE(ac_answer->rejected);
1567
1568 const AudioContentDescription* answer_acd =
1569 GetFirstAudioContentDescription(answer.get());
1570 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001571 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001572}
1573
1574// Create a video offer and answer and ensure the RTP header extensions
1575// matches what we expect.
1576TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1577 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001578 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +02001579 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1580 MAKE_VECTOR(kVideoRtpExtension1), &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001581
Steve Anton6fe1fba2018-12-11 10:15:23 -08001582 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001583 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001584 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1585 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001586 std::unique_ptr<SessionDescription> answer =
1587 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001588
Yves Gerey665174f2018-06-19 15:03:05 +02001589 EXPECT_EQ(
1590 MAKE_VECTOR(kAudioRtpExtension1),
1591 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1592 EXPECT_EQ(
1593 MAKE_VECTOR(kVideoRtpExtension1),
1594 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1595 EXPECT_EQ(
1596 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1597 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1598 EXPECT_EQ(
1599 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1600 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001601}
1602
Johannes Kronce8e8672019-02-22 13:06:44 +01001603// Create a audio/video offer and answer and ensure that the
1604// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1605// supported and should take precedence even though not listed among locally
1606// supported extensions.
1607TEST_F(MediaSessionDescriptionFactoryTest,
1608 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1609 TestTransportSequenceNumberNegotiation(
1610 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1611 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1612 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1613}
1614TEST_F(MediaSessionDescriptionFactoryTest,
1615 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1616 TestTransportSequenceNumberNegotiation(
1617 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1618 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1619 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1620}
1621TEST_F(MediaSessionDescriptionFactoryTest,
1622 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1623 TestTransportSequenceNumberNegotiation(
1624 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1625 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1626 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1627}
1628
jbauch5869f502017-06-29 12:31:36 -07001629TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001630 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1631 MediaSessionOptions opts;
1632 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1633
Markus Handell755c65d2020-06-24 01:06:10 +02001634 SetAudioVideoRtpHeaderExtensions(
1635 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1636 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001637 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001638 SetAudioVideoRtpHeaderExtensions(
1639 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1640 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001641 std::unique_ptr<SessionDescription> answer =
1642 f2_.CreateAnswer(offer.get(), opts, nullptr);
1643 EXPECT_THAT(
1644 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001645 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001646 EXPECT_THAT(
1647 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001648 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001649}
1650
1651TEST_F(MediaSessionDescriptionFactoryTest,
1652 TestNegotiateFrameDescriptorWhenExposedLocally) {
1653 MediaSessionOptions opts;
1654 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1655
Markus Handell755c65d2020-06-24 01:06:10 +02001656 SetAudioVideoRtpHeaderExtensions(
1657 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1658 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001659 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1660 std::unique_ptr<SessionDescription> answer =
1661 f2_.CreateAnswer(offer.get(), opts, nullptr);
1662 EXPECT_THAT(
1663 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001664 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001665 EXPECT_THAT(
1666 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001667 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001668}
1669
1670TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001671 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1672 MediaSessionOptions opts;
1673 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1674
1675 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell755c65d2020-06-24 01:06:10 +02001676 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +00001677 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001678 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1679 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001680 std::unique_ptr<SessionDescription> answer =
1681 f2_.CreateAnswer(offer.get(), opts, nullptr);
1682 EXPECT_THAT(
1683 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1684 ElementsAre(offer_dd));
1685}
1686
1687TEST_F(MediaSessionDescriptionFactoryTest,
1688 NegotiateDependencyDescriptorWhenExposedLocally) {
1689 MediaSessionOptions opts;
1690 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1691
1692 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1693 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell755c65d2020-06-24 01:06:10 +02001694 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001695 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001696 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001697 std::unique_ptr<SessionDescription> answer =
1698 f2_.CreateAnswer(offer.get(), opts, nullptr);
1699 EXPECT_THAT(
1700 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1701 ElementsAre(offer_dd));
1702}
1703
1704TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001705 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1706 MediaSessionOptions opts;
1707 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1708
1709 const cricket::RtpHeaderExtensions offered_extensions = {
1710 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1711 const cricket::RtpHeaderExtensions local_extensions = {
1712 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001713 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1714 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001715 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001716 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001717 std::unique_ptr<SessionDescription> answer =
1718 f2_.CreateAnswer(offer.get(), opts, nullptr);
1719 EXPECT_THAT(
1720 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1721 ElementsAreArray(offered_extensions));
1722 EXPECT_THAT(
1723 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1724 ElementsAreArray(offered_extensions));
1725}
1726
1727TEST_F(MediaSessionDescriptionFactoryTest,
1728 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1729 MediaSessionOptions opts;
1730 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1731
1732 const cricket::RtpHeaderExtensions offered_extensions = {
1733 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1734 const cricket::RtpHeaderExtensions local_extensions = {
1735 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001736 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1737 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001738 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001739 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001740 std::unique_ptr<SessionDescription> answer =
1741 f2_.CreateAnswer(offer.get(), opts, nullptr);
1742 EXPECT_THAT(
1743 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1744 ElementsAreArray(offered_extensions));
1745 EXPECT_THAT(
1746 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1747 ElementsAreArray(offered_extensions));
1748}
1749
1750TEST_F(MediaSessionDescriptionFactoryTest,
1751 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1752 MediaSessionOptions opts;
1753 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1754
1755 const cricket::RtpHeaderExtensions offered_extensions = {
1756 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1757 const cricket::RtpHeaderExtensions local_extensions = {
1758 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001759 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1760 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001761 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001762 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001763 std::unique_ptr<SessionDescription> answer =
1764 f2_.CreateAnswer(offer.get(), opts, nullptr);
1765 EXPECT_THAT(
1766 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1767 IsEmpty());
1768 EXPECT_THAT(
1769 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1770 IsEmpty());
1771}
1772
1773TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handell755c65d2020-06-24 01:06:10 +02001774 OffersUnstoppedExtensionsWithAudioVideoExtensionStopped) {
1775 MediaSessionOptions opts;
1776 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1777 RtpTransceiverDirection::kSendRecv, kActive,
1778 &opts);
1779 opts.media_description_options.back().header_extensions = {
1780 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1781 RtpTransceiverDirection::kStopped),
1782 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1783 RtpTransceiverDirection::kSendOnly)};
1784 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1785 RtpTransceiverDirection::kSendRecv, kActive,
1786 &opts);
1787 opts.media_description_options.back().header_extensions = {
1788 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1789 RtpTransceiverDirection::kStopped),
1790 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1791 RtpTransceiverDirection::kSendOnly)};
1792 auto offer = f1_.CreateOffer(opts, nullptr);
1793 EXPECT_THAT(
1794 offer->contents(),
1795 ElementsAre(
1796 Property(&ContentInfo::media_description,
1797 Pointee(Property(
1798 &MediaContentDescription::rtp_header_extensions,
1799 ElementsAre(Field(&RtpExtension::uri, "uri2"))))),
1800 Property(&ContentInfo::media_description,
1801 Pointee(Property(
1802 &MediaContentDescription::rtp_header_extensions,
1803 ElementsAre(Field(&RtpExtension::uri, "uri3")))))));
1804}
1805
1806TEST_F(MediaSessionDescriptionFactoryTest,
1807 OffersUnstoppedExtensionsWithAudioExtensionStopped) {
1808 MediaSessionOptions opts;
1809 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1810 RtpTransceiverDirection::kSendRecv, kActive,
1811 &opts);
1812 opts.media_description_options.back().header_extensions = {
1813 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1814 RtpTransceiverDirection::kSendOnly),
1815 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1816 RtpTransceiverDirection::kStopped)};
1817 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1818 RtpTransceiverDirection::kSendRecv, kActive,
1819 &opts);
1820 opts.media_description_options.back().header_extensions = {
1821 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1822 RtpTransceiverDirection::kSendRecv),
1823 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1824 RtpTransceiverDirection::kSendOnly)};
1825 auto offer = f1_.CreateOffer(opts, nullptr);
1826 EXPECT_THAT(
1827 offer->contents(),
1828 ElementsAre(
1829 Property(&ContentInfo::media_description,
1830 Pointee(Property(
1831 &MediaContentDescription::rtp_header_extensions,
1832 ElementsAre(Field(&RtpExtension::uri, "uri1"))))),
1833 Property(
1834 &ContentInfo::media_description,
1835 Pointee(Property(
1836 &MediaContentDescription::rtp_header_extensions,
1837 UnorderedElementsAre(Field(&RtpExtension::uri, "uri3"),
1838 Field(&RtpExtension::uri, "uri42")))))));
1839}
1840
1841TEST_F(MediaSessionDescriptionFactoryTest,
1842 OffersUnstoppedExtensionsWithVideoExtensionStopped) {
1843 MediaSessionOptions opts;
1844 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1845 RtpTransceiverDirection::kSendRecv, kActive,
1846 &opts);
1847 opts.media_description_options.back().header_extensions = {
1848 webrtc::RtpHeaderExtensionCapability("uri1", 5,
1849 RtpTransceiverDirection::kSendOnly),
1850 webrtc::RtpHeaderExtensionCapability("uri2", 7,
1851 RtpTransceiverDirection::kSendRecv)};
1852 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1853 RtpTransceiverDirection::kSendRecv, kActive,
1854 &opts);
1855 opts.media_description_options.back().header_extensions = {
1856 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1857 RtpTransceiverDirection::kSendRecv),
1858 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1859 RtpTransceiverDirection::kStopped)};
1860 auto offer = f1_.CreateOffer(opts, nullptr);
1861 EXPECT_THAT(
1862 offer->contents(),
1863 ElementsAre(
1864 Property(
1865 &ContentInfo::media_description,
1866 Pointee(Property(
1867 &MediaContentDescription::rtp_header_extensions,
1868 UnorderedElementsAre(Field(&RtpExtension::uri, "uri1"),
1869 Field(&RtpExtension::uri, "uri2"))))),
1870 Property(&ContentInfo::media_description,
1871 Pointee(Property(
1872 &MediaContentDescription::rtp_header_extensions,
1873 ElementsAre(Field(&RtpExtension::uri, "uri42")))))));
1874}
1875
1876TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1877 MediaSessionOptions opts;
1878 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1879 RtpTransceiverDirection::kSendRecv, kActive,
1880 &opts);
1881 opts.media_description_options.back().header_extensions = {
1882 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1883 RtpTransceiverDirection::kStopped),
1884 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1885 RtpTransceiverDirection::kSendOnly),
1886 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1887 RtpTransceiverDirection::kRecvOnly),
1888 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1889 RtpTransceiverDirection::kSendRecv)};
1890 auto offer = f1_.CreateOffer(opts, nullptr);
1891 opts.media_description_options.back().header_extensions = {
1892 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1893 RtpTransceiverDirection::kSendOnly),
1894 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1895 RtpTransceiverDirection::kRecvOnly),
1896 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1897 RtpTransceiverDirection::kStopped),
1898 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1899 RtpTransceiverDirection::kSendRecv)};
1900 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1901 EXPECT_THAT(
1902 answer->contents(),
1903 ElementsAre(Property(
1904 &ContentInfo::media_description,
1905 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1906 ElementsAre(Field(&RtpExtension::uri, "uri2"),
1907 Field(&RtpExtension::uri, "uri4")))))));
1908}
1909
1910TEST_F(MediaSessionDescriptionFactoryTest,
1911 AppendsUnstoppedExtensionsToCurrentDescription) {
1912 MediaSessionOptions opts;
1913 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1914 RtpTransceiverDirection::kSendRecv, kActive,
1915 &opts);
1916 opts.media_description_options.back().header_extensions = {
1917 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1918 RtpTransceiverDirection::kSendRecv)};
1919 auto offer = f1_.CreateOffer(opts, nullptr);
1920 opts.media_description_options.back().header_extensions = {
1921 webrtc::RtpHeaderExtensionCapability("uri1", 2,
1922 RtpTransceiverDirection::kSendRecv),
1923 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1924 RtpTransceiverDirection::kRecvOnly),
1925 webrtc::RtpHeaderExtensionCapability("uri3", 5,
1926 RtpTransceiverDirection::kStopped),
1927 webrtc::RtpHeaderExtensionCapability("uri4", 6,
1928 RtpTransceiverDirection::kSendRecv)};
1929 auto offer2 = f1_.CreateOffer(opts, offer.get());
1930 EXPECT_THAT(
1931 offer2->contents(),
1932 ElementsAre(Property(
1933 &ContentInfo::media_description,
1934 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1935 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1936 Field(&RtpExtension::uri, "uri2"),
1937 Field(&RtpExtension::uri, "uri4")))))));
1938}
1939
1940TEST_F(MediaSessionDescriptionFactoryTest,
1941 AppendsStoppedExtensionIfKnownAndPresentInTheOffer) {
1942 MediaSessionOptions opts;
1943 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1944 RtpTransceiverDirection::kSendRecv, kActive,
1945 &opts);
1946 opts.media_description_options.back().header_extensions = {
1947 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1948 RtpTransceiverDirection::kSendRecv),
1949 webrtc::RtpHeaderExtensionCapability("uri2", 1,
1950 RtpTransceiverDirection::kSendRecv)};
1951 auto offer = f1_.CreateOffer(opts, nullptr);
1952
1953 // Now add "uri2" as stopped to the options verify that the offer contains
1954 // uri2 since it's already present since before.
1955 opts.media_description_options.back().header_extensions = {
1956 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1957 RtpTransceiverDirection::kSendRecv),
1958 webrtc::RtpHeaderExtensionCapability("uri2", 2,
1959 RtpTransceiverDirection::kStopped)};
1960 auto offer2 = f1_.CreateOffer(opts, offer.get());
1961 EXPECT_THAT(
1962 offer2->contents(),
1963 ElementsAre(Property(
1964 &ContentInfo::media_description,
1965 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1966 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1967 Field(&RtpExtension::uri, "uri2")))))));
1968}
1969
1970TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001971 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001972 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001973 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001974
1975 f1_.set_enable_encrypted_rtp_header_extensions(true);
1976 f2_.set_enable_encrypted_rtp_header_extensions(true);
1977
Markus Handell755c65d2020-06-24 01:06:10 +02001978 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1979 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001980 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001981 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001982 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1983 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001984 std::unique_ptr<SessionDescription> answer =
1985 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001986
Yves Gerey665174f2018-06-19 15:03:05 +02001987 EXPECT_EQ(
1988 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1989 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1990 EXPECT_EQ(
1991 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1992 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1993 EXPECT_EQ(
1994 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1995 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1996 EXPECT_EQ(
1997 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1998 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001999}
2000
2001TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002002 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07002003 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002004 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002005
2006 f1_.set_enable_encrypted_rtp_header_extensions(true);
2007
Markus Handell755c65d2020-06-24 01:06:10 +02002008 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2009 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002010 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002011 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002012 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2013 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002014 std::unique_ptr<SessionDescription> answer =
2015 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002016
Yves Gerey665174f2018-06-19 15:03:05 +02002017 EXPECT_EQ(
2018 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2019 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2020 EXPECT_EQ(
2021 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2022 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2023 EXPECT_EQ(
2024 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2025 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2026 EXPECT_EQ(
2027 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2028 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002029}
2030
2031TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002032 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07002033 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002034 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002035
2036 f2_.set_enable_encrypted_rtp_header_extensions(true);
2037
Markus Handell755c65d2020-06-24 01:06:10 +02002038 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2039 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002040 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002041 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002042 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2043 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002044 std::unique_ptr<SessionDescription> answer =
2045 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002046
Yves Gerey665174f2018-06-19 15:03:05 +02002047 EXPECT_EQ(
2048 MAKE_VECTOR(kAudioRtpExtension1),
2049 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2050 EXPECT_EQ(
2051 MAKE_VECTOR(kVideoRtpExtension1),
2052 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2053 EXPECT_EQ(
2054 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2055 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2056 EXPECT_EQ(
2057 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2058 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002059}
2060
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002061// Create an audio, video, data answer without legacy StreamParams.
2062TEST_F(MediaSessionDescriptionFactoryTest,
2063 TestCreateAnswerWithoutLegacyStreams) {
2064 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002065 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002066 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002067 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002068 std::unique_ptr<SessionDescription> answer =
2069 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002070 const ContentInfo* ac = answer->GetContentByName("audio");
2071 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072 ASSERT_TRUE(ac != NULL);
2073 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002074 const AudioContentDescription* acd = ac->media_description()->as_audio();
2075 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002076
2077 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2078 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002079}
2080
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081// Create a typical video answer, and ensure it matches what we expect.
2082TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2083 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002084 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002085
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002086 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002087 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002088
kwiberg31022942016-03-11 14:18:21 -08002089 std::unique_ptr<SessionDescription> offer;
2090 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002091
2092 offer_opts.rtcp_mux_enabled = true;
2093 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002094 offer = f1_.CreateOffer(offer_opts, NULL);
2095 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002096 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2097 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002098 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2099 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002100 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2101 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002102 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2103 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002104
2105 offer_opts.rtcp_mux_enabled = true;
2106 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002107 offer = f1_.CreateOffer(offer_opts, NULL);
2108 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002109 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2110 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002111 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2112 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002113 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2114 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002115 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2116 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002117
2118 offer_opts.rtcp_mux_enabled = false;
2119 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002120 offer = f1_.CreateOffer(offer_opts, NULL);
2121 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002122 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2123 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002124 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2125 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002126 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2127 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002128 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2129 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130
2131 offer_opts.rtcp_mux_enabled = false;
2132 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002133 offer = f1_.CreateOffer(offer_opts, NULL);
2134 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002135 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2136 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002137 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2138 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002139 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2140 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002141 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2142 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002143}
2144
2145// Create an audio-only answer to a video offer.
2146TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2147 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002148 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2149 RtpTransceiverDirection::kRecvOnly, kActive,
2150 &opts);
2151 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2152 RtpTransceiverDirection::kRecvOnly, kActive,
2153 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002154 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002156
2157 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002158 std::unique_ptr<SessionDescription> answer =
2159 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002160 const ContentInfo* ac = answer->GetContentByName("audio");
2161 const ContentInfo* vc = answer->GetContentByName("video");
2162 ASSERT_TRUE(ac != NULL);
2163 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002164 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002165 EXPECT_TRUE(vc->rejected);
2166}
2167
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002168// Create an answer that rejects the contents which are rejected in the offer.
2169TEST_F(MediaSessionDescriptionFactoryTest,
2170 CreateAnswerToOfferWithRejectedMedia) {
2171 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002172 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002173 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174 ASSERT_TRUE(offer.get() != NULL);
2175 ContentInfo* ac = offer->GetContentByName("audio");
2176 ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002177 ASSERT_TRUE(ac != NULL);
2178 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179 ac->rejected = true;
2180 vc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002181 std::unique_ptr<SessionDescription> answer =
2182 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002183 ac = answer->GetContentByName("audio");
2184 vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002185 ASSERT_TRUE(ac != NULL);
2186 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002187 EXPECT_TRUE(ac->rejected);
2188 EXPECT_TRUE(vc->rejected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002189}
2190
Johannes Kron0854eb62018-10-10 22:33:20 +02002191TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002192 OfferAndAnswerDoesNotHaveMixedByteSessionAttribute) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002193 MediaSessionOptions opts;
Emil Lundmark801c9992021-01-19 13:06:32 +01002194 std::unique_ptr<SessionDescription> offer =
2195 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002196 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002197
Emil Lundmark801c9992021-01-19 13:06:32 +01002198 std::unique_ptr<SessionDescription> answer(
2199 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2200
2201 EXPECT_FALSE(answer->extmap_allow_mixed());
2202}
2203
2204TEST_F(MediaSessionDescriptionFactoryTest,
2205 OfferAndAnswerHaveMixedByteSessionAttribute) {
2206 MediaSessionOptions opts;
2207 std::unique_ptr<SessionDescription> offer =
2208 f1_.CreateOffer(opts, /*current_description=*/nullptr);
Johannes Kron9581bc42018-10-23 10:17:39 +02002209 offer->set_extmap_allow_mixed(true);
Emil Lundmark801c9992021-01-19 13:06:32 +01002210
Johannes Kron0854eb62018-10-10 22:33:20 +02002211 std::unique_ptr<SessionDescription> answer_support(
Emil Lundmark801c9992021-01-19 13:06:32 +01002212 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2213
Johannes Kron9581bc42018-10-23 10:17:39 +02002214 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002215}
2216
2217TEST_F(MediaSessionDescriptionFactoryTest,
Emil Lundmark801c9992021-01-19 13:06:32 +01002218 OfferAndAnswerDoesNotHaveMixedByteMediaAttributes) {
Johannes Kron0854eb62018-10-10 22:33:20 +02002219 MediaSessionOptions opts;
2220 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Emil Lundmark801c9992021-01-19 13:06:32 +01002221 std::unique_ptr<SessionDescription> offer =
2222 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2223 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002224 MediaContentDescription* audio_offer =
2225 offer->GetContentDescriptionByName("audio");
Emil Lundmark801c9992021-01-19 13:06:32 +01002226 MediaContentDescription* video_offer =
2227 offer->GetContentDescriptionByName("video");
2228 ASSERT_EQ(MediaContentDescription::kNo,
2229 audio_offer->extmap_allow_mixed_enum());
2230 ASSERT_EQ(MediaContentDescription::kNo,
2231 video_offer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002232
Emil Lundmark801c9992021-01-19 13:06:32 +01002233 std::unique_ptr<SessionDescription> answer(
2234 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
Johannes Kron0854eb62018-10-10 22:33:20 +02002235
Johannes Kron0854eb62018-10-10 22:33:20 +02002236 MediaContentDescription* audio_answer =
Emil Lundmark801c9992021-01-19 13:06:32 +01002237 answer->GetContentDescriptionByName("audio");
2238 MediaContentDescription* video_answer =
2239 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002240 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002241 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002242 EXPECT_EQ(MediaContentDescription::kNo,
2243 video_answer->extmap_allow_mixed_enum());
2244}
Johannes Kron0854eb62018-10-10 22:33:20 +02002245
Emil Lundmark801c9992021-01-19 13:06:32 +01002246TEST_F(MediaSessionDescriptionFactoryTest,
2247 OfferAndAnswerHaveSameMixedByteMediaAttributes) {
2248 MediaSessionOptions opts;
2249 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2250 std::unique_ptr<SessionDescription> offer =
2251 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2252 offer->set_extmap_allow_mixed(false);
2253 MediaContentDescription* audio_offer =
2254 offer->GetContentDescriptionByName("audio");
Johannes Kron9581bc42018-10-23 10:17:39 +02002255 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Emil Lundmark801c9992021-01-19 13:06:32 +01002256 MediaContentDescription* video_offer =
2257 offer->GetContentDescriptionByName("video");
2258 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2259
2260 std::unique_ptr<SessionDescription> answer(
2261 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2262
2263 MediaContentDescription* audio_answer =
2264 answer->GetContentDescriptionByName("audio");
2265 MediaContentDescription* video_answer =
2266 answer->GetContentDescriptionByName("video");
Johannes Kron0854eb62018-10-10 22:33:20 +02002267 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002268 audio_answer->extmap_allow_mixed_enum());
Emil Lundmark801c9992021-01-19 13:06:32 +01002269 EXPECT_EQ(MediaContentDescription::kMedia,
2270 video_answer->extmap_allow_mixed_enum());
2271}
2272
2273TEST_F(MediaSessionDescriptionFactoryTest,
2274 OfferAndAnswerHaveDifferentMixedByteMediaAttributes) {
2275 MediaSessionOptions opts;
2276 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2277 std::unique_ptr<SessionDescription> offer =
2278 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2279 offer->set_extmap_allow_mixed(false);
2280 MediaContentDescription* audio_offer =
2281 offer->GetContentDescriptionByName("audio");
2282 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2283 MediaContentDescription* video_offer =
2284 offer->GetContentDescriptionByName("video");
2285 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2286
2287 std::unique_ptr<SessionDescription> answer(
2288 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2289
2290 MediaContentDescription* audio_answer =
2291 answer->GetContentDescriptionByName("audio");
2292 MediaContentDescription* video_answer =
2293 answer->GetContentDescriptionByName("video");
2294 EXPECT_EQ(MediaContentDescription::kNo,
2295 audio_answer->extmap_allow_mixed_enum());
2296 EXPECT_EQ(MediaContentDescription::kMedia,
2297 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002298}
2299
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002300// Create an audio and video offer with:
2301// - one video track
2302// - two audio tracks
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002303// and ensure it matches what we expect. Also updates the initial offer by
2304// adding a new video track and replaces one of the audio tracks.
2305TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2306 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002307 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002308 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2309 {kMediaStream1}, 1, &opts);
2310 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2311 {kMediaStream1}, 1, &opts);
2312 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2313 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002314
Harald Alvestrand0d018412021-11-04 13:52:31 +00002315 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002316 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002317
2318 ASSERT_TRUE(offer.get() != NULL);
2319 const ContentInfo* ac = offer->GetContentByName("audio");
2320 const ContentInfo* vc = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002321 ASSERT_TRUE(ac != NULL);
2322 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002323 const AudioContentDescription* acd = ac->media_description()->as_audio();
2324 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002325 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002326 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002327
2328 const StreamParamsVec& audio_streams = acd->streams();
2329 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002330 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002331 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2332 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2333 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2334 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2335 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2336 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2337
2338 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2339 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Harald Alvestrand0d018412021-11-04 13:52:31 +00002340 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002341
2342 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002343 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002344 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002345
2346 const StreamParamsVec& video_streams = vcd->streams();
2347 ASSERT_EQ(1U, video_streams.size());
2348 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2349 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2350 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2351 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2352
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002353 // Update the offer. Add a new video track that is not synched to the
2354 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002355 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2356 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002357 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002358 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2359 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002360 std::unique_ptr<SessionDescription> updated_offer(
2361 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002362
2363 ASSERT_TRUE(updated_offer.get() != NULL);
2364 ac = updated_offer->GetContentByName("audio");
2365 vc = updated_offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002366 ASSERT_TRUE(ac != NULL);
2367 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002368 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002369 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002370 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002371 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002372
2373 EXPECT_EQ(acd->type(), updated_acd->type());
2374 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2375 EXPECT_EQ(vcd->type(), updated_vcd->type());
2376 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
Harald Alvestrand0d018412021-11-04 13:52:31 +00002377 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2378 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2379 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2380 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002381
2382 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2383 ASSERT_EQ(2U, updated_audio_streams.size());
2384 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2385 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2386 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2387 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2388 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2389
2390 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2391 ASSERT_EQ(2U, updated_video_streams.size());
2392 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2393 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002394 // All the media streams in one PeerConnection share one RTCP CNAME.
2395 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002396}
2397
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002398// Create an offer with simulcast video stream.
2399TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2400 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002401 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2402 RtpTransceiverDirection::kRecvOnly, kActive,
2403 &opts);
2404 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2405 RtpTransceiverDirection::kSendRecv, kActive,
2406 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002407 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002408 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2409 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002410 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002411
2412 ASSERT_TRUE(offer.get() != NULL);
2413 const ContentInfo* vc = offer->GetContentByName("video");
2414 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002415 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002416
2417 const StreamParamsVec& video_streams = vcd->streams();
2418 ASSERT_EQ(1U, video_streams.size());
2419 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2420 const SsrcGroup* sim_ssrc_group =
2421 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2422 ASSERT_TRUE(sim_ssrc_group != NULL);
2423 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2424}
2425
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002426MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2427 const RidDescription& rid1 = ::testing::get<0>(arg);
2428 const RidDescription& rid2 = ::testing::get<1>(arg);
2429 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2430}
2431
2432static void CheckSimulcastInSessionDescription(
2433 const SessionDescription* description,
2434 const std::string& content_name,
2435 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002436 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002437 ASSERT_NE(description, nullptr);
2438 const ContentInfo* content = description->GetContentByName(content_name);
2439 ASSERT_NE(content, nullptr);
2440 const MediaContentDescription* cd = content->media_description();
2441 ASSERT_NE(cd, nullptr);
2442 const StreamParamsVec& streams = cd->streams();
2443 ASSERT_THAT(streams, SizeIs(1));
2444 const StreamParams& stream = streams[0];
2445 ASSERT_THAT(stream.ssrcs, IsEmpty());
2446 EXPECT_TRUE(stream.has_rids());
2447 const std::vector<RidDescription> rids = stream.rids();
2448
2449 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2450
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002451 EXPECT_TRUE(cd->HasSimulcast());
2452 const SimulcastDescription& simulcast = cd->simulcast_description();
2453 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2454 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2455
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002456 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002457}
2458
2459// Create an offer with spec-compliant simulcast video stream.
2460TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2461 MediaSessionOptions opts;
2462 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2463 RtpTransceiverDirection::kSendRecv, kActive,
2464 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002465 std::vector<RidDescription> send_rids;
2466 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2467 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2468 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2469 SimulcastLayerList simulcast_layers;
2470 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2471 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2472 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2473 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2474 {kMediaStream1}, send_rids,
2475 simulcast_layers, 0, &opts);
2476 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2477
2478 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002479 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002480}
2481
2482// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2483// In this scenario, RIDs do not need to be negotiated (there is only one).
2484TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2485 MediaSessionOptions opts;
2486 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2487 RtpTransceiverDirection::kSendRecv, kActive,
2488 &opts);
2489 RidDescription rid("f", RidDirection::kSend);
2490 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2491 {kMediaStream1}, {rid},
2492 SimulcastLayerList(), 0, &opts);
2493 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2494
2495 ASSERT_NE(offer.get(), nullptr);
2496 const ContentInfo* content = offer->GetContentByName("video");
2497 ASSERT_NE(content, nullptr);
2498 const MediaContentDescription* cd = content->media_description();
2499 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002500 const StreamParamsVec& streams = cd->streams();
2501 ASSERT_THAT(streams, SizeIs(1));
2502 const StreamParams& stream = streams[0];
2503 ASSERT_THAT(stream.ssrcs, IsEmpty());
2504 EXPECT_FALSE(stream.has_rids());
2505 EXPECT_FALSE(cd->HasSimulcast());
2506}
2507
2508// Create an answer with spec-compliant simulcast video stream.
2509// In this scenario, the SFU is the caller requesting that we send Simulcast.
2510TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2511 MediaSessionOptions offer_opts;
2512 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2513 RtpTransceiverDirection::kSendRecv, kActive,
2514 &offer_opts);
2515 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2516 {kMediaStream1}, 1, &offer_opts);
2517 std::unique_ptr<SessionDescription> offer =
2518 f1_.CreateOffer(offer_opts, nullptr);
2519
2520 MediaSessionOptions answer_opts;
2521 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2522 RtpTransceiverDirection::kSendRecv, kActive,
2523 &answer_opts);
2524
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002525 std::vector<RidDescription> rid_descriptions{
2526 RidDescription("f", RidDirection::kSend),
2527 RidDescription("h", RidDirection::kSend),
2528 RidDescription("q", RidDirection::kSend),
2529 };
2530 SimulcastLayerList simulcast_layers;
2531 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2532 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2533 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2534 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2535 {kMediaStream1}, rid_descriptions,
2536 simulcast_layers, 0, &answer_opts);
2537 std::unique_ptr<SessionDescription> answer =
2538 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2539
2540 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002541 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002542}
2543
2544// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2545// In this scenario, RIDs do not need to be negotiated (there is only one).
2546// Note that RID Direction is not the same as the transceiver direction.
2547TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2548 MediaSessionOptions offer_opts;
2549 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2550 RtpTransceiverDirection::kSendRecv, kActive,
2551 &offer_opts);
2552 RidDescription rid_offer("f", RidDirection::kSend);
2553 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2554 {kMediaStream1}, {rid_offer},
2555 SimulcastLayerList(), 0, &offer_opts);
2556 std::unique_ptr<SessionDescription> offer =
2557 f1_.CreateOffer(offer_opts, nullptr);
2558
2559 MediaSessionOptions answer_opts;
2560 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2561 RtpTransceiverDirection::kSendRecv, kActive,
2562 &answer_opts);
2563
2564 RidDescription rid_answer("f", RidDirection::kReceive);
2565 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2566 {kMediaStream1}, {rid_answer},
2567 SimulcastLayerList(), 0, &answer_opts);
2568 std::unique_ptr<SessionDescription> answer =
2569 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2570
2571 ASSERT_NE(answer.get(), nullptr);
2572 const ContentInfo* content = offer->GetContentByName("video");
2573 ASSERT_NE(content, nullptr);
2574 const MediaContentDescription* cd = content->media_description();
2575 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002576 const StreamParamsVec& streams = cd->streams();
2577 ASSERT_THAT(streams, SizeIs(1));
2578 const StreamParams& stream = streams[0];
2579 ASSERT_THAT(stream.ssrcs, IsEmpty());
2580 EXPECT_FALSE(stream.has_rids());
2581 EXPECT_FALSE(cd->HasSimulcast());
2582}
2583
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002584// Create an audio and video answer to a standard video offer with:
2585// - one video track
2586// - two audio tracks
2587// - two data tracks
2588// and ensure it matches what we expect. Also updates the initial answer by
2589// adding a new video track and removes one of the audio tracks.
2590TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2591 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002592 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2593 RtpTransceiverDirection::kRecvOnly, kActive,
2594 &offer_opts);
2595 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2596 RtpTransceiverDirection::kRecvOnly, kActive,
2597 &offer_opts);
Harald Alvestrand0d018412021-11-04 13:52:31 +00002598 f1_.set_secure(SEC_ENABLED);
2599 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002600 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002601
zhihuang1c378ed2017-08-17 14:10:50 -07002602 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002603 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2604 RtpTransceiverDirection::kSendRecv, kActive,
2605 &answer_opts);
2606 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2607 RtpTransceiverDirection::kSendRecv, kActive,
2608 &answer_opts);
2609 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2610 {kMediaStream1}, 1, &answer_opts);
2611 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2612 {kMediaStream1}, 1, &answer_opts);
2613 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2614 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002615
Steve Anton6fe1fba2018-12-11 10:15:23 -08002616 std::unique_ptr<SessionDescription> answer =
2617 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002618
2619 ASSERT_TRUE(answer.get() != NULL);
2620 const ContentInfo* ac = answer->GetContentByName("audio");
2621 const ContentInfo* vc = answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002622 ASSERT_TRUE(ac != NULL);
2623 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002624 const AudioContentDescription* acd = ac->media_description()->as_audio();
2625 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand0d018412021-11-04 13:52:31 +00002626 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2627 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002628
2629 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002630 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002631
2632 const StreamParamsVec& audio_streams = acd->streams();
2633 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002634 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002635 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2636 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2637 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2638 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2639 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2640 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2641
2642 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2643 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2644
2645 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002646 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002647
2648 const StreamParamsVec& video_streams = vcd->streams();
2649 ASSERT_EQ(1U, video_streams.size());
2650 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2651 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2652 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2653 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2654
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002655 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002656 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002657 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2658 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002659 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002660 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002661 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002662
2663 ASSERT_TRUE(updated_answer.get() != NULL);
2664 ac = updated_answer->GetContentByName("audio");
2665 vc = updated_answer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002666 ASSERT_TRUE(ac != NULL);
2667 ASSERT_TRUE(vc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002668 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002669 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002671 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002672
Harald Alvestrand0d018412021-11-04 13:52:31 +00002673 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2674 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2675 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2676 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
2677
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002678 EXPECT_EQ(acd->type(), updated_acd->type());
2679 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2680 EXPECT_EQ(vcd->type(), updated_vcd->type());
2681 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002682
2683 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2684 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002685 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686
2687 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2688 ASSERT_EQ(2U, updated_video_streams.size());
2689 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2690 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002691 // All media streams in one PeerConnection share one CNAME.
2692 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002693}
2694
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002695// Create an updated offer after creating an answer to the original offer and
2696// verify that the codecs that were part of the original answer are not changed
2697// in the updated offer.
2698TEST_F(MediaSessionDescriptionFactoryTest,
2699 RespondentCreatesOfferAfterCreatingAnswer) {
2700 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002701 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002702
Steve Anton6fe1fba2018-12-11 10:15:23 -08002703 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2704 std::unique_ptr<SessionDescription> answer =
2705 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002706
2707 const AudioContentDescription* acd =
2708 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002709 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002710
2711 const VideoContentDescription* vcd =
2712 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002713 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714
kwiberg31022942016-03-11 14:18:21 -08002715 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716 f2_.CreateOffer(opts, answer.get()));
2717
2718 // The expected audio codecs are the common audio codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002719 // offer/answer exchange plus the audio codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720 // preference order.
Artem Titov880fa812021-07-30 22:30:23 +02002721 // TODO(wu): `updated_offer` should not include the codec
Artem Titovcfea2182021-08-10 01:22:31 +02002722 // (i.e. `kAudioCodecs2[0]`) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002723 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002724 kAudioCodecsAnswer[0],
2725 kAudioCodecsAnswer[1],
2726 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002727 };
2728
2729 // The expected video codecs are the common video codecs from the first
Artem Titov880fa812021-07-30 22:30:23 +02002730 // offer/answer exchange plus the video codecs only `f2_` offer, sorted in
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002731 // preference order.
2732 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002733 kVideoCodecsAnswer[0],
2734 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002735 };
2736
2737 const AudioContentDescription* updated_acd =
2738 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002739 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002740
2741 const VideoContentDescription* updated_vcd =
2742 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002743 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002744}
2745
Steve Anton5c72e712018-12-10 14:25:30 -08002746// Test that a reoffer does not reuse audio codecs from a previous media section
2747// that is being recycled.
2748TEST_F(MediaSessionDescriptionFactoryTest,
2749 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002750 f1_.set_video_codecs({}, {});
2751 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002752
2753 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002754 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2755 RtpTransceiverDirection::kSendRecv, kActive,
2756 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002757 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2758 std::unique_ptr<SessionDescription> answer =
2759 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002760
2761 // Recycle the media section by changing its mid.
2762 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002763 std::unique_ptr<SessionDescription> reoffer =
2764 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002765
2766 // Expect that the results of the first negotiation are ignored. If the m=
2767 // section was not recycled the payload types would match the initial offerer.
2768 const AudioContentDescription* acd =
2769 GetFirstAudioContentDescription(reoffer.get());
2770 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2771}
2772
2773// Test that a reoffer does not reuse video codecs from a previous media section
2774// that is being recycled.
2775TEST_F(MediaSessionDescriptionFactoryTest,
2776 ReOfferDoesNotReUseRecycledVideoCodecs) {
2777 f1_.set_audio_codecs({}, {});
2778 f2_.set_audio_codecs({}, {});
2779
2780 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002781 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2782 RtpTransceiverDirection::kSendRecv, kActive,
2783 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002784 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2785 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002786
2787 // Recycle the media section by changing its mid.
2788 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002789 std::unique_ptr<SessionDescription> reoffer =
2790 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002791
2792 // Expect that the results of the first negotiation are ignored. If the m=
2793 // section was not recycled the payload types would match the initial offerer.
2794 const VideoContentDescription* vcd =
2795 GetFirstVideoContentDescription(reoffer.get());
2796 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2797}
2798
2799// Test that a reanswer does not reuse audio codecs from a previous media
2800// section that is being recycled.
2801TEST_F(MediaSessionDescriptionFactoryTest,
2802 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002803 f1_.set_video_codecs({}, {});
2804 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002805
Artem Titov880fa812021-07-30 22:30:23 +02002806 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2807 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002808 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002809 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2810 RtpTransceiverDirection::kSendRecv, kActive,
2811 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002812 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2813 std::unique_ptr<SessionDescription> answer =
2814 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002815
2816 // Recycle the media section by changing its mid.
2817 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002818 std::unique_ptr<SessionDescription> reoffer =
2819 f1_.CreateOffer(opts, answer.get());
2820 std::unique_ptr<SessionDescription> reanswer =
2821 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002822
2823 // Expect that the results of the first negotiation are ignored. If the m=
2824 // section was not recycled the payload types would match the initial offerer.
2825 const AudioContentDescription* acd =
2826 GetFirstAudioContentDescription(reanswer.get());
2827 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2828}
2829
2830// Test that a reanswer does not reuse video codecs from a previous media
2831// section that is being recycled.
2832TEST_F(MediaSessionDescriptionFactoryTest,
2833 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2834 f1_.set_audio_codecs({}, {});
2835 f2_.set_audio_codecs({}, {});
2836
Artem Titov880fa812021-07-30 22:30:23 +02002837 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2838 // second offer/answer is forward (`f1_` as offerer).
Steve Anton5c72e712018-12-10 14:25:30 -08002839 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002840 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2841 RtpTransceiverDirection::kSendRecv, kActive,
2842 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002843 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2844 std::unique_ptr<SessionDescription> answer =
2845 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002846
2847 // Recycle the media section by changing its mid.
2848 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002849 std::unique_ptr<SessionDescription> reoffer =
2850 f1_.CreateOffer(opts, answer.get());
2851 std::unique_ptr<SessionDescription> reanswer =
2852 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002853
2854 // Expect that the results of the first negotiation are ignored. If the m=
2855 // section was not recycled the payload types would match the initial offerer.
2856 const VideoContentDescription* vcd =
2857 GetFirstVideoContentDescription(reanswer.get());
2858 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2859}
2860
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861// Create an updated offer after creating an answer to the original offer and
2862// verify that the codecs that were part of the original answer are not changed
2863// in the updated offer. In this test Rtx is enabled.
2864TEST_F(MediaSessionDescriptionFactoryTest,
2865 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2866 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002867 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2868 RtpTransceiverDirection::kRecvOnly, kActive,
2869 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002870 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02002871 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002872 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002873 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874
2875 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02002876 // This creates rtx for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002877 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002878 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002879
Steve Anton6fe1fba2018-12-11 10:15:23 -08002880 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002881 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002882 std::unique_ptr<SessionDescription> answer =
2883 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002884
2885 const VideoContentDescription* vcd =
2886 GetFirstVideoContentDescription(answer.get());
2887
2888 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002889 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2890 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002891
2892 EXPECT_EQ(expected_codecs, vcd->codecs());
2893
Artem Titov880fa812021-07-30 22:30:23 +02002894 // Now, make sure we get same result (except for the order) if `f2_` creates
2895 // an updated offer even though the default payload types between `f1_` and
2896 // `f2_` are different.
kwiberg31022942016-03-11 14:18:21 -08002897 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002898 f2_.CreateOffer(opts, answer.get()));
2899 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002900 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002901 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2902
2903 const VideoContentDescription* updated_vcd =
2904 GetFirstVideoContentDescription(updated_answer.get());
2905
2906 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2907}
2908
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002909// Regression test for:
2910// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2911// Existing codecs should always appear before new codecs in re-offers. But
2912// under a specific set of circumstances, the existing RTX codec was ending up
2913// added to the end of the list.
2914TEST_F(MediaSessionDescriptionFactoryTest,
2915 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2916 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002917 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2918 RtpTransceiverDirection::kRecvOnly, kActive,
2919 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002920 // We specifically choose different preferred payload types for VP8 to
2921 // trigger the issue.
2922 cricket::VideoCodec vp8_offerer(100, "VP8");
2923 cricket::VideoCodec vp8_offerer_rtx =
2924 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2925 cricket::VideoCodec vp8_answerer(110, "VP8");
2926 cricket::VideoCodec vp8_answerer_rtx =
2927 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2928 cricket::VideoCodec vp9(120, "VP9");
2929 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2930
2931 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2932 // We also specifically cause the answerer to prefer VP9, such that if it
2933 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2934 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2935 vp8_answerer_rtx};
2936
Johannes Kron3e983682020-03-29 22:17:00 +02002937 f1_.set_video_codecs(f1_codecs, f1_codecs);
2938 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002939 std::vector<AudioCodec> audio_codecs;
2940 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2941 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2942
2943 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002944 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002945 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002946 std::unique_ptr<SessionDescription> answer =
2947 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002948
2949 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2950 // But if the bug is triggered, RTX for VP8 ends up last.
2951 std::unique_ptr<SessionDescription> updated_offer(
2952 f2_.CreateOffer(opts, answer.get()));
2953
2954 const VideoContentDescription* vcd =
2955 GetFirstVideoContentDescription(updated_offer.get());
2956 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2957 ASSERT_EQ(4u, codecs.size());
2958 EXPECT_EQ(vp8_offerer, codecs[0]);
2959 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2960 EXPECT_EQ(vp9, codecs[2]);
2961 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002962}
2963
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002964// Create an updated offer that adds video after creating an audio only answer
2965// to the original offer. This test verifies that if a video codec and the RTX
2966// codec have the same default payload type as an audio codec that is already in
2967// use, the added codecs payload types are changed.
2968TEST_F(MediaSessionDescriptionFactoryTest,
2969 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2970 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
Artem Titov880fa812021-07-30 22:30:23 +02002971 // This creates rtx for H264 with the payload type `f1_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002972 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002973 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974
2975 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002976 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2977 RtpTransceiverDirection::kRecvOnly, kActive,
2978 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002979
Steve Anton6fe1fba2018-12-11 10:15:23 -08002980 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2981 std::unique_ptr<SessionDescription> answer =
2982 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002983
2984 const AudioContentDescription* acd =
2985 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002986 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002987
Artem Titov880fa812021-07-30 22:30:23 +02002988 // Now - let `f2_` add video with RTX and let the payload type the RTX codec
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002989 // reference be the same as an audio codec that was negotiated in the
2990 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002991 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002992 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002993
2994 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2995 int used_pl_type = acd->codecs()[0].id;
2996 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002997 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002998 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002999
kwiberg31022942016-03-11 14:18:21 -08003000 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003001 f2_.CreateOffer(opts, answer.get()));
3002 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003003 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003004 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3005
3006 const AudioContentDescription* updated_acd =
3007 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003008 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003009
3010 const VideoContentDescription* updated_vcd =
3011 GetFirstVideoContentDescription(updated_answer.get());
3012
3013 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003014 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003015 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003016 EXPECT_NE(used_pl_type, new_h264_pl_type);
3017 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003018 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003019 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3020 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3021}
3022
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003023// Create an updated offer with RTX after creating an answer to an offer
3024// without RTX, and with different default payload types.
3025// Verify that the added RTX codec references the correct payload type.
3026TEST_F(MediaSessionDescriptionFactoryTest,
3027 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3028 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003029 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003030
3031 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003032 // This creates rtx for H264 with the payload type `f2_` uses.
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003033 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003034 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003035
Steve Anton6fe1fba2018-12-11 10:15:23 -08003036 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003037 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003038 std::unique_ptr<SessionDescription> answer =
3039 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003040
3041 const VideoContentDescription* vcd =
3042 GetFirstVideoContentDescription(answer.get());
3043
3044 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3045 EXPECT_EQ(expected_codecs, vcd->codecs());
3046
Artem Titov880fa812021-07-30 22:30:23 +02003047 // Now, ensure that the RTX codec is created correctly when `f2_` creates an
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003048 // updated offer, even though the default payload types are different from
Artem Titov880fa812021-07-30 22:30:23 +02003049 // those of `f1_`.
kwiberg31022942016-03-11 14:18:21 -08003050 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003051 f2_.CreateOffer(opts, answer.get()));
3052 ASSERT_TRUE(updated_offer);
3053
3054 const VideoContentDescription* updated_vcd =
3055 GetFirstVideoContentDescription(updated_offer.get());
3056
3057 // New offer should attempt to add H263, and RTX for H264.
3058 expected_codecs.push_back(kVideoCodecs2[1]);
3059 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3060 &expected_codecs);
3061 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3062}
3063
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003064// Test that RTX is ignored when there is no associated payload type parameter.
3065TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3066 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003067 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3068 RtpTransceiverDirection::kRecvOnly, kActive,
3069 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003070 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003071 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003072 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003073 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003074
3075 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
Artem Titov880fa812021-07-30 22:30:23 +02003076 // This creates RTX for H264 with the payload type `f2_` uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003077 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &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
Steve Anton6fe1fba2018-12-11 10:15:23 -08003080 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003081 ASSERT_TRUE(offer.get() != NULL);
3082 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3083 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3084 // is possible to test that that RTX is dropped when
3085 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003086 MediaContentDescription* media_desc =
3087 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3088 ASSERT_TRUE(media_desc);
3089 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003090 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003091 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003092 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003093 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003094 }
3095 }
3096 desc->set_codecs(codecs);
3097
Steve Anton6fe1fba2018-12-11 10:15:23 -08003098 std::unique_ptr<SessionDescription> answer =
3099 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003100
Steve Anton64b626b2019-01-28 17:25:26 -08003101 EXPECT_THAT(
3102 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3103 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003104}
3105
3106// Test that RTX will be filtered out in the answer if its associated payload
3107// type doesn't match the local value.
3108TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3109 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003110 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3111 RtpTransceiverDirection::kRecvOnly, kActive,
3112 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003113 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3114 // This creates RTX for H264 in sender.
3115 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003116 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003117
3118 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3119 // This creates RTX for H263 in receiver.
3120 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003121 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003122
Steve Anton6fe1fba2018-12-11 10:15:23 -08003123 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003124 ASSERT_TRUE(offer.get() != NULL);
3125 // Associated payload type doesn't match, therefore, RTX codec is removed in
3126 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003127 std::unique_ptr<SessionDescription> answer =
3128 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003129
Steve Anton64b626b2019-01-28 17:25:26 -08003130 EXPECT_THAT(
3131 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3132 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003133}
3134
3135// Test that when multiple RTX codecs are offered, only the matched RTX codec
3136// is added in the answer, and the unsupported RTX codec is filtered out.
3137TEST_F(MediaSessionDescriptionFactoryTest,
3138 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3139 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003140 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3141 RtpTransceiverDirection::kRecvOnly, kActive,
3142 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003143 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3144 // This creates RTX for H264-SVC in sender.
3145 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003146 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003147
3148 // This creates RTX for H264 in sender.
3149 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003150 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003151
3152 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3153 // This creates RTX for H264 in receiver.
3154 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003155 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003156
3157 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3158 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003159 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003160 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003161 std::unique_ptr<SessionDescription> answer =
3162 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003163 const VideoContentDescription* vcd =
3164 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003165 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3166 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3167 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003168
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003169 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003170}
3171
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003172// Test that after one RTX codec has been negotiated, a new offer can attempt
3173// to add another.
3174TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3175 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003176 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3177 RtpTransceiverDirection::kRecvOnly, kActive,
3178 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003179 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3180 // This creates RTX for H264 for the offerer.
3181 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003182 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003183
Steve Anton6fe1fba2018-12-11 10:15:23 -08003184 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003185 ASSERT_TRUE(offer);
3186 const VideoContentDescription* vcd =
3187 GetFirstVideoContentDescription(offer.get());
3188
3189 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3190 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3191 &expected_codecs);
3192 EXPECT_EQ(expected_codecs, vcd->codecs());
3193
3194 // Now, attempt to add RTX for H264-SVC.
3195 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003196 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003197
kwiberg31022942016-03-11 14:18:21 -08003198 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003199 f1_.CreateOffer(opts, offer.get()));
3200 ASSERT_TRUE(updated_offer);
3201 vcd = GetFirstVideoContentDescription(updated_offer.get());
3202
3203 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3204 &expected_codecs);
3205 EXPECT_EQ(expected_codecs, vcd->codecs());
3206}
3207
Noah Richards2e7a0982015-05-18 14:02:54 -07003208// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3209// generated for each simulcast ssrc and correctly grouped.
3210TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3211 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003212 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3213 RtpTransceiverDirection::kSendRecv, kActive,
3214 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003215 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003216 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3217 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003218
3219 // Use a single real codec, and then add RTX for it.
3220 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003221 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003222 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003223 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003224
3225 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3226 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003227 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003228 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003229 MediaContentDescription* media_desc =
3230 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3231 ASSERT_TRUE(media_desc);
3232 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003233 const StreamParamsVec& streams = desc->streams();
3234 // Single stream.
3235 ASSERT_EQ(1u, streams.size());
3236 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3237 EXPECT_EQ(6u, streams[0].ssrcs.size());
3238 // And should have a SIM group for the simulcast.
3239 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3240 // And a FID group for RTX.
3241 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003242 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003243 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3244 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003245 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003246 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3247 EXPECT_EQ(3u, fid_ssrcs.size());
3248}
3249
brandtr03d5fb12016-11-22 03:37:59 -08003250// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003251// together with a FEC-FR grouping. Guarded by WebRTC-FlexFEC-03 trial.
brandtr03d5fb12016-11-22 03:37:59 -08003252TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003253 webrtc::test::ScopedFieldTrials override_field_trials(
3254 "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003255 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003256 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3257 RtpTransceiverDirection::kSendRecv, kActive,
3258 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003259 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003260 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3261 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003262
3263 // Use a single real codec, and then add FlexFEC for it.
3264 std::vector<VideoCodec> f1_codecs;
3265 f1_codecs.push_back(VideoCodec(97, "H264"));
3266 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003267 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003268
3269 // Ensure that the offer has a single FlexFEC ssrc and that
3270 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003271 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003272 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003273 MediaContentDescription* media_desc =
3274 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3275 ASSERT_TRUE(media_desc);
3276 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003277 const StreamParamsVec& streams = desc->streams();
3278 // Single stream.
3279 ASSERT_EQ(1u, streams.size());
3280 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3281 EXPECT_EQ(2u, streams[0].ssrcs.size());
3282 // And should have a FEC-FR group for FlexFEC.
3283 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3284 std::vector<uint32_t> primary_ssrcs;
3285 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3286 ASSERT_EQ(1u, primary_ssrcs.size());
3287 uint32_t flexfec_ssrc;
3288 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3289 EXPECT_NE(flexfec_ssrc, 0u);
3290}
3291
3292// Test that FlexFEC is disabled for simulcast.
3293// TODO(brandtr): Remove this test when we support simulcast, either through
3294// multiple FlexfecSenders, or through multistream protection.
3295TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
Philipp Hanckefedc7ab2020-11-17 21:59:12 +01003296 webrtc::test::ScopedFieldTrials override_field_trials(
3297 "WebRTC-FlexFEC-03/Enabled/");
brandtr03d5fb12016-11-22 03:37:59 -08003298 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003299 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3300 RtpTransceiverDirection::kSendRecv, kActive,
3301 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003302 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003303 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3304 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003305
3306 // Use a single real codec, and then add FlexFEC for it.
3307 std::vector<VideoCodec> f1_codecs;
3308 f1_codecs.push_back(VideoCodec(97, "H264"));
3309 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003310 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003311
3312 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3313 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003314 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003315 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003316 MediaContentDescription* media_desc =
3317 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3318 ASSERT_TRUE(media_desc);
3319 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003320 const StreamParamsVec& streams = desc->streams();
3321 // Single stream.
3322 ASSERT_EQ(1u, streams.size());
3323 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3324 EXPECT_EQ(3u, streams[0].ssrcs.size());
3325 // And should have a SIM group for the simulcast.
3326 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3327 // And not a FEC-FR group for FlexFEC.
3328 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3329 std::vector<uint32_t> primary_ssrcs;
3330 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3331 EXPECT_EQ(3u, primary_ssrcs.size());
3332 for (uint32_t primary_ssrc : primary_ssrcs) {
3333 uint32_t flexfec_ssrc;
3334 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3335 }
3336}
3337
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003338// Create an updated offer after creating an answer to the original offer and
3339// verify that the RTP header extensions that were part of the original answer
3340// are not changed in the updated offer.
3341TEST_F(MediaSessionDescriptionFactoryTest,
3342 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3343 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003344 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003345
Markus Handell755c65d2020-06-24 01:06:10 +02003346 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3347 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003348 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02003349 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3350 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003351 std::unique_ptr<SessionDescription> answer =
3352 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003353
Yves Gerey665174f2018-06-19 15:03:05 +02003354 EXPECT_EQ(
3355 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3356 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3357 EXPECT_EQ(
3358 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3359 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003360
kwiberg31022942016-03-11 14:18:21 -08003361 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003362 f2_.CreateOffer(opts, answer.get()));
3363
3364 // The expected RTP header extensions in the new offer are the resulting
3365 // extensions from the first offer/answer exchange plus the extensions only
Artem Titov880fa812021-07-30 22:30:23 +02003366 // `f2_` offer.
3367 // Since the default local extension id `f2_` uses has already been used by
3368 // `f1_` for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003369 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003370 kAudioRtpExtensionAnswer[0],
3371 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003372 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003373 };
3374
Artem Titov880fa812021-07-30 22:30:23 +02003375 // Since the default local extension id `f2_` uses has already been used by
3376 // `f1_` for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003377 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003378 kVideoRtpExtensionAnswer[0],
3379 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003380 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003381 };
3382
3383 const AudioContentDescription* updated_acd =
3384 GetFirstAudioContentDescription(updated_offer.get());
3385 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3386 updated_acd->rtp_header_extensions());
3387
3388 const VideoContentDescription* updated_vcd =
3389 GetFirstVideoContentDescription(updated_offer.get());
3390 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3391 updated_vcd->rtp_header_extensions());
3392}
3393
deadbeefa5b273a2015-08-20 17:30:13 -07003394// Verify that if the same RTP extension URI is used for audio and video, the
3395// same ID is used. Also verify that the ID isn't changed when creating an
3396// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003397TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003398 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003399 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003400
Markus Handell755c65d2020-06-24 01:06:10 +02003401 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3402 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003403 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003404
3405 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3406 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003407 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003408 kVideoRtpExtension3[0],
3409 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003410 };
3411
Yves Gerey665174f2018-06-19 15:03:05 +02003412 EXPECT_EQ(
3413 MAKE_VECTOR(kAudioRtpExtension3),
3414 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3415 EXPECT_EQ(
3416 MAKE_VECTOR(kExpectedVideoRtpExtension),
3417 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003418
3419 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003420 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003421 f1_.CreateOffer(opts, offer.get()));
3422
3423 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003424 GetFirstAudioContentDescription(updated_offer.get())
3425 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003426 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003427 GetFirstVideoContentDescription(updated_offer.get())
3428 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003429}
3430
jbauch5869f502017-06-29 12:31:36 -07003431// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3432TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3433 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003434 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003435
3436 f1_.set_enable_encrypted_rtp_header_extensions(true);
3437 f2_.set_enable_encrypted_rtp_header_extensions(true);
3438
Markus Handell755c65d2020-06-24 01:06:10 +02003439 SetAudioVideoRtpHeaderExtensions(
3440 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3441 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003442 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003443
Yves Gerey665174f2018-06-19 15:03:05 +02003444 EXPECT_EQ(
3445 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3446 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3447 EXPECT_EQ(
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003448 MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003449 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003450
3451 // Nothing should change when creating a new offer
3452 std::unique_ptr<SessionDescription> updated_offer(
3453 f1_.CreateOffer(opts, offer.get()));
3454
3455 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003456 GetFirstAudioContentDescription(updated_offer.get())
3457 ->rtp_header_extensions());
Lennart Grahl0d0ed762021-05-17 16:06:37 +02003458 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003459 GetFirstVideoContentDescription(updated_offer.get())
3460 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003461}
3462
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003463TEST(MediaSessionDescription, CopySessionDescription) {
3464 SessionDescription source;
3465 cricket::ContentGroup group(cricket::CN_AUDIO);
3466 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003467 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003468 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003469 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3470 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003471 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003472 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003473 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003474 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3475 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003476 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003477
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003478 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003479 ASSERT_TRUE(copy.get() != NULL);
3480 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3481 const ContentInfo* ac = copy->GetContentByName("audio");
3482 const ContentInfo* vc = copy->GetContentByName("video");
3483 ASSERT_TRUE(ac != NULL);
3484 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003485 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003486 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003487 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3488 EXPECT_EQ(1u, acd->first_ssrc());
3489
Steve Anton5adfafd2017-12-20 16:34:00 -08003490 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003491 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003492 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3493 EXPECT_EQ(2u, vcd->first_ssrc());
3494}
3495
3496// The below TestTransportInfoXXX tests create different offers/answers, and
3497// ensure the TransportInfo in the SessionDescription matches what we expect.
3498TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3499 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003500 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3501 RtpTransceiverDirection::kRecvOnly, kActive,
3502 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003503 TestTransportInfo(true, options, false);
3504}
3505
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003506TEST_F(MediaSessionDescriptionFactoryTest,
3507 TestTransportInfoOfferIceRenomination) {
3508 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003509 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3510 RtpTransceiverDirection::kRecvOnly, kActive,
3511 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003512 options.media_description_options[0]
3513 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003514 TestTransportInfo(true, options, false);
3515}
3516
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003517TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3518 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003519 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3520 RtpTransceiverDirection::kRecvOnly, kActive,
3521 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003522 TestTransportInfo(true, options, true);
3523}
3524
3525TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3526 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003527 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003528 TestTransportInfo(true, options, false);
3529}
3530
3531TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003532 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003533 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003534 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003535 TestTransportInfo(true, options, true);
3536}
3537
3538TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3539 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003540 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003541 options.bundle_enabled = true;
3542 TestTransportInfo(true, options, false);
3543}
3544
3545TEST_F(MediaSessionDescriptionFactoryTest,
3546 TestTransportInfoOfferBundleCurrent) {
3547 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003548 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003549 options.bundle_enabled = true;
3550 TestTransportInfo(true, options, true);
3551}
3552
3553TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3554 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003555 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3556 RtpTransceiverDirection::kRecvOnly, kActive,
3557 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003558 TestTransportInfo(false, options, false);
3559}
3560
3561TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003562 TestTransportInfoAnswerIceRenomination) {
3563 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003564 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3565 RtpTransceiverDirection::kRecvOnly, kActive,
3566 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003567 options.media_description_options[0]
3568 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003569 TestTransportInfo(false, options, false);
3570}
3571
3572TEST_F(MediaSessionDescriptionFactoryTest,
3573 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003574 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003575 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3576 RtpTransceiverDirection::kRecvOnly, kActive,
3577 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003578 TestTransportInfo(false, options, true);
3579}
3580
3581TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3582 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003583 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003584 TestTransportInfo(false, options, false);
3585}
3586
3587TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003588 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003589 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003590 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003591 TestTransportInfo(false, options, true);
3592}
3593
3594TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3595 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003596 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003597 options.bundle_enabled = true;
3598 TestTransportInfo(false, options, false);
3599}
3600
3601TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003602 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003603 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003604 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003605 options.bundle_enabled = true;
3606 TestTransportInfo(false, options, true);
3607}
3608
Harald Alvestrand0d018412021-11-04 13:52:31 +00003609// Create an offer with bundle enabled and verify the crypto parameters are
3610// the common set of the available cryptos.
3611TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3612 TestCryptoWithBundle(true);
3613}
3614
3615// Create an answer with bundle enabled and verify the crypto parameters are
3616// the common set of the available cryptos.
3617TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3618 TestCryptoWithBundle(false);
3619}
3620
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003621// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3622// DTLS is not enabled locally.
3623TEST_F(MediaSessionDescriptionFactoryTest,
3624 TestOfferDtlsSavpfWithoutDtlsFailed) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003625 f1_.set_secure(SEC_ENABLED);
3626 f2_.set_secure(SEC_ENABLED);
3627 tdf1_.set_secure(SEC_DISABLED);
3628 tdf2_.set_secure(SEC_DISABLED);
3629
Steve Anton6fe1fba2018-12-11 10:15:23 -08003630 std::unique_ptr<SessionDescription> offer =
3631 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003632 ASSERT_TRUE(offer.get() != NULL);
3633 ContentInfo* offer_content = offer->GetContentByName("audio");
3634 ASSERT_TRUE(offer_content != NULL);
3635 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003636 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003637 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3638
Steve Anton6fe1fba2018-12-11 10:15:23 -08003639 std::unique_ptr<SessionDescription> answer =
3640 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003641 ASSERT_TRUE(answer != NULL);
3642 ContentInfo* answer_content = answer->GetContentByName("audio");
3643 ASSERT_TRUE(answer_content != NULL);
3644
3645 ASSERT_TRUE(answer_content->rejected);
3646}
3647
3648// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3649// UDP/TLS/RTP/SAVPF.
3650TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003651 f1_.set_secure(SEC_ENABLED);
3652 f2_.set_secure(SEC_ENABLED);
3653 tdf1_.set_secure(SEC_ENABLED);
3654 tdf2_.set_secure(SEC_ENABLED);
3655
Steve Anton6fe1fba2018-12-11 10:15:23 -08003656 std::unique_ptr<SessionDescription> offer =
3657 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003658 ASSERT_TRUE(offer.get() != NULL);
3659 ContentInfo* offer_content = offer->GetContentByName("audio");
3660 ASSERT_TRUE(offer_content != NULL);
3661 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003662 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003663 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3664
Steve Anton6fe1fba2018-12-11 10:15:23 -08003665 std::unique_ptr<SessionDescription> answer =
3666 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003667 ASSERT_TRUE(answer != NULL);
3668
3669 const ContentInfo* answer_content = answer->GetContentByName("audio");
3670 ASSERT_TRUE(answer_content != NULL);
3671 ASSERT_FALSE(answer_content->rejected);
3672
3673 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003674 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003675 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003676}
3677
Harald Alvestrand0d018412021-11-04 13:52:31 +00003678// Test that we include both SDES and DTLS in the offer, but only include SDES
3679// in the answer if DTLS isn't negotiated.
3680TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3681 f1_.set_secure(SEC_ENABLED);
3682 f2_.set_secure(SEC_ENABLED);
3683 tdf1_.set_secure(SEC_ENABLED);
3684 tdf2_.set_secure(SEC_DISABLED);
3685 MediaSessionOptions options;
3686 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3687 std::unique_ptr<SessionDescription> offer, answer;
3688 const cricket::MediaContentDescription* audio_media_desc;
3689 const cricket::MediaContentDescription* video_media_desc;
3690 const cricket::TransportDescription* audio_trans_desc;
3691 const cricket::TransportDescription* video_trans_desc;
3692
3693 // Generate an offer with SDES and DTLS support.
3694 offer = f1_.CreateOffer(options, NULL);
3695 ASSERT_TRUE(offer.get() != NULL);
3696
3697 audio_media_desc = offer->GetContentDescriptionByName("audio");
3698 ASSERT_TRUE(audio_media_desc != NULL);
3699 video_media_desc = offer->GetContentDescriptionByName("video");
3700 ASSERT_TRUE(video_media_desc != NULL);
3701 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3702 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3703
3704 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3705 ASSERT_TRUE(audio_trans_desc != NULL);
3706 video_trans_desc = offer->GetTransportDescriptionByName("video");
3707 ASSERT_TRUE(video_trans_desc != NULL);
3708 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3709 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3710
3711 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
3712 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3713 ASSERT_TRUE(answer.get() != NULL);
3714
3715 audio_media_desc = answer->GetContentDescriptionByName("audio");
3716 ASSERT_TRUE(audio_media_desc != NULL);
3717 video_media_desc = answer->GetContentDescriptionByName("video");
3718 ASSERT_TRUE(video_media_desc != NULL);
3719 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3720 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3721
3722 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3723 ASSERT_TRUE(audio_trans_desc != NULL);
3724 video_trans_desc = answer->GetTransportDescriptionByName("video");
3725 ASSERT_TRUE(video_trans_desc != NULL);
3726 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3727 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3728
3729 // Enable DTLS; the answer should now only have DTLS support.
3730 tdf2_.set_secure(SEC_ENABLED);
3731 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3732 ASSERT_TRUE(answer.get() != NULL);
3733
3734 audio_media_desc = answer->GetContentDescriptionByName("audio");
3735 ASSERT_TRUE(audio_media_desc != NULL);
3736 video_media_desc = answer->GetContentDescriptionByName("video");
3737 ASSERT_TRUE(video_media_desc != NULL);
3738 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3739 EXPECT_TRUE(video_media_desc->cryptos().empty());
3740 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3741 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
3742
3743 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3744 ASSERT_TRUE(audio_trans_desc != NULL);
3745 video_trans_desc = answer->GetTransportDescriptionByName("video");
3746 ASSERT_TRUE(video_trans_desc != NULL);
3747 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3748 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3749
3750 // Try creating offer again. DTLS enabled now, crypto's should be empty
3751 // in new offer.
3752 offer = f1_.CreateOffer(options, offer.get());
3753 ASSERT_TRUE(offer.get() != NULL);
3754 audio_media_desc = offer->GetContentDescriptionByName("audio");
3755 ASSERT_TRUE(audio_media_desc != NULL);
3756 video_media_desc = offer->GetContentDescriptionByName("video");
3757 ASSERT_TRUE(video_media_desc != NULL);
3758 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3759 EXPECT_TRUE(video_media_desc->cryptos().empty());
3760
3761 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3762 ASSERT_TRUE(audio_trans_desc != NULL);
3763 video_trans_desc = offer->GetTransportDescriptionByName("video");
3764 ASSERT_TRUE(video_trans_desc != NULL);
3765 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3766 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3767}
3768
3769// Test that an answer can't be created if cryptos are required but the offer is
3770// unsecure.
3771TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
3772 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
3773 f1_.set_secure(SEC_DISABLED);
3774 tdf1_.set_secure(SEC_DISABLED);
3775 f2_.set_secure(SEC_REQUIRED);
3776 tdf1_.set_secure(SEC_ENABLED);
3777
3778 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
3779 ASSERT_TRUE(offer.get() != NULL);
3780 std::unique_ptr<SessionDescription> answer =
3781 f2_.CreateAnswer(offer.get(), options, NULL);
3782 EXPECT_TRUE(answer.get() == NULL);
3783}
3784
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003785// Test that we accept a DTLS offer without SDES and create an appropriate
3786// answer.
3787TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
Harald Alvestrand0d018412021-11-04 13:52:31 +00003788 f1_.set_secure(SEC_DISABLED);
3789 f2_.set_secure(SEC_ENABLED);
3790 tdf1_.set_secure(SEC_ENABLED);
3791 tdf2_.set_secure(SEC_ENABLED);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003792 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003793 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003794
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003795 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003796 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003797 ASSERT_TRUE(offer.get() != NULL);
3798
Harald Alvestrand0d018412021-11-04 13:52:31 +00003799 const AudioContentDescription* audio_offer =
3800 GetFirstAudioContentDescription(offer.get());
3801 ASSERT_TRUE(audio_offer->cryptos().empty());
3802 const VideoContentDescription* video_offer =
3803 GetFirstVideoContentDescription(offer.get());
3804 ASSERT_TRUE(video_offer->cryptos().empty());
3805
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003806 const cricket::TransportDescription* audio_offer_trans_desc =
3807 offer->GetTransportDescriptionByName("audio");
3808 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3809 const cricket::TransportDescription* video_offer_trans_desc =
3810 offer->GetTransportDescriptionByName("video");
3811 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003812
3813 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003814 std::unique_ptr<SessionDescription> answer =
3815 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003816 ASSERT_TRUE(answer.get() != NULL);
3817
3818 const cricket::TransportDescription* audio_answer_trans_desc =
3819 answer->GetTransportDescriptionByName("audio");
3820 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3821 const cricket::TransportDescription* video_answer_trans_desc =
3822 answer->GetTransportDescriptionByName("video");
3823 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003824}
3825
3826// Verifies if vad_enabled option is set to false, CN codecs are not present in
3827// offer or answer.
3828TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3829 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003830 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003831 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003832 ASSERT_TRUE(offer.get() != NULL);
3833 const ContentInfo* audio_content = offer->GetContentByName("audio");
3834 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3835
3836 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003837 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003838 ASSERT_TRUE(offer.get() != NULL);
3839 audio_content = offer->GetContentByName("audio");
3840 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003841 std::unique_ptr<SessionDescription> answer =
3842 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003843 ASSERT_TRUE(answer.get() != NULL);
3844 audio_content = answer->GetContentByName("audio");
3845 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3846}
deadbeef44f08192015-12-15 16:20:09 -08003847
zhihuang1c378ed2017-08-17 14:10:50 -07003848// Test that the generated MIDs match the existing offer.
3849TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003850 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003851 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3852 RtpTransceiverDirection::kRecvOnly, kActive,
3853 &opts);
3854 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3855 RtpTransceiverDirection::kRecvOnly, kActive,
3856 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003857 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3858 RtpTransceiverDirection::kSendRecv, kActive,
3859 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003860 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003861 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003862 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003863 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003864
deadbeef44f08192015-12-15 16:20:09 -08003865 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3866 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3867 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3868 ASSERT_TRUE(audio_content != nullptr);
3869 ASSERT_TRUE(video_content != nullptr);
3870 ASSERT_TRUE(data_content != nullptr);
3871 EXPECT_EQ("audio_modified", audio_content->name);
3872 EXPECT_EQ("video_modified", video_content->name);
3873 EXPECT_EQ("data_modified", data_content->name);
3874}
zhihuangcf5b37c2016-05-05 11:44:35 -07003875
zhihuang1c378ed2017-08-17 14:10:50 -07003876// The following tests verify that the unified plan SDP is supported.
3877// Test that we can create an offer with multiple media sections of same media
3878// type.
3879TEST_F(MediaSessionDescriptionFactoryTest,
3880 CreateOfferWithMultipleAVMediaSections) {
3881 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003882 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3883 RtpTransceiverDirection::kSendRecv, kActive,
3884 &opts);
3885 AttachSenderToMediaDescriptionOptions(
3886 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003887
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003888 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3889 RtpTransceiverDirection::kSendRecv, kActive,
3890 &opts);
3891 AttachSenderToMediaDescriptionOptions(
3892 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003893
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003894 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3895 RtpTransceiverDirection::kSendRecv, kActive,
3896 &opts);
3897 AttachSenderToMediaDescriptionOptions(
3898 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003899
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003900 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3901 RtpTransceiverDirection::kSendRecv, kActive,
3902 &opts);
3903 AttachSenderToMediaDescriptionOptions(
3904 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003905 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003906 ASSERT_TRUE(offer);
3907
3908 ASSERT_EQ(4u, offer->contents().size());
3909 EXPECT_FALSE(offer->contents()[0].rejected);
3910 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003911 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003912 ASSERT_EQ(1u, acd->streams().size());
3913 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003914 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003915
3916 EXPECT_FALSE(offer->contents()[1].rejected);
3917 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003918 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003919 ASSERT_EQ(1u, vcd->streams().size());
3920 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003921 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003922
3923 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003924 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003925 ASSERT_EQ(1u, acd->streams().size());
3926 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003927 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003928
3929 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003930 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003931 ASSERT_EQ(1u, vcd->streams().size());
3932 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003933 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003934}
3935
3936// Test that we can create an answer with multiple media sections of same media
3937// type.
3938TEST_F(MediaSessionDescriptionFactoryTest,
3939 CreateAnswerWithMultipleAVMediaSections) {
3940 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003941 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3942 RtpTransceiverDirection::kSendRecv, kActive,
3943 &opts);
3944 AttachSenderToMediaDescriptionOptions(
3945 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003946
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003947 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3948 RtpTransceiverDirection::kSendRecv, kActive,
3949 &opts);
3950 AttachSenderToMediaDescriptionOptions(
3951 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003952
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003953 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3954 RtpTransceiverDirection::kSendRecv, kActive,
3955 &opts);
3956 AttachSenderToMediaDescriptionOptions(
3957 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003958
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003959 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3960 RtpTransceiverDirection::kSendRecv, kActive,
3961 &opts);
3962 AttachSenderToMediaDescriptionOptions(
3963 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003964
Steve Anton6fe1fba2018-12-11 10:15:23 -08003965 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003966 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003967 std::unique_ptr<SessionDescription> answer =
3968 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003969
3970 ASSERT_EQ(4u, answer->contents().size());
3971 EXPECT_FALSE(answer->contents()[0].rejected);
3972 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003973 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003974 ASSERT_EQ(1u, acd->streams().size());
3975 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003976 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003977
3978 EXPECT_FALSE(answer->contents()[1].rejected);
3979 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003980 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003981 ASSERT_EQ(1u, vcd->streams().size());
3982 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003983 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003984
3985 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003986 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003987 ASSERT_EQ(1u, acd->streams().size());
3988 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003989 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003990
3991 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003992 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003993 ASSERT_EQ(1u, vcd->streams().size());
3994 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003995 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003996}
3997
3998// Test that the media section will be rejected in offer if the corresponding
3999// MediaDescriptionOptions is stopped by the offerer.
4000TEST_F(MediaSessionDescriptionFactoryTest,
4001 CreateOfferWithMediaSectionStoppedByOfferer) {
4002 // Create an offer with two audio sections and one of them is stopped.
4003 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004004 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4005 RtpTransceiverDirection::kSendRecv, kActive,
4006 &offer_opts);
4007 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4008 RtpTransceiverDirection::kInactive, kStopped,
4009 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004010 std::unique_ptr<SessionDescription> offer =
4011 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004012 ASSERT_TRUE(offer);
4013 ASSERT_EQ(2u, offer->contents().size());
4014 EXPECT_FALSE(offer->contents()[0].rejected);
4015 EXPECT_TRUE(offer->contents()[1].rejected);
4016}
4017
4018// Test that the media section will be rejected in answer if the corresponding
4019// MediaDescriptionOptions is stopped by the offerer.
4020TEST_F(MediaSessionDescriptionFactoryTest,
4021 CreateAnswerWithMediaSectionStoppedByOfferer) {
4022 // Create an offer with two audio sections and one of them is stopped.
4023 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004024 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4025 RtpTransceiverDirection::kSendRecv, kActive,
4026 &offer_opts);
4027 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4028 RtpTransceiverDirection::kInactive, kStopped,
4029 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004030 std::unique_ptr<SessionDescription> offer =
4031 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004032 ASSERT_TRUE(offer);
4033 ASSERT_EQ(2u, offer->contents().size());
4034 EXPECT_FALSE(offer->contents()[0].rejected);
4035 EXPECT_TRUE(offer->contents()[1].rejected);
4036
4037 // Create an answer based on the offer.
4038 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004039 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4040 RtpTransceiverDirection::kSendRecv, kActive,
4041 &answer_opts);
4042 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4043 RtpTransceiverDirection::kSendRecv, kActive,
4044 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004045 std::unique_ptr<SessionDescription> answer =
4046 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004047 ASSERT_EQ(2u, answer->contents().size());
4048 EXPECT_FALSE(answer->contents()[0].rejected);
4049 EXPECT_TRUE(answer->contents()[1].rejected);
4050}
4051
4052// Test that the media section will be rejected in answer if the corresponding
4053// MediaDescriptionOptions is stopped by the answerer.
4054TEST_F(MediaSessionDescriptionFactoryTest,
4055 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4056 // Create an offer with two audio sections.
4057 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004058 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4059 RtpTransceiverDirection::kSendRecv, kActive,
4060 &offer_opts);
4061 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4062 RtpTransceiverDirection::kSendRecv, kActive,
4063 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004064 std::unique_ptr<SessionDescription> offer =
4065 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004066 ASSERT_TRUE(offer);
4067 ASSERT_EQ(2u, offer->contents().size());
4068 ASSERT_FALSE(offer->contents()[0].rejected);
4069 ASSERT_FALSE(offer->contents()[1].rejected);
4070
4071 // The answerer rejects one of the audio sections.
4072 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004073 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4074 RtpTransceiverDirection::kSendRecv, kActive,
4075 &answer_opts);
4076 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4077 RtpTransceiverDirection::kInactive, kStopped,
4078 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004079 std::unique_ptr<SessionDescription> answer =
4080 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004081 ASSERT_EQ(2u, answer->contents().size());
4082 EXPECT_FALSE(answer->contents()[0].rejected);
4083 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004084
4085 // The TransportInfo of the rejected m= section is expected to be added in the
4086 // answer.
4087 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004088}
4089
4090// Test the generated media sections has the same order of the
4091// corresponding MediaDescriptionOptions.
4092TEST_F(MediaSessionDescriptionFactoryTest,
4093 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4094 MediaSessionOptions opts;
4095 // This tests put video section first because normally audio comes first by
4096 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004097 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4098 RtpTransceiverDirection::kSendRecv, kActive,
4099 &opts);
4100 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4101 RtpTransceiverDirection::kSendRecv, kActive,
4102 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004103 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004104
4105 ASSERT_TRUE(offer);
4106 ASSERT_EQ(2u, offer->contents().size());
4107 EXPECT_EQ("video", offer->contents()[0].name);
4108 EXPECT_EQ("audio", offer->contents()[1].name);
4109}
4110
4111// Test that different media sections using the same codec have same payload
4112// type.
4113TEST_F(MediaSessionDescriptionFactoryTest,
4114 PayloadTypesSharedByMediaSectionsOfSameType) {
4115 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004116 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4117 RtpTransceiverDirection::kSendRecv, kActive,
4118 &opts);
4119 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4120 RtpTransceiverDirection::kSendRecv, kActive,
4121 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004122 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004123 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004124 ASSERT_TRUE(offer);
4125 ASSERT_EQ(2u, offer->contents().size());
4126 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004127 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004128 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004129 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004130 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4131 ASSERT_EQ(2u, vcd1->codecs().size());
4132 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4133 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4134 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4135 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4136
4137 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004138 std::unique_ptr<SessionDescription> answer =
4139 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004140 ASSERT_TRUE(answer);
4141 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004142 vcd1 = answer->contents()[0].media_description()->as_video();
4143 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004144 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4145 ASSERT_EQ(1u, vcd1->codecs().size());
4146 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4147 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4148}
4149
4150// Test that the codec preference order per media section is respected in
4151// subsequent offer.
4152TEST_F(MediaSessionDescriptionFactoryTest,
4153 CreateOfferRespectsCodecPreferenceOrder) {
4154 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004155 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4156 RtpTransceiverDirection::kSendRecv, kActive,
4157 &opts);
4158 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4159 RtpTransceiverDirection::kSendRecv, kActive,
4160 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004161 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004162 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004163 ASSERT_TRUE(offer);
4164 ASSERT_EQ(2u, offer->contents().size());
4165 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004166 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004167 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004168 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004169 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4170 EXPECT_EQ(video_codecs, vcd1->codecs());
4171 EXPECT_EQ(video_codecs, vcd2->codecs());
4172
4173 // Change the codec preference of the first video section and create a
4174 // follow-up offer.
4175 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4176 vcd1->set_codecs(video_codecs_reverse);
4177 std::unique_ptr<SessionDescription> updated_offer(
4178 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004179 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4180 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004181 // The video codec preference order should be respected.
4182 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4183 EXPECT_EQ(video_codecs, vcd2->codecs());
4184}
4185
4186// Test that the codec preference order per media section is respected in
4187// the answer.
4188TEST_F(MediaSessionDescriptionFactoryTest,
4189 CreateAnswerRespectsCodecPreferenceOrder) {
4190 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004191 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4192 RtpTransceiverDirection::kSendRecv, kActive,
4193 &opts);
4194 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4195 RtpTransceiverDirection::kSendRecv, kActive,
4196 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004197 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004198 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004199 ASSERT_TRUE(offer);
4200 ASSERT_EQ(2u, offer->contents().size());
4201 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004202 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004203 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004204 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004205 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4206 EXPECT_EQ(video_codecs, vcd1->codecs());
4207 EXPECT_EQ(video_codecs, vcd2->codecs());
4208
4209 // Change the codec preference of the first video section and create an
4210 // answer.
4211 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4212 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004213 std::unique_ptr<SessionDescription> answer =
4214 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004215 vcd1 = answer->contents()[0].media_description()->as_video();
4216 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004217 // The video codec preference order should be respected.
4218 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4219 EXPECT_EQ(video_codecs, vcd2->codecs());
4220}
4221
Zhi Huang6f367472017-11-22 13:20:02 -08004222// Test that when creating an answer, the codecs use local parameters instead of
4223// the remote ones.
4224TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4225 const std::string audio_param_name = "audio_param";
4226 const std::string audio_value1 = "audio_v1";
4227 const std::string audio_value2 = "audio_v2";
4228 const std::string video_param_name = "video_param";
4229 const std::string video_value1 = "video_v1";
4230 const std::string video_value2 = "video_v2";
4231
4232 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4233 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4234 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4235 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4236
4237 // Set the parameters for codecs.
4238 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4239 video_codecs1[0].SetParam(video_param_name, video_value1);
4240 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4241 video_codecs2[0].SetParam(video_param_name, video_value2);
4242
4243 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004244 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004245 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004246 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004247
4248 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004249 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4250 RtpTransceiverDirection::kSendRecv, kActive,
4251 &opts);
4252 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4253 RtpTransceiverDirection::kSendRecv, kActive,
4254 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004255
Steve Anton6fe1fba2018-12-11 10:15:23 -08004256 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004257 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004258 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4259 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004260 std::string value;
4261 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4262 EXPECT_EQ(audio_value1, value);
4263 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4264 EXPECT_EQ(video_value1, value);
4265
Steve Anton6fe1fba2018-12-11 10:15:23 -08004266 std::unique_ptr<SessionDescription> answer =
4267 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004268 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004269 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4270 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004271 // Use the parameters from the local codecs.
4272 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4273 EXPECT_EQ(audio_value2, value);
4274 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4275 EXPECT_EQ(video_value2, value);
4276}
4277
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004278// Test that matching packetization-mode is part of the criteria for matching
4279// H264 codecs (in addition to profile-level-id). Previously, this was not the
4280// case, so the first H264 codec with the same profile-level-id would match and
4281// the payload type in the answer would be incorrect.
4282// This is a regression test for bugs.webrtc.org/8808
4283TEST_F(MediaSessionDescriptionFactoryTest,
4284 H264MatchCriteriaIncludesPacketizationMode) {
4285 // Create two H264 codecs with the same profile level ID and different
4286 // packetization modes.
4287 VideoCodec h264_pm0(96, "H264");
4288 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4289 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4290 VideoCodec h264_pm1(97, "H264");
4291 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4292 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4293
4294 // Offerer will send both codecs, answerer should choose the one with matching
4295 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004296 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4297 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004298
4299 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004300 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4301 RtpTransceiverDirection::kSendRecv, kActive,
4302 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004303
Steve Anton6fe1fba2018-12-11 10:15:23 -08004304 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004305 ASSERT_TRUE(offer);
4306
Steve Anton6fe1fba2018-12-11 10:15:23 -08004307 std::unique_ptr<SessionDescription> answer =
4308 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004309 ASSERT_TRUE(answer);
4310
4311 // Answer should have one negotiated codec with packetization-mode=1 using the
4312 // offered payload type.
4313 ASSERT_EQ(1u, answer->contents().size());
4314 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4315 ASSERT_EQ(1u, answer_vcd->codecs().size());
4316 auto answer_codec = answer_vcd->codecs()[0];
4317 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4318}
4319
zhihuangcf5b37c2016-05-05 11:44:35 -07004320class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4321 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004322 MediaProtocolTest()
4323 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004324 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4325 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004326 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4327 MAKE_VECTOR(kVideoCodecs1));
ossu075af922016-06-14 03:29:38 -07004328 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4329 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004330 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4331 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004332 f1_.set_secure(SEC_ENABLED);
4333 f2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004334 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004335 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004336 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004337 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
Harald Alvestrand0d018412021-11-04 13:52:31 +00004338 tdf1_.set_secure(SEC_ENABLED);
4339 tdf2_.set_secure(SEC_ENABLED);
zhihuangcf5b37c2016-05-05 11:44:35 -07004340 }
4341
4342 protected:
4343 MediaSessionDescriptionFactory f1_;
4344 MediaSessionDescriptionFactory f2_;
4345 TransportDescriptionFactory tdf1_;
4346 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004347 UniqueRandomIdGenerator ssrc_generator1;
4348 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004349};
4350
4351TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4352 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004353 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004354 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004355 ASSERT_TRUE(offer.get() != nullptr);
4356 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004357 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004358 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004359 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004360 std::unique_ptr<SessionDescription> answer =
4361 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004362 const ContentInfo* ac = answer->GetContentByName("audio");
4363 const ContentInfo* vc = answer->GetContentByName("video");
4364 ASSERT_TRUE(ac != nullptr);
4365 ASSERT_TRUE(vc != nullptr);
4366 EXPECT_FALSE(ac->rejected); // the offer is accepted
4367 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004368 const AudioContentDescription* acd = ac->media_description()->as_audio();
4369 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004370 EXPECT_EQ(GetParam(), acd->protocol());
4371 EXPECT_EQ(GetParam(), vcd->protocol());
4372}
4373
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004374INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4375 MediaProtocolTest,
4376 ::testing::ValuesIn(kMediaProtocols));
4377INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4378 MediaProtocolTest,
4379 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004380
4381TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4382 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004383 UniqueRandomIdGenerator ssrc_generator;
4384 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004385 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4386 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4387
4388 // The merged list of codecs should contain any send codecs that are also
4389 // nominally in the recieve codecs list. Payload types should be picked from
4390 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4391 // (set to 1). This equals what happens when the send codecs are used in an
4392 // offer and the receive codecs are used in the following answer.
4393 const std::vector<AudioCodec> sendrecv_codecs =
4394 MAKE_VECTOR(kAudioCodecsAnswer);
4395 const std::vector<AudioCodec> no_codecs;
4396
4397 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4398 << "Please don't change shared test data!";
4399 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4400 << "Please don't change shared test data!";
4401 // Alter iLBC send codec to have zero channels, to test that that is handled
4402 // properly.
4403 send_codecs[1].channels = 0;
4404
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004405 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004406 // are handled properly.
4407 recv_codecs[2].name = "ilbc";
4408
4409 // Test proper merge
4410 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004411 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4412 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4413 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004414
4415 // Test empty send codecs list
4416 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004417 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4418 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4419 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004420
4421 // Test empty recv codecs list
4422 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004423 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4424 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4425 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004426
4427 // Test all empty codec lists
4428 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004429 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4430 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4431 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004432}
4433
4434namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004435// Compare the two vectors of codecs ignoring the payload type.
4436template <class Codec>
4437bool CodecsMatch(const std::vector<Codec>& codecs1,
4438 const std::vector<Codec>& codecs2) {
4439 if (codecs1.size() != codecs2.size()) {
4440 return false;
4441 }
4442
4443 for (size_t i = 0; i < codecs1.size(); ++i) {
4444 if (!codecs1[i].Matches(codecs2[i])) {
4445 return false;
4446 }
4447 }
4448 return true;
4449}
4450
Steve Anton4e70a722017-11-28 14:57:10 -08004451void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004452 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004453 UniqueRandomIdGenerator ssrc_generator;
4454 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004455 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4456 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4457 const std::vector<AudioCodec> sendrecv_codecs =
4458 MAKE_VECTOR(kAudioCodecsAnswer);
4459 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004460
4461 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004462 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4463 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004464
Steve Anton4e70a722017-11-28 14:57:10 -08004465 if (direction == RtpTransceiverDirection::kSendRecv ||
4466 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004467 AttachSenderToMediaDescriptionOptions(
4468 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004469 }
ossu075af922016-06-14 03:29:38 -07004470
Steve Anton6fe1fba2018-12-11 10:15:23 -08004471 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004472 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004473 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004474
4475 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004476 // that the codecs put in are right. This happens when we neither want to
4477 // send nor receive audio. The checks are still in place if at some point
4478 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004479 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004480 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004481 // sendrecv and inactive should both present lists as if the channel was
4482 // to be used for sending and receiving. Inactive essentially means it
4483 // might eventually be used anything, but we don't know more at this
4484 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004485 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004486 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004487 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004488 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004489 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004490 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004491 }
4492 }
4493}
4494
4495static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004496 AudioCodec(0, "codec0", 16000, -1, 1),
4497 AudioCodec(1, "codec1", 8000, 13300, 1),
4498 AudioCodec(2, "codec2", 8000, 64000, 1),
4499 AudioCodec(3, "codec3", 8000, 64000, 1),
4500 AudioCodec(4, "codec4", 8000, 0, 2),
4501 AudioCodec(5, "codec5", 32000, 0, 1),
4502 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004503
zhihuang1c378ed2017-08-17 14:10:50 -07004504/* The codecs groups below are chosen as per the matrix below. The objective
4505 * is to have different sets of codecs in the inputs, to get unique sets of
4506 * codecs after negotiation, depending on offer and answer communication
4507 * directions. One-way directions in the offer should either result in the
4508 * opposite direction in the answer, or an inactive answer. Regardless, the
4509 * choice of codecs should be as if the answer contained the opposite
4510 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004511 *
4512 * | Offer | Answer | Result
4513 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4514 * 0 | x - - | - x - | x - - - -
4515 * 1 | x x x | - x - | x - - x -
4516 * 2 | - x - | x - - | - x - - -
4517 * 3 | x x x | x - - | - x x - -
4518 * 4 | - x - | x x x | - x - - -
4519 * 5 | x - - | x x x | x - - - -
4520 * 6 | x x x | x x x | x x x x x
4521 */
4522// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004523static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4524static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004525// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4526// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004527static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4528static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004529// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004530static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4531static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4532static const int kResultSendrecv_SendCodecs[] = {3, 6};
4533static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4534static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004535
4536template <typename T, int IDXS>
4537std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4538 std::vector<T> out;
4539 out.reserve(IDXS);
4540 for (int idx : indices)
4541 out.push_back(array[idx]);
4542
4543 return out;
4544}
4545
Steve Anton4e70a722017-11-28 14:57:10 -08004546void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4547 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004548 bool add_legacy_stream) {
4549 TransportDescriptionFactory offer_tdf;
4550 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004551 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4552 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4553 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004554 offer_factory.set_audio_codecs(
4555 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4556 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4557 answer_factory.set_audio_codecs(
4558 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4559 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4560
ossu075af922016-06-14 03:29:38 -07004561 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004562 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4563 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004564
Steve Anton4e70a722017-11-28 14:57:10 -08004565 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004566 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4567 kAudioTrack1, {kMediaStream1}, 1,
4568 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004569 }
4570
Steve Anton6fe1fba2018-12-11 10:15:23 -08004571 std::unique_ptr<SessionDescription> offer =
4572 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004573 ASSERT_TRUE(offer.get() != NULL);
4574
4575 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004576 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4577 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004578
Steve Anton4e70a722017-11-28 14:57:10 -08004579 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004580 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4581 kAudioTrack1, {kMediaStream1}, 1,
4582 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004583 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004584 std::unique_ptr<SessionDescription> answer =
4585 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004586 const ContentInfo* ac = answer->GetContentByName("audio");
4587
zhihuang1c378ed2017-08-17 14:10:50 -07004588 // If the factory didn't add any audio content to the answer, we cannot
4589 // check that the codecs put in are right. This happens when we neither want
4590 // to send nor receive audio. The checks are still in place if at some point
4591 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004592 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004593 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4594 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004595
ossu075af922016-06-14 03:29:38 -07004596 std::vector<AudioCodec> target_codecs;
4597 // For offers with sendrecv or inactive, we should never reply with more
4598 // codecs than offered, with these codec sets.
4599 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004600 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004601 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4602 kResultSendrecv_SendrecvCodecs);
4603 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004604 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004605 target_codecs =
4606 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004607 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004608 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004609 target_codecs =
4610 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004611 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004612 case RtpTransceiverDirection::kSendRecv:
4613 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004614 target_codecs =
4615 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004616 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004617 target_codecs =
4618 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004619 } else {
4620 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4621 kResultSendrecv_SendrecvCodecs);
4622 }
4623 break;
Harald Alvestrand6060df52020-08-11 09:54:02 +02004624 case RtpTransceiverDirection::kStopped:
4625 // This does not happen in any current test.
Artem Titovd3251962021-11-15 16:57:07 +01004626 RTC_DCHECK_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004627 }
4628
zhihuang1c378ed2017-08-17 14:10:50 -07004629 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004630 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004631 bool first = true;
4632 os << "{";
4633 for (const auto& c : codecs) {
4634 os << (first ? " " : ", ") << c.id;
4635 first = false;
4636 }
4637 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004638 return os.Release();
ossu075af922016-06-14 03:29:38 -07004639 };
4640
4641 EXPECT_TRUE(acd->codecs() == target_codecs)
4642 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004643 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4644 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004645 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004646 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4647 << "; got: "
4648 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004649 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004650 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004651 << "Only inactive offers are allowed to not generate any audio "
4652 "content";
ossu075af922016-06-14 03:29:38 -07004653 }
4654}
brandtr03d5fb12016-11-22 03:37:59 -08004655
4656} // namespace
ossu075af922016-06-14 03:29:38 -07004657
4658class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004659 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004660
4661TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004662 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004663}
4664
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004665INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4666 AudioCodecsOfferTest,
4667 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4668 RtpTransceiverDirection::kRecvOnly,
4669 RtpTransceiverDirection::kSendRecv,
4670 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004671
4672class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004673 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4674 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004675 bool>> {};
ossu075af922016-06-14 03:29:38 -07004676
4677TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004678 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4679 ::testing::get<1>(GetParam()),
4680 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004681}
4682
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004683INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004684 MediaSessionDescriptionFactoryTest,
4685 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004686 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4687 RtpTransceiverDirection::kRecvOnly,
4688 RtpTransceiverDirection::kSendRecv,
4689 RtpTransceiverDirection::kInactive),
4690 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4691 RtpTransceiverDirection::kRecvOnly,
4692 RtpTransceiverDirection::kSendRecv,
4693 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004694 ::testing::Bool()));