blob: 8b5e32054c9a3554a4b7651c12e108cac2dbf687 [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"
29#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"
Steve Antone38a5a12018-11-21 16:05:15 -080037#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038
Yves Gerey665174f2018-06-19 15:03:05 +020039#define ASSERT_CRYPTO(cd, s, cs) \
40 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080041 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042
43typedef std::vector<cricket::Candidate> Candidates;
44
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080045using cricket::AudioCodec;
46using cricket::AudioContentDescription;
47using cricket::ContentInfo;
48using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080049using cricket::GetFirstAudioContent;
50using cricket::GetFirstAudioContentDescription;
51using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020052using cricket::GetFirstRtpDataContentDescription;
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::RtpDataCodec;
68using cricket::RtpDataContentDescription;
69using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080070using cricket::SEC_DISABLED;
71using cricket::SEC_ENABLED;
72using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080074using cricket::SimulcastDescription;
75using cricket::SimulcastLayer;
76using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077using cricket::SsrcGroup;
78using cricket::StreamParams;
79using cricket::StreamParamsVec;
80using cricket::TransportDescription;
81using cricket::TransportDescriptionFactory;
82using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080084using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070085using rtc::CS_AEAD_AES_128_GCM;
86using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080087using rtc::CS_AES_CM_128_HMAC_SHA1_32;
88using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080089using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020090using ::testing::Contains;
91using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +010092using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020093using ::testing::ElementsAreArray;
94using ::testing::Eq;
95using ::testing::Field;
96using ::testing::IsEmpty;
97using ::testing::IsFalse;
98using ::testing::Ne;
99using ::testing::Not;
100using ::testing::Pointwise;
101using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700102using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800103using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104
105static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700106 AudioCodec(103, "ISAC", 16000, -1, 1),
107 AudioCodec(102, "iLBC", 8000, 13300, 1),
108 AudioCodec(0, "PCMU", 8000, 64000, 1),
109 AudioCodec(8, "PCMA", 8000, 64000, 1),
110 AudioCodec(117, "red", 8000, 0, 1),
111 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
113static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200114 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700115 AudioCodec(0, "PCMU", 8000, 64000, 1),
116 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117};
118
119static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700120 AudioCodec(102, "iLBC", 8000, 13300, 1),
121 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122};
123
perkj26752742016-10-24 01:21:16 -0700124static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
125 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126
zhihuang1c378ed2017-08-17 14:10:50 -0700127static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
128 VideoCodec(96, "H264-SVC")};
129
perkj26752742016-10-24 01:21:16 -0700130static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
131 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132
perkj26752742016-10-24 01:21:16 -0700133static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200135static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
136 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200138static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
139 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200141static const RtpDataCodec kDataCodecsAnswer[] = {
142 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143
isheriff6f8d6862016-05-26 11:24:55 -0700144static const RtpExtension kAudioRtpExtension1[] = {
145 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
146 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147};
148
jbauch5869f502017-06-29 12:31:36 -0700149static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
151 RtpExtension("http://google.com/testing/audio_something", 10),
152 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
153};
154
isheriff6f8d6862016-05-26 11:24:55 -0700155static const RtpExtension kAudioRtpExtension2[] = {
156 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
157 RtpExtension("http://google.com/testing/audio_something_else", 8),
158 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159};
160
isheriff6f8d6862016-05-26 11:24:55 -0700161static const RtpExtension kAudioRtpExtension3[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700164};
165
jbauch5869f502017-06-29 12:31:36 -0700166static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
167 RtpExtension("http://google.com/testing/audio_something", 2),
168 // Use RTP extension that supports encryption.
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
170};
171
172static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
173 RtpExtension("http://google.com/testing/audio_something", 2),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
175 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
176};
177
isheriff6f8d6862016-05-26 11:24:55 -0700178static const RtpExtension kAudioRtpExtensionAnswer[] = {
179 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000180};
181
jbauch5869f502017-06-29 12:31:36 -0700182static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
183 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
184};
185
isheriff6f8d6862016-05-26 11:24:55 -0700186static const RtpExtension kVideoRtpExtension1[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
188 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000189};
190
jbauch5869f502017-06-29 12:31:36 -0700191static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
192 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
193 RtpExtension("http://google.com/testing/video_something", 13),
194 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
195};
196
isheriff6f8d6862016-05-26 11:24:55 -0700197static const RtpExtension kVideoRtpExtension2[] = {
198 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
199 RtpExtension("http://google.com/testing/video_something_else", 14),
200 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000201};
202
isheriff6f8d6862016-05-26 11:24:55 -0700203static const RtpExtension kVideoRtpExtension3[] = {
204 RtpExtension("http://google.com/testing/video_something", 4),
205 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700206};
207
jbauch5869f502017-06-29 12:31:36 -0700208static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
209 RtpExtension("http://google.com/testing/video_something", 4),
210 // Use RTP extension that supports encryption.
211 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
212};
213
isheriff6f8d6862016-05-26 11:24:55 -0700214static const RtpExtension kVideoRtpExtensionAnswer[] = {
215 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216};
217
jbauch5869f502017-06-29 12:31:36 -0700218static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
219 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
220};
221
Johannes Kronce8e8672019-02-22 13:06:44 +0100222static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
223 RtpExtension("http://www.ietf.org/id/"
224 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
225 1),
226};
227
228static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
229 RtpExtension("http://www.ietf.org/id/"
230 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
231 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100232 RtpExtension(
233 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
234 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100235};
236
237static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100238 RtpExtension(
239 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
240 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100241};
242
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100243static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
244 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
245 "generic-frame-descriptor-00",
246 3),
247};
248
Peter Boström0c4e06b2015-10-07 12:23:21 +0200249static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
250static const uint32_t kSimSsrc[] = {10, 20, 30};
251static const uint32_t kFec1Ssrc[] = {10, 11};
252static const uint32_t kFec2Ssrc[] = {20, 21};
253static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254
255static const char kMediaStream1[] = "stream_1";
256static const char kMediaStream2[] = "stream_2";
257static const char kVideoTrack1[] = "video_1";
258static const char kVideoTrack2[] = "video_2";
259static const char kAudioTrack1[] = "audio_1";
260static const char kAudioTrack2[] = "audio_2";
261static const char kAudioTrack3[] = "audio_3";
262static const char kDataTrack1[] = "data_1";
263static const char kDataTrack2[] = "data_2";
264static const char kDataTrack3[] = "data_3";
265
zhihuangcf5b37c2016-05-05 11:44:35 -0700266static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
267 "RTP/SAVPF"};
268static const char* kMediaProtocolsDtls[] = {
269 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
270 "UDP/TLS/RTP/SAVP"};
271
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700272// SRTP cipher name negotiated by the tests. This must be updated if the
273// default changes.
274static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
275static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
276
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800277// These constants are used to make the code using "AddMediaDescriptionOptions"
278// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700279static constexpr bool kStopped = true;
280static constexpr bool kActive = false;
281
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000282static bool IsMediaContentOfType(const ContentInfo* content,
283 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800284 RTC_DCHECK(content);
285 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000286}
287
Steve Anton4e70a722017-11-28 14:57:10 -0800288static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800289 RTC_DCHECK(content);
290 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000291}
292
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000293static void AddRtxCodec(const VideoCodec& rtx_codec,
294 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800295 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000296 codecs->push_back(rtx_codec);
297}
298
299template <class T>
300static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
301 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100302 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000303 for (const auto& codec : codecs) {
304 codec_names.push_back(codec.name);
305 }
306 return codec_names;
307}
308
zhihuang1c378ed2017-08-17 14:10:50 -0700309// This is used for test only. MIDs are not the identification of the
310// MediaDescriptionOptions since some end points may not support MID and the SDP
311// may not contain 'mid'.
312std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
313 const std::string& mid,
314 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800315 return absl::c_find_if(
316 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700317 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
318}
319
320std::vector<MediaDescriptionOptions>::const_iterator
321FindFirstMediaDescriptionByMid(const std::string& mid,
322 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800323 return absl::c_find_if(
324 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700325 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700326}
327
328// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800329static void AddMediaDescriptionOptions(MediaType type,
330 const std::string& mid,
331 RtpTransceiverDirection direction,
332 bool stopped,
333 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800334 opts->media_description_options.push_back(
335 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700336}
337
Steve Anton4e70a722017-11-28 14:57:10 -0800338static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700339 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800340 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
341 opts);
342 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
343 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700344}
345
346static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800347 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700348 MediaSessionOptions* opts) {
349 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800350 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700351}
352
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800353static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700354 const std::string& mid,
355 MediaType type,
356 const std::string& track_id,
357 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800358 const std::vector<RidDescription>& rids,
359 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700360 int num_sim_layer,
361 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700362 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
363 switch (type) {
364 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700365 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700366 break;
367 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800368 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
369 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700370 break;
371 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700372 RTC_CHECK(stream_ids.size() == 1U);
373 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700374 break;
375 default:
376 RTC_NOTREACHED();
377 }
378}
379
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800380static void AttachSenderToMediaDescriptionOptions(
381 const std::string& mid,
382 MediaType type,
383 const std::string& track_id,
384 const std::vector<std::string>& stream_ids,
385 int num_sim_layer,
386 MediaSessionOptions* session_options) {
387 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
388 SimulcastLayerList(), num_sim_layer,
389 session_options);
390}
391
zhihuang1c378ed2017-08-17 14:10:50 -0700392static void DetachSenderFromMediaSection(const std::string& mid,
393 const std::string& track_id,
394 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700395 std::vector<cricket::SenderOptions>& sender_options_list =
396 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
397 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800398 absl::c_find_if(sender_options_list,
399 [track_id](const cricket::SenderOptions& sender_options) {
400 return sender_options.track_id == track_id;
401 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700402 RTC_DCHECK(sender_it != sender_options_list.end());
403 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700404}
405
406// Helper function used to create a default MediaSessionOptions for Plan B SDP.
407// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
408static MediaSessionOptions CreatePlanBMediaSessionOptions() {
409 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800410 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
411 RtpTransceiverDirection::kRecvOnly, kActive,
412 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700413 return session_options;
414}
415
Philipp Hancke1aec2bf2020-05-12 10:11:27 +0200416// prefers GCM SDES crypto suites by removing non-GCM defaults.
417void PreferGcmCryptoParameters(CryptoParamsVec* cryptos) {
418 cryptos->erase(
419 std::remove_if(cryptos->begin(), cryptos->end(),
420 [](const cricket::CryptoParams& crypto) {
421 return crypto.cipher_suite != CS_AEAD_AES_256_GCM &&
422 crypto.cipher_suite != CS_AEAD_AES_128_GCM;
423 }),
424 cryptos->end());
425}
426
zhihuang1c378ed2017-08-17 14:10:50 -0700427// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
428// was designed for Plan B SDP, where only one audio "m=" section and one video
429// "m=" section could be generated, and ordering couldn't be controlled. Many of
430// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200431class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800433 MediaSessionDescriptionFactoryTest()
434 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700435 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
436 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200437 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
438 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200439 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700440 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
441 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200442 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
443 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200444 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200445 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700446 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200447 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700448 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 }
450
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000451 // Create a video StreamParamsVec object with:
452 // - one video stream with 3 simulcast streams and FEC,
453 StreamParamsVec CreateComplexVideoStreamParamsVec() {
454 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
455 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
456 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
457 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
458
459 std::vector<SsrcGroup> ssrc_groups;
460 ssrc_groups.push_back(sim_group);
461 ssrc_groups.push_back(fec_group1);
462 ssrc_groups.push_back(fec_group2);
463 ssrc_groups.push_back(fec_group3);
464
465 StreamParams simulcast_params;
466 simulcast_params.id = kVideoTrack1;
467 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
468 simulcast_params.ssrc_groups = ssrc_groups;
469 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800470 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000471
472 StreamParamsVec video_streams;
473 video_streams.push_back(simulcast_params);
474
475 return video_streams;
476 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000477
478 bool CompareCryptoParams(const CryptoParamsVec& c1,
479 const CryptoParamsVec& c2) {
480 if (c1.size() != c2.size())
481 return false;
482 for (size_t i = 0; i < c1.size(); ++i)
483 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
484 c1[i].key_params != c2[i].key_params ||
485 c1[i].session_params != c2[i].session_params)
486 return false;
487 return true;
488 }
489
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700490 // Returns true if the transport info contains "renomination" as an
491 // ICE option.
492 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800493 return absl::c_linear_search(transport_info->description.transport_options,
494 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700495 }
496
zhihuang1c378ed2017-08-17 14:10:50 -0700497 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700498 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499 bool has_current_desc) {
500 const std::string current_audio_ufrag = "current_audio_ufrag";
501 const std::string current_audio_pwd = "current_audio_pwd";
502 const std::string current_video_ufrag = "current_video_ufrag";
503 const std::string current_video_pwd = "current_video_pwd";
504 const std::string current_data_ufrag = "current_data_ufrag";
505 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800506 std::unique_ptr<SessionDescription> current_desc;
507 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200509 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800510 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200511 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800512 TransportDescription(current_audio_ufrag, current_audio_pwd)));
513 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200514 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800515 TransportDescription(current_video_ufrag, current_video_pwd)));
516 current_desc->AddTransportInfo(TransportInfo(
517 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 }
519 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800520 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521 } else {
kwiberg31022942016-03-11 14:18:21 -0800522 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800523 offer = f1_.CreateOffer(options, NULL);
524 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525 }
526 ASSERT_TRUE(desc.get() != NULL);
527 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000528 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000529 EXPECT_TRUE(ti_audio != NULL);
530 if (has_current_desc) {
531 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
532 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
533 } else {
534 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
535 ti_audio->description.ice_ufrag.size());
536 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
537 ti_audio->description.ice_pwd.size());
538 }
zhihuang1c378ed2017-08-17 14:10:50 -0700539 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700540 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700541 EXPECT_EQ(
542 media_desc_options_it->transport_options.enable_ice_renomination,
543 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700544 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
545 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546
547 } else {
548 EXPECT_TRUE(ti_audio == NULL);
549 }
550 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000551 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700553 auto media_desc_options_it =
554 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 if (options.bundle_enabled) {
556 EXPECT_EQ(ti_audio->description.ice_ufrag,
557 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200558 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700559 EXPECT_EQ(ti_audio->description.opaque_parameters,
560 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 } else {
562 if (has_current_desc) {
563 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
564 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
565 } else {
566 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
567 ti_video->description.ice_ufrag.size());
568 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
569 ti_video->description.ice_pwd.size());
570 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700571 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
572 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 }
zhihuang1c378ed2017-08-17 14:10:50 -0700574 EXPECT_EQ(
575 media_desc_options_it->transport_options.enable_ice_renomination,
576 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 } else {
578 EXPECT_TRUE(ti_video == NULL);
579 }
580 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
581 if (options.has_data()) {
582 EXPECT_TRUE(ti_data != NULL);
583 if (options.bundle_enabled) {
584 EXPECT_EQ(ti_audio->description.ice_ufrag,
585 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200586 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 } else {
588 if (has_current_desc) {
589 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
590 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
591 } else {
592 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
593 ti_data->description.ice_ufrag.size());
594 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
595 ti_data->description.ice_pwd.size());
596 }
597 }
zhihuang1c378ed2017-08-17 14:10:50 -0700598 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700599 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700600 EXPECT_EQ(
601 media_desc_options_it->transport_options.enable_ice_renomination,
602 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700603
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700605 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 }
607 }
608
609 void TestCryptoWithBundle(bool offer) {
610 f1_.set_secure(SEC_ENABLED);
611 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800612 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
613 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
614 &options);
kwiberg31022942016-03-11 14:18:21 -0800615 std::unique_ptr<SessionDescription> ref_desc;
616 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 if (offer) {
618 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800619 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800621 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 } else {
623 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800624 ref_desc = f1_.CreateOffer(options, NULL);
625 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800627 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800629 desc->GetContentDescriptionByName("audio");
630 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800632 desc->GetContentDescriptionByName("video");
633 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
635 video_media_desc->cryptos()));
636 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800637 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 audio_media_desc->cryptos()[0].cipher_suite);
639
640 // Verify the selected crypto is one from the reference audio
641 // media content.
642 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800643 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 bool found = false;
645 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
646 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200647 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000648 found = true;
649 break;
650 }
651 }
652 EXPECT_TRUE(found);
653 }
654
655 // This test that the audio and video media direction is set to
656 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700657 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800659 RtpTransceiverDirection direction_in_offer,
660 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700661 MediaSessionOptions offer_opts;
662 AddAudioVideoSections(direction_in_offer, &offer_opts);
663
Steve Anton6fe1fba2018-12-11 10:15:23 -0800664 std::unique_ptr<SessionDescription> offer =
665 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700667 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700669 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671
zhihuang1c378ed2017-08-17 14:10:50 -0700672 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800673 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800674 std::unique_ptr<SessionDescription> answer =
675 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000676 const AudioContentDescription* acd_answer =
677 GetFirstAudioContentDescription(answer.get());
678 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
679 const VideoContentDescription* vcd_answer =
680 GetFirstVideoContentDescription(answer.get());
681 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
682 }
683
684 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800685 RTC_DCHECK(content);
686 RTC_CHECK(content->media_description());
687 const cricket::AudioContentDescription* audio_desc =
688 content->media_description()->as_audio();
689 RTC_CHECK(audio_desc);
690 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
691 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800693 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 }
695 return true;
696 }
697
jbauchcb560652016-08-04 05:20:32 -0700698 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
699 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800700 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700701 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700702
jbauchcb560652016-08-04 05:20:32 -0700703 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800704 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700705 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700706
jbauchcb560652016-08-04 05:20:32 -0700707 f1_.set_secure(SEC_ENABLED);
708 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800709 std::unique_ptr<SessionDescription> offer =
710 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700711 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +0200712 if (gcm_offer && gcm_answer) {
713 for (cricket::ContentInfo& content : offer->contents()) {
714 auto cryptos = content.media_description()->cryptos();
715 PreferGcmCryptoParameters(&cryptos);
716 content.media_description()->set_cryptos(cryptos);
717 }
718 }
Steve Anton6fe1fba2018-12-11 10:15:23 -0800719 std::unique_ptr<SessionDescription> answer =
720 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700721 const ContentInfo* ac = answer->GetContentByName("audio");
722 const ContentInfo* vc = answer->GetContentByName("video");
723 ASSERT_TRUE(ac != NULL);
724 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800725 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
726 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800727 const AudioContentDescription* acd = ac->media_description()->as_audio();
728 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700729 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800730 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700731 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700732 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700733 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
734 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700735 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700736 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700737 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700738 }
739 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800740 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200741 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
742 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700743 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700744 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700745 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700746 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700747 }
Steve Antone38a5a12018-11-21 16:05:15 -0800748 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700749 }
750
Johannes Kronce8e8672019-02-22 13:06:44 +0100751 void TestTransportSequenceNumberNegotiation(
752 const cricket::RtpHeaderExtensions& local,
753 const cricket::RtpHeaderExtensions& offered,
754 const cricket::RtpHeaderExtensions& expectedAnswer) {
755 MediaSessionOptions opts;
756 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +0000757 f1_.set_audio_rtp_header_extensions(offered);
758 f1_.set_video_rtp_header_extensions(offered);
759 f2_.set_audio_rtp_header_extensions(local);
760 f2_.set_video_rtp_header_extensions(local);
761
Johannes Kronce8e8672019-02-22 13:06:44 +0100762 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
763 ASSERT_TRUE(offer.get() != NULL);
764 std::unique_ptr<SessionDescription> answer =
765 f2_.CreateAnswer(offer.get(), opts, NULL);
766
767 EXPECT_EQ(
768 expectedAnswer,
769 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
770 EXPECT_EQ(
771 expectedAnswer,
772 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
773 }
774
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800776 UniqueRandomIdGenerator ssrc_generator1;
777 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 MediaSessionDescriptionFactory f1_;
779 MediaSessionDescriptionFactory f2_;
780 TransportDescriptionFactory tdf1_;
781 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782};
783
784// Create a typical audio offer, and ensure it matches what we expect.
785TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
786 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800787 std::unique_ptr<SessionDescription> offer =
788 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 ASSERT_TRUE(offer.get() != NULL);
790 const ContentInfo* ac = offer->GetContentByName("audio");
791 const ContentInfo* vc = offer->GetContentByName("video");
792 ASSERT_TRUE(ac != NULL);
793 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800794 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800795 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700797 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700798 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
800 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700801 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800802 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000803}
804
805// Create a typical video offer, and ensure it matches what we expect.
806TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
807 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800808 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800810 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 ASSERT_TRUE(offer.get() != NULL);
812 const ContentInfo* ac = offer->GetContentByName("audio");
813 const ContentInfo* vc = offer->GetContentByName("video");
814 ASSERT_TRUE(ac != NULL);
815 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800816 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
817 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800818 const AudioContentDescription* acd = ac->media_description()->as_audio();
819 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700821 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700822 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
824 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700825 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800826 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200828 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700829 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
831 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700832 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800833 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834}
835
836// Test creating an offer with bundle where the Codecs have the same dynamic
837// RTP playlod type. The test verifies that the offer don't contain the
838// duplicate RTP payload types.
839TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200840 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700841 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200842 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
844 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
845
846 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800847 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
848 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800850 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851 const VideoContentDescription* vcd =
852 GetFirstVideoContentDescription(offer.get());
853 const AudioContentDescription* acd =
854 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200855 const RtpDataContentDescription* dcd =
856 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857 ASSERT_TRUE(NULL != vcd);
858 ASSERT_TRUE(NULL != acd);
859 ASSERT_TRUE(NULL != dcd);
860 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
861 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
862 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
863 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
864 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
865 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
866}
867
zhihuang1c378ed2017-08-17 14:10:50 -0700868// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869// after an audio only session has been negotiated.
870TEST_F(MediaSessionDescriptionFactoryTest,
871 TestCreateUpdatedVideoOfferWithBundle) {
872 f1_.set_secure(SEC_ENABLED);
873 f2_.set_secure(SEC_ENABLED);
874 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800875 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
876 RtpTransceiverDirection::kRecvOnly, kActive,
877 &opts);
878 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
879 RtpTransceiverDirection::kInactive, kStopped,
880 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 opts.data_channel_type = cricket::DCT_NONE;
882 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800883 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
884 std::unique_ptr<SessionDescription> answer =
885 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000886
887 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800888 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
889 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
890 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800892 std::unique_ptr<SessionDescription> updated_offer(
893 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894
895 const AudioContentDescription* acd =
896 GetFirstAudioContentDescription(updated_offer.get());
897 const VideoContentDescription* vcd =
898 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200899 const RtpDataContentDescription* dcd =
900 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 EXPECT_TRUE(NULL != vcd);
902 EXPECT_TRUE(NULL != acd);
903 EXPECT_TRUE(NULL != dcd);
904
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700905 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800906 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700907 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800908 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700909 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800910 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911}
deadbeef44f08192015-12-15 16:20:09 -0800912
wu@webrtc.org78187522013-10-07 23:32:02 +0000913// Create a RTP data offer, and ensure it matches what we expect.
914TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800916 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
917 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800919 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000920 ASSERT_TRUE(offer.get() != NULL);
921 const ContentInfo* ac = offer->GetContentByName("audio");
922 const ContentInfo* dc = offer->GetContentByName("data");
923 ASSERT_TRUE(ac != NULL);
924 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800925 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
926 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800927 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200928 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000929 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700930 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700931 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000932 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
933 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700934 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800935 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000936 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200937 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700938 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000939 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200940 dcd->bandwidth()); // default bandwidth (auto)
941 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700942 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800943 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944}
945
wu@webrtc.org78187522013-10-07 23:32:02 +0000946// Create an SCTP data offer with bundle without error.
947TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
948 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000949 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800950 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000951 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800952 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000953 EXPECT_TRUE(offer.get() != NULL);
954 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000955 auto dcd = GetFirstSctpDataContentDescription(offer.get());
956 ASSERT_TRUE(dcd);
957 // Since this transport is insecure, the protocol should be "SCTP".
958 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
959}
960
961// Create an SCTP data offer with bundle without error.
962TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
963 MediaSessionOptions opts;
964 opts.bundle_enabled = true;
965 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
966 f1_.set_secure(SEC_ENABLED);
967 tdf1_.set_secure(SEC_ENABLED);
968 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
969 EXPECT_TRUE(offer.get() != NULL);
970 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
971 auto dcd = GetFirstSctpDataContentDescription(offer.get());
972 ASSERT_TRUE(dcd);
973 // The protocol should now be "UDP/DTLS/SCTP"
974 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000975}
976
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000977// Test creating an sctp data channel from an already generated offer.
978TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
979 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000980 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800981 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000982 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800983 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000984 ASSERT_TRUE(offer1.get() != NULL);
985 const ContentInfo* data = offer1->GetContentByName("data");
986 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800987 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000988
989 // Now set data_channel_type to 'none' (default) and make sure that the
990 // datachannel type that gets generated from the previous offer, is of the
991 // same type.
992 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800993 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000994 f1_.CreateOffer(opts, offer1.get()));
995 data = offer2->GetContentByName("data");
996 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800997 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000998}
999
Steve Anton2bed3972019-01-04 17:04:30 -08001000// Test that if BUNDLE is enabled and all media sections are rejected then the
1001// BUNDLE group is not present in the re-offer.
1002TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
1003 MediaSessionOptions opts;
1004 opts.bundle_enabled = true;
1005 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1006 RtpTransceiverDirection::kSendRecv, kActive,
1007 &opts);
1008 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1009
1010 opts.media_description_options[0].stopped = true;
1011 std::unique_ptr<SessionDescription> reoffer =
1012 f1_.CreateOffer(opts, offer.get());
1013
1014 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1015}
1016
1017// Test that if BUNDLE is enabled and the remote re-offer does not include a
1018// BUNDLE group since all media sections are rejected, then the re-answer also
1019// does not include a BUNDLE group.
1020TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
1021 MediaSessionOptions opts;
1022 opts.bundle_enabled = true;
1023 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1024 RtpTransceiverDirection::kSendRecv, kActive,
1025 &opts);
1026 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1027 std::unique_ptr<SessionDescription> answer =
1028 f2_.CreateAnswer(offer.get(), opts, nullptr);
1029
1030 opts.media_description_options[0].stopped = true;
1031 std::unique_ptr<SessionDescription> reoffer =
1032 f1_.CreateOffer(opts, offer.get());
1033 std::unique_ptr<SessionDescription> reanswer =
1034 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1035
1036 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1037}
1038
1039// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1040// was rejected then the new offerer-tagged media section is the non-rejected
1041// media section.
1042TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1043 MediaSessionOptions opts;
1044 opts.bundle_enabled = true;
1045 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1046 RtpTransceiverDirection::kSendRecv, kActive,
1047 &opts);
1048 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1049
1050 // Reject the audio m= section and add a video m= section.
1051 opts.media_description_options[0].stopped = true;
1052 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1053 RtpTransceiverDirection::kSendRecv, kActive,
1054 &opts);
1055 std::unique_ptr<SessionDescription> reoffer =
1056 f1_.CreateOffer(opts, offer.get());
1057
1058 const cricket::ContentGroup* bundle_group =
1059 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1060 ASSERT_TRUE(bundle_group);
1061 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1062 EXPECT_TRUE(bundle_group->HasContentName("video"));
1063}
1064
1065// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1066// was rejected and a new media section is added, then the re-answer BUNDLE
1067// group will contain only the non-rejected media section.
1068TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1069 MediaSessionOptions opts;
1070 opts.bundle_enabled = true;
1071 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1072 RtpTransceiverDirection::kSendRecv, kActive,
1073 &opts);
1074 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1075 std::unique_ptr<SessionDescription> answer =
1076 f2_.CreateAnswer(offer.get(), opts, nullptr);
1077
1078 // Reject the audio m= section and add a video m= section.
1079 opts.media_description_options[0].stopped = true;
1080 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1081 RtpTransceiverDirection::kSendRecv, kActive,
1082 &opts);
1083 std::unique_ptr<SessionDescription> reoffer =
1084 f1_.CreateOffer(opts, offer.get());
1085 std::unique_ptr<SessionDescription> reanswer =
1086 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1087
1088 const cricket::ContentGroup* bundle_group =
1089 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1090 ASSERT_TRUE(bundle_group);
1091 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1092 EXPECT_TRUE(bundle_group->HasContentName("video"));
1093}
1094
1095// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1096// and there is still a non-rejected media section that was in the initial
1097// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1098// media section.
1099TEST_F(MediaSessionDescriptionFactoryTest,
1100 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1101 MediaSessionOptions opts;
1102 opts.bundle_enabled = true;
1103 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1104 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1105 std::unique_ptr<SessionDescription> answer =
1106 f2_.CreateAnswer(offer.get(), opts, nullptr);
1107
1108 // Reject the audio m= section.
1109 opts.media_description_options[0].stopped = true;
1110 std::unique_ptr<SessionDescription> reoffer =
1111 f1_.CreateOffer(opts, offer.get());
1112
1113 const TransportDescription* offer_tagged =
1114 offer->GetTransportDescriptionByName("audio");
1115 ASSERT_TRUE(offer_tagged);
1116 const TransportDescription* reoffer_tagged =
1117 reoffer->GetTransportDescriptionByName("video");
1118 ASSERT_TRUE(reoffer_tagged);
1119 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1120 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1121}
1122
1123// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1124// and there is still a non-rejected media section that was in the initial
1125// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1126// media section.
1127TEST_F(MediaSessionDescriptionFactoryTest,
1128 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1129 MediaSessionOptions opts;
1130 opts.bundle_enabled = true;
1131 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1132 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1133 std::unique_ptr<SessionDescription> answer =
1134 f2_.CreateAnswer(offer.get(), opts, nullptr);
1135
1136 // Reject the audio m= section.
1137 opts.media_description_options[0].stopped = true;
1138 std::unique_ptr<SessionDescription> reoffer =
1139 f1_.CreateOffer(opts, offer.get());
1140 std::unique_ptr<SessionDescription> reanswer =
1141 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1142
1143 const TransportDescription* answer_tagged =
1144 answer->GetTransportDescriptionByName("audio");
1145 ASSERT_TRUE(answer_tagged);
1146 const TransportDescription* reanswer_tagged =
1147 reanswer->GetTransportDescriptionByName("video");
1148 ASSERT_TRUE(reanswer_tagged);
1149 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1150 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1151}
1152
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001153// Create an audio, video offer without legacy StreamParams.
1154TEST_F(MediaSessionDescriptionFactoryTest,
1155 TestCreateOfferWithoutLegacyStreams) {
1156 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001157 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001158 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001159 ASSERT_TRUE(offer.get() != NULL);
1160 const ContentInfo* ac = offer->GetContentByName("audio");
1161 const ContentInfo* vc = offer->GetContentByName("video");
1162 ASSERT_TRUE(ac != NULL);
1163 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001164 const AudioContentDescription* acd = ac->media_description()->as_audio();
1165 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001166
Yves Gerey665174f2018-06-19 15:03:05 +02001167 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1168 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001169}
1170
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001171// Creates an audio+video sendonly offer.
1172TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001173 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001174 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001175 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1176 {kMediaStream1}, 1, &opts);
1177 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1178 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001179
Steve Anton6fe1fba2018-12-11 10:15:23 -08001180 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001181 ASSERT_TRUE(offer.get() != NULL);
1182 EXPECT_EQ(2u, offer->contents().size());
1183 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1184 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1185
Steve Anton4e70a722017-11-28 14:57:10 -08001186 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1187 GetMediaDirection(&offer->contents()[0]));
1188 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1189 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001190}
1191
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001192// Verifies that the order of the media contents in the current
1193// SessionDescription is preserved in the new SessionDescription.
1194TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1195 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001196 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001197
kwiberg31022942016-03-11 14:18:21 -08001198 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001199 ASSERT_TRUE(offer1.get() != NULL);
1200 EXPECT_EQ(1u, offer1->contents().size());
1201 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1202
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001203 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1204 RtpTransceiverDirection::kRecvOnly, kActive,
1205 &opts);
kwiberg31022942016-03-11 14:18:21 -08001206 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001207 f1_.CreateOffer(opts, offer1.get()));
1208 ASSERT_TRUE(offer2.get() != NULL);
1209 EXPECT_EQ(2u, offer2->contents().size());
1210 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1211 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1212
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001213 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1214 RtpTransceiverDirection::kRecvOnly, kActive,
1215 &opts);
kwiberg31022942016-03-11 14:18:21 -08001216 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001217 f1_.CreateOffer(opts, offer2.get()));
1218 ASSERT_TRUE(offer3.get() != NULL);
1219 EXPECT_EQ(3u, offer3->contents().size());
1220 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1221 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1222 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001223}
1224
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225// Create a typical audio answer, and ensure it matches what we expect.
1226TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1227 f1_.set_secure(SEC_ENABLED);
1228 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001229 std::unique_ptr<SessionDescription> offer =
1230 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001232 std::unique_ptr<SessionDescription> answer =
1233 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001234 const ContentInfo* ac = answer->GetContentByName("audio");
1235 const ContentInfo* vc = answer->GetContentByName("video");
1236 ASSERT_TRUE(ac != NULL);
1237 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001238 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001239 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001241 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001242 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1244 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001245 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001246 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247}
1248
jbauchcb560652016-08-04 05:20:32 -07001249// Create a typical audio answer with GCM ciphers enabled, and ensure it
1250// matches what we expect.
1251TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1252 f1_.set_secure(SEC_ENABLED);
1253 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001254 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001255 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001256 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001257 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +02001258 for (cricket::ContentInfo& content : offer->contents()) {
1259 auto cryptos = content.media_description()->cryptos();
1260 PreferGcmCryptoParameters(&cryptos);
1261 content.media_description()->set_cryptos(cryptos);
1262 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08001263 std::unique_ptr<SessionDescription> answer =
1264 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001265 const ContentInfo* ac = answer->GetContentByName("audio");
1266 const ContentInfo* vc = answer->GetContentByName("video");
1267 ASSERT_TRUE(ac != NULL);
1268 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001269 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001270 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001271 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001272 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001273 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001274 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1275 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001276 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001277 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001278}
1279
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280// Create a typical video answer, and ensure it matches what we expect.
1281TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1282 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001283 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001284 f1_.set_secure(SEC_ENABLED);
1285 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001286 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001288 std::unique_ptr<SessionDescription> answer =
1289 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001290 const ContentInfo* ac = answer->GetContentByName("audio");
1291 const ContentInfo* vc = answer->GetContentByName("video");
1292 ASSERT_TRUE(ac != NULL);
1293 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001294 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1295 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001296 const AudioContentDescription* acd = ac->media_description()->as_audio();
1297 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001299 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001301 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001302 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001303 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001304 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001305 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001306 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1307 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001308 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001309 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310}
1311
jbauchcb560652016-08-04 05:20:32 -07001312// Create a typical video answer with GCM ciphers enabled, and ensure it
1313// matches what we expect.
1314TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1315 TestVideoGcmCipher(true, true);
1316}
1317
1318// Create a typical video answer with GCM ciphers enabled for the offer only,
1319// and ensure it matches what we expect.
1320TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1321 TestVideoGcmCipher(true, false);
1322}
1323
1324// Create a typical video answer with GCM ciphers enabled for the answer only,
1325// and ensure it matches what we expect.
1326TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1327 TestVideoGcmCipher(false, true);
1328}
1329
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001330TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001331 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001332 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333 f1_.set_secure(SEC_ENABLED);
1334 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001335 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001336 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001337 std::unique_ptr<SessionDescription> answer =
1338 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001340 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001341 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001342 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001343 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1344 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001345 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001346 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001347 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001348 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001349 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001350 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001352 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001353 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001354 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001355 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001356 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001357 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001358 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001359}
1360
jbauchcb560652016-08-04 05:20:32 -07001361TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001362 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001363 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001364 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001365 f1_.set_secure(SEC_ENABLED);
1366 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001367 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001368 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +02001369 for (cricket::ContentInfo& content : offer->contents()) {
1370 auto cryptos = content.media_description()->cryptos();
1371 PreferGcmCryptoParameters(&cryptos);
1372 content.media_description()->set_cryptos(cryptos);
1373 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08001374 std::unique_ptr<SessionDescription> answer =
1375 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001376 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001377 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001378 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001379 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001380 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1381 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001382 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001383 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001384 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001385 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001386 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001387 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001388 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001389 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001390 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001391 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001392 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001393 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001394 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001395 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001396}
1397
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001398// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1399// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001400TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1401 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001402 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001403 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001404 ASSERT_TRUE(offer.get() != NULL);
1405 ContentInfo* dc_offer = offer->GetContentByName("data");
1406 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001407 SctpDataContentDescription* dcd_offer =
1408 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001409 EXPECT_TRUE(dcd_offer->use_sctpmap());
1410
Steve Anton6fe1fba2018-12-11 10:15:23 -08001411 std::unique_ptr<SessionDescription> answer =
1412 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001413 const ContentInfo* dc_answer = answer->GetContentByName("data");
1414 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001415 const SctpDataContentDescription* dcd_answer =
1416 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001417 EXPECT_TRUE(dcd_answer->use_sctpmap());
1418}
1419
1420// The answer's use_sctpmap flag should match the offer's.
1421TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1422 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001423 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001424 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001425 ASSERT_TRUE(offer.get() != NULL);
1426 ContentInfo* dc_offer = offer->GetContentByName("data");
1427 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001428 SctpDataContentDescription* dcd_offer =
1429 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001430 dcd_offer->set_use_sctpmap(false);
1431
Steve Anton6fe1fba2018-12-11 10:15:23 -08001432 std::unique_ptr<SessionDescription> answer =
1433 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001434 const ContentInfo* dc_answer = answer->GetContentByName("data");
1435 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001436 const SctpDataContentDescription* dcd_answer =
1437 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001438 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001439}
1440
deadbeef8b7e9ad2017-05-25 09:38:55 -07001441// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1442// and "TCP/DTLS/SCTP" offers.
1443TEST_F(MediaSessionDescriptionFactoryTest,
1444 TestCreateDataAnswerToDifferentOfferedProtos) {
1445 // Need to enable DTLS offer/answer generation (disabled by default in this
1446 // test).
1447 f1_.set_secure(SEC_ENABLED);
1448 f2_.set_secure(SEC_ENABLED);
1449 tdf1_.set_secure(SEC_ENABLED);
1450 tdf2_.set_secure(SEC_ENABLED);
1451
1452 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001453 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001454 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001455 ASSERT_TRUE(offer.get() != nullptr);
1456 ContentInfo* dc_offer = offer->GetContentByName("data");
1457 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001458 SctpDataContentDescription* dcd_offer =
1459 dc_offer->media_description()->as_sctp();
1460 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001461
1462 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1463 "TCP/DTLS/SCTP"};
1464 for (const std::string& proto : protos) {
1465 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001466 std::unique_ptr<SessionDescription> answer =
1467 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001468 const ContentInfo* dc_answer = answer->GetContentByName("data");
1469 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001470 const SctpDataContentDescription* dcd_answer =
1471 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001472 EXPECT_FALSE(dc_answer->rejected);
1473 EXPECT_EQ(proto, dcd_answer->protocol());
1474 }
1475}
1476
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001477TEST_F(MediaSessionDescriptionFactoryTest,
1478 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1479 // Need to enable DTLS offer/answer generation (disabled by default in this
1480 // test).
1481 f1_.set_secure(SEC_ENABLED);
1482 f2_.set_secure(SEC_ENABLED);
1483 tdf1_.set_secure(SEC_ENABLED);
1484 tdf2_.set_secure(SEC_ENABLED);
1485
1486 MediaSessionOptions opts;
1487 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1488 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1489 ASSERT_TRUE(offer.get() != nullptr);
1490 ContentInfo* dc_offer = offer->GetContentByName("data");
1491 ASSERT_TRUE(dc_offer != nullptr);
1492 SctpDataContentDescription* dcd_offer =
1493 dc_offer->media_description()->as_sctp();
1494 ASSERT_TRUE(dcd_offer);
1495 dcd_offer->set_max_message_size(1234);
1496 std::unique_ptr<SessionDescription> answer =
1497 f2_.CreateAnswer(offer.get(), opts, nullptr);
1498 const ContentInfo* dc_answer = answer->GetContentByName("data");
1499 ASSERT_TRUE(dc_answer != nullptr);
1500 const SctpDataContentDescription* dcd_answer =
1501 dc_answer->media_description()->as_sctp();
1502 EXPECT_FALSE(dc_answer->rejected);
1503 EXPECT_EQ(1234, dcd_answer->max_message_size());
1504}
1505
1506TEST_F(MediaSessionDescriptionFactoryTest,
1507 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1508 // Need to enable DTLS offer/answer generation (disabled by default in this
1509 // test).
1510 f1_.set_secure(SEC_ENABLED);
1511 f2_.set_secure(SEC_ENABLED);
1512 tdf1_.set_secure(SEC_ENABLED);
1513 tdf2_.set_secure(SEC_ENABLED);
1514
1515 MediaSessionOptions opts;
1516 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1517 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1518 ASSERT_TRUE(offer.get() != nullptr);
1519 ContentInfo* dc_offer = offer->GetContentByName("data");
1520 ASSERT_TRUE(dc_offer != nullptr);
1521 SctpDataContentDescription* dcd_offer =
1522 dc_offer->media_description()->as_sctp();
1523 ASSERT_TRUE(dcd_offer);
1524 dcd_offer->set_max_message_size(0);
1525 std::unique_ptr<SessionDescription> answer =
1526 f2_.CreateAnswer(offer.get(), opts, nullptr);
1527 const ContentInfo* dc_answer = answer->GetContentByName("data");
1528 ASSERT_TRUE(dc_answer != nullptr);
1529 const SctpDataContentDescription* dcd_answer =
1530 dc_answer->media_description()->as_sctp();
1531 EXPECT_FALSE(dc_answer->rejected);
1532 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1533}
1534
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001535// Verifies that the order of the media contents in the offer is preserved in
1536// the answer.
1537TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1538 MediaSessionOptions opts;
1539
1540 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001541 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001542 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001543 ASSERT_TRUE(offer1.get() != NULL);
1544
1545 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001546 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1547 RtpTransceiverDirection::kRecvOnly, kActive,
1548 &opts);
kwiberg31022942016-03-11 14:18:21 -08001549 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001550 f1_.CreateOffer(opts, offer1.get()));
1551 ASSERT_TRUE(offer2.get() != NULL);
1552
1553 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001554 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1555 RtpTransceiverDirection::kRecvOnly, kActive,
1556 &opts);
kwiberg31022942016-03-11 14:18:21 -08001557 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001558 f1_.CreateOffer(opts, offer2.get()));
1559 ASSERT_TRUE(offer3.get() != NULL);
1560
Steve Anton6fe1fba2018-12-11 10:15:23 -08001561 std::unique_ptr<SessionDescription> answer =
1562 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001563 ASSERT_TRUE(answer.get() != NULL);
1564 EXPECT_EQ(3u, answer->contents().size());
1565 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1566 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1567 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1568}
1569
ossu075af922016-06-14 03:29:38 -07001570// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1571// answerer settings.
1572
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001573// This test that the media direction is set to send/receive in an answer if
1574// the offer is send receive.
1575TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001576 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1577 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578}
1579
1580// This test that the media direction is set to receive only in an answer if
1581// the offer is send only.
1582TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001583 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1584 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001585}
1586
1587// This test that the media direction is set to send only in an answer if
1588// the offer is recv only.
1589TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001590 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1591 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001592}
1593
1594// This test that the media direction is set to inactive in an answer if
1595// the offer is inactive.
1596TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001597 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1598 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001599}
1600
1601// Test that a data content with an unknown protocol is rejected in an answer.
1602TEST_F(MediaSessionDescriptionFactoryTest,
1603 CreateDataAnswerToOfferWithUnknownProtocol) {
1604 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001605 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001606 f1_.set_secure(SEC_ENABLED);
1607 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001608 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001609 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001610 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001611 RtpDataContentDescription* dcd_offer =
1612 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001613 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001614 // Offer must be acceptable as an RTP protocol in order to be set.
1615 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001616 dcd_offer->set_protocol(protocol);
1617
Steve Anton6fe1fba2018-12-11 10:15:23 -08001618 std::unique_ptr<SessionDescription> answer =
1619 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620
1621 const ContentInfo* dc_answer = answer->GetContentByName("data");
1622 ASSERT_TRUE(dc_answer != NULL);
1623 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001624 const RtpDataContentDescription* dcd_answer =
1625 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626 ASSERT_TRUE(dcd_answer != NULL);
1627 EXPECT_EQ(protocol, dcd_answer->protocol());
1628}
1629
1630// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1631TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001632 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 f1_.set_secure(SEC_DISABLED);
1634 f2_.set_secure(SEC_DISABLED);
1635 tdf1_.set_secure(SEC_DISABLED);
1636 tdf2_.set_secure(SEC_DISABLED);
1637
Steve Anton6fe1fba2018-12-11 10:15:23 -08001638 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639 const AudioContentDescription* offer_acd =
1640 GetFirstAudioContentDescription(offer.get());
1641 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001642 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001643
Steve Anton6fe1fba2018-12-11 10:15:23 -08001644 std::unique_ptr<SessionDescription> answer =
1645 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001646
1647 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1648 ASSERT_TRUE(ac_answer != NULL);
1649 EXPECT_FALSE(ac_answer->rejected);
1650
1651 const AudioContentDescription* answer_acd =
1652 GetFirstAudioContentDescription(answer.get());
1653 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001654 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001655}
1656
1657// Create a video offer and answer and ensure the RTP header extensions
1658// matches what we expect.
1659TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1660 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001661 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +00001662 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1663 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1664 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1665 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001666
Steve Anton6fe1fba2018-12-11 10:15:23 -08001667 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001669 std::unique_ptr<SessionDescription> answer =
1670 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001671
Yves Gerey665174f2018-06-19 15:03:05 +02001672 EXPECT_EQ(
1673 MAKE_VECTOR(kAudioRtpExtension1),
1674 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1675 EXPECT_EQ(
1676 MAKE_VECTOR(kVideoRtpExtension1),
1677 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1678 EXPECT_EQ(
1679 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1680 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1681 EXPECT_EQ(
1682 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1683 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001684}
1685
Johannes Kronce8e8672019-02-22 13:06:44 +01001686// Create a audio/video offer and answer and ensure that the
1687// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1688// supported and should take precedence even though not listed among locally
1689// supported extensions.
1690TEST_F(MediaSessionDescriptionFactoryTest,
1691 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1692 TestTransportSequenceNumberNegotiation(
1693 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1694 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1695 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1696}
1697TEST_F(MediaSessionDescriptionFactoryTest,
1698 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1699 TestTransportSequenceNumberNegotiation(
1700 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1701 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1702 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1703}
1704TEST_F(MediaSessionDescriptionFactoryTest,
1705 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1706 TestTransportSequenceNumberNegotiation(
1707 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1708 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1709 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1710}
1711
jbauch5869f502017-06-29 12:31:36 -07001712TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001713 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1714 MediaSessionOptions opts;
1715 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1716
Markus Handell6f727da2020-06-12 15:24:54 +00001717 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1718 f1_.set_audio_rtp_header_extensions(offered);
1719 f1_.set_video_rtp_header_extensions(offered);
1720 const auto local = MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01);
1721 f2_.set_audio_rtp_header_extensions(local);
1722 f2_.set_video_rtp_header_extensions(local);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001723 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1724 std::unique_ptr<SessionDescription> answer =
1725 f2_.CreateAnswer(offer.get(), opts, nullptr);
1726 EXPECT_THAT(
1727 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell6f727da2020-06-12 15:24:54 +00001728 ElementsAreArray(offered));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001729 EXPECT_THAT(
1730 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell6f727da2020-06-12 15:24:54 +00001731 ElementsAreArray(offered));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001732}
1733
1734TEST_F(MediaSessionDescriptionFactoryTest,
1735 TestNegotiateFrameDescriptorWhenExposedLocally) {
1736 MediaSessionOptions opts;
1737 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1738
Markus Handell6f727da2020-06-12 15:24:54 +00001739 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1740 f1_.set_audio_rtp_header_extensions(offered);
1741 f1_.set_video_rtp_header_extensions(offered);
1742 const auto local = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1743 f2_.set_audio_rtp_header_extensions(local);
1744 f2_.set_video_rtp_header_extensions(local);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001745 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1746 std::unique_ptr<SessionDescription> answer =
1747 f2_.CreateAnswer(offer.get(), opts, nullptr);
1748 EXPECT_THAT(
1749 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell6f727da2020-06-12 15:24:54 +00001750 ElementsAreArray(offered));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001751 EXPECT_THAT(
1752 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell6f727da2020-06-12 15:24:54 +00001753 ElementsAreArray(offered));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001754}
1755
1756TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001757 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1758 MediaSessionOptions opts;
1759 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1760
1761 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell71db9ac2020-06-08 19:48:49 +02001762 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
Markus Handell6f727da2020-06-12 15:24:54 +00001763 f1_.set_video_rtp_header_extensions({offer_dd});
1764 f2_.set_video_rtp_header_extensions({local_tsn});
1765 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001766 std::unique_ptr<SessionDescription> answer =
1767 f2_.CreateAnswer(offer.get(), opts, nullptr);
1768 EXPECT_THAT(
1769 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1770 ElementsAre(offer_dd));
1771}
1772
1773TEST_F(MediaSessionDescriptionFactoryTest,
1774 NegotiateDependencyDescriptorWhenExposedLocally) {
1775 MediaSessionOptions opts;
1776 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1777
1778 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1779 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell6f727da2020-06-12 15:24:54 +00001780 f1_.set_video_rtp_header_extensions({offer_dd});
1781 f2_.set_video_rtp_header_extensions({local_dd});
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001782 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1783 std::unique_ptr<SessionDescription> answer =
1784 f2_.CreateAnswer(offer.get(), opts, nullptr);
1785 EXPECT_THAT(
1786 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1787 ElementsAre(offer_dd));
1788}
1789
1790TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001791 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1792 MediaSessionOptions opts;
1793 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1794
1795 const cricket::RtpHeaderExtensions offered_extensions = {
1796 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1797 const cricket::RtpHeaderExtensions local_extensions = {
1798 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
Markus Handell6f727da2020-06-12 15:24:54 +00001799 f1_.set_video_rtp_header_extensions(offered_extensions);
1800 f1_.set_audio_rtp_header_extensions(offered_extensions);
1801 f2_.set_video_rtp_header_extensions(local_extensions);
1802 f2_.set_audio_rtp_header_extensions(local_extensions);
1803
Minyue Li430e4a02020-03-10 10:59:37 +01001804 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1805 std::unique_ptr<SessionDescription> answer =
1806 f2_.CreateAnswer(offer.get(), opts, nullptr);
1807 EXPECT_THAT(
1808 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1809 ElementsAreArray(offered_extensions));
1810 EXPECT_THAT(
1811 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1812 ElementsAreArray(offered_extensions));
1813}
1814
1815TEST_F(MediaSessionDescriptionFactoryTest,
1816 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1817 MediaSessionOptions opts;
1818 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1819
1820 const cricket::RtpHeaderExtensions offered_extensions = {
1821 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1822 const cricket::RtpHeaderExtensions local_extensions = {
1823 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell6f727da2020-06-12 15:24:54 +00001824 f1_.set_video_rtp_header_extensions(offered_extensions);
1825 f1_.set_audio_rtp_header_extensions(offered_extensions);
1826 f2_.set_video_rtp_header_extensions(local_extensions);
1827 f2_.set_audio_rtp_header_extensions(local_extensions);
1828
Minyue Li430e4a02020-03-10 10:59:37 +01001829 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1830 std::unique_ptr<SessionDescription> answer =
1831 f2_.CreateAnswer(offer.get(), opts, nullptr);
1832 EXPECT_THAT(
1833 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1834 ElementsAreArray(offered_extensions));
1835 EXPECT_THAT(
1836 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1837 ElementsAreArray(offered_extensions));
1838}
1839
1840TEST_F(MediaSessionDescriptionFactoryTest,
1841 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1842 MediaSessionOptions opts;
1843 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1844
1845 const cricket::RtpHeaderExtensions offered_extensions = {
1846 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1847 const cricket::RtpHeaderExtensions local_extensions = {
1848 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell6f727da2020-06-12 15:24:54 +00001849 f1_.set_video_rtp_header_extensions(offered_extensions);
1850 f1_.set_audio_rtp_header_extensions(offered_extensions);
1851 f2_.set_video_rtp_header_extensions(local_extensions);
1852 f2_.set_audio_rtp_header_extensions(local_extensions);
1853
Minyue Li430e4a02020-03-10 10:59:37 +01001854 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1855 std::unique_ptr<SessionDescription> answer =
1856 f2_.CreateAnswer(offer.get(), opts, nullptr);
1857 EXPECT_THAT(
1858 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1859 IsEmpty());
1860 EXPECT_THAT(
1861 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1862 IsEmpty());
1863}
1864
1865TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001866 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001867 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001868 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001869
1870 f1_.set_enable_encrypted_rtp_header_extensions(true);
1871 f2_.set_enable_encrypted_rtp_header_extensions(true);
1872
Markus Handell6f727da2020-06-12 15:24:54 +00001873 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1874 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1875 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1876 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1877
Steve Anton6fe1fba2018-12-11 10:15:23 -08001878 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001879 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001880 std::unique_ptr<SessionDescription> answer =
1881 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001882
Yves Gerey665174f2018-06-19 15:03:05 +02001883 EXPECT_EQ(
1884 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1885 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1886 EXPECT_EQ(
1887 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1888 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1889 EXPECT_EQ(
1890 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1891 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1892 EXPECT_EQ(
1893 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1894 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001895}
1896
1897TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001898 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001899 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001900 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001901
1902 f1_.set_enable_encrypted_rtp_header_extensions(true);
1903
Markus Handell6f727da2020-06-12 15:24:54 +00001904 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1905 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1906 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1907 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1908
Steve Anton6fe1fba2018-12-11 10:15:23 -08001909 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001910 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001911 std::unique_ptr<SessionDescription> answer =
1912 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001913
Yves Gerey665174f2018-06-19 15:03:05 +02001914 EXPECT_EQ(
1915 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1916 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1917 EXPECT_EQ(
1918 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1919 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1920 EXPECT_EQ(
1921 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1922 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1923 EXPECT_EQ(
1924 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1925 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001926}
1927
1928TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001929 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001930 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001931 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001932
1933 f2_.set_enable_encrypted_rtp_header_extensions(true);
1934
Markus Handell6f727da2020-06-12 15:24:54 +00001935 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1936 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1937 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1938 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1939
Steve Anton6fe1fba2018-12-11 10:15:23 -08001940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001941 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001942 std::unique_ptr<SessionDescription> answer =
1943 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001944
Yves Gerey665174f2018-06-19 15:03:05 +02001945 EXPECT_EQ(
1946 MAKE_VECTOR(kAudioRtpExtension1),
1947 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1948 EXPECT_EQ(
1949 MAKE_VECTOR(kVideoRtpExtension1),
1950 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1951 EXPECT_EQ(
1952 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1953 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1954 EXPECT_EQ(
1955 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1956 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001957}
1958
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001959// Create an audio, video, data answer without legacy StreamParams.
1960TEST_F(MediaSessionDescriptionFactoryTest,
1961 TestCreateAnswerWithoutLegacyStreams) {
1962 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001963 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1964 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001965 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001966 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001967 std::unique_ptr<SessionDescription> answer =
1968 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001969 const ContentInfo* ac = answer->GetContentByName("audio");
1970 const ContentInfo* vc = answer->GetContentByName("video");
1971 const ContentInfo* dc = answer->GetContentByName("data");
1972 ASSERT_TRUE(ac != NULL);
1973 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001974 const AudioContentDescription* acd = ac->media_description()->as_audio();
1975 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001976 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977
1978 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1979 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1980 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1981}
1982
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983// Create a typical video answer, and ensure it matches what we expect.
1984TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1985 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001986 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1987 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1988 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001989
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001991 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1992 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1993 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994
kwiberg31022942016-03-11 14:18:21 -08001995 std::unique_ptr<SessionDescription> offer;
1996 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001997
1998 offer_opts.rtcp_mux_enabled = true;
1999 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002000 offer = f1_.CreateOffer(offer_opts, NULL);
2001 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002002 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2003 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002004 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002005 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2006 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002007 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2009 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002010 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2012 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002013 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014
2015 offer_opts.rtcp_mux_enabled = true;
2016 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002017 offer = f1_.CreateOffer(offer_opts, NULL);
2018 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002019 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2020 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002021 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002022 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2023 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002024 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2026 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002027 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2029 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002030 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002031
2032 offer_opts.rtcp_mux_enabled = false;
2033 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002034 offer = f1_.CreateOffer(offer_opts, NULL);
2035 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002036 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2037 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002038 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002039 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2040 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002041 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002042 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2043 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002044 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002045 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2046 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002047 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002048
2049 offer_opts.rtcp_mux_enabled = false;
2050 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002051 offer = f1_.CreateOffer(offer_opts, NULL);
2052 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002053 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2054 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002055 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002056 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2057 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002058 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002059 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2060 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002061 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002062 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2063 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002064 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065}
2066
2067// Create an audio-only answer to a video offer.
2068TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2069 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002070 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2071 RtpTransceiverDirection::kRecvOnly, kActive,
2072 &opts);
2073 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2074 RtpTransceiverDirection::kRecvOnly, kActive,
2075 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002076 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002077 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002078
2079 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002080 std::unique_ptr<SessionDescription> answer =
2081 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002082 const ContentInfo* ac = answer->GetContentByName("audio");
2083 const ContentInfo* vc = answer->GetContentByName("video");
2084 ASSERT_TRUE(ac != NULL);
2085 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002086 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002087 EXPECT_TRUE(vc->rejected);
2088}
2089
2090// Create an audio-only answer to an offer with data.
2091TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002092 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002093 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002094 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2095 RtpTransceiverDirection::kRecvOnly, kActive,
2096 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002097 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002098 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002099
2100 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002101 std::unique_ptr<SessionDescription> answer =
2102 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002103 const ContentInfo* ac = answer->GetContentByName("audio");
2104 const ContentInfo* dc = answer->GetContentByName("data");
2105 ASSERT_TRUE(ac != NULL);
2106 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002107 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002108 EXPECT_TRUE(dc->rejected);
2109}
2110
2111// Create an answer that rejects the contents which are rejected in the offer.
2112TEST_F(MediaSessionDescriptionFactoryTest,
2113 CreateAnswerToOfferWithRejectedMedia) {
2114 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002115 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2116 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002117 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002118 ASSERT_TRUE(offer.get() != NULL);
2119 ContentInfo* ac = offer->GetContentByName("audio");
2120 ContentInfo* vc = offer->GetContentByName("video");
2121 ContentInfo* dc = offer->GetContentByName("data");
2122 ASSERT_TRUE(ac != NULL);
2123 ASSERT_TRUE(vc != NULL);
2124 ASSERT_TRUE(dc != NULL);
2125 ac->rejected = true;
2126 vc->rejected = true;
2127 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002128 std::unique_ptr<SessionDescription> answer =
2129 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130 ac = answer->GetContentByName("audio");
2131 vc = answer->GetContentByName("video");
2132 dc = answer->GetContentByName("data");
2133 ASSERT_TRUE(ac != NULL);
2134 ASSERT_TRUE(vc != NULL);
2135 ASSERT_TRUE(dc != NULL);
2136 EXPECT_TRUE(ac->rejected);
2137 EXPECT_TRUE(vc->rejected);
2138 EXPECT_TRUE(dc->rejected);
2139}
2140
Johannes Kron0854eb62018-10-10 22:33:20 +02002141TEST_F(MediaSessionDescriptionFactoryTest,
2142 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2143 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002144 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002145 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002146 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002147 ASSERT_TRUE(offer.get() != NULL);
2148 std::unique_ptr<SessionDescription> answer_no_support(
2149 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002150 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002151
2152 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002153 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002154 ASSERT_TRUE(offer.get() != NULL);
2155 std::unique_ptr<SessionDescription> answer_support(
2156 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002157 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002158}
2159
2160TEST_F(MediaSessionDescriptionFactoryTest,
2161 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2162 MediaSessionOptions opts;
2163 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002164 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002165 MediaContentDescription* video_offer =
2166 offer->GetContentDescriptionByName("video");
2167 ASSERT_TRUE(video_offer);
2168 MediaContentDescription* audio_offer =
2169 offer->GetContentDescriptionByName("audio");
2170 ASSERT_TRUE(audio_offer);
2171
2172 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002173 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2174 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002175
2176 ASSERT_TRUE(offer.get() != NULL);
2177 std::unique_ptr<SessionDescription> answer_no_support(
2178 f2_.CreateAnswer(offer.get(), opts, NULL));
2179 MediaContentDescription* video_answer =
2180 answer_no_support->GetContentDescriptionByName("video");
2181 MediaContentDescription* audio_answer =
2182 answer_no_support->GetContentDescriptionByName("audio");
2183 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002184 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002185 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002186 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002187
2188 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002189 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2190 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002191 ASSERT_TRUE(offer.get() != NULL);
2192 std::unique_ptr<SessionDescription> answer_support(
2193 f2_.CreateAnswer(offer.get(), opts, NULL));
2194 video_answer = answer_support->GetContentDescriptionByName("video");
2195 audio_answer = answer_support->GetContentDescriptionByName("audio");
2196 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002197 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002198 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002199 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002200}
2201
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002202// Create an audio and video offer with:
2203// - one video track
2204// - two audio tracks
2205// - two data tracks
2206// and ensure it matches what we expect. Also updates the initial offer by
2207// adding a new video track and replaces one of the audio tracks.
2208TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2209 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002210 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002211 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2212 {kMediaStream1}, 1, &opts);
2213 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2214 {kMediaStream1}, 1, &opts);
2215 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2216 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002217
Steve Anton4e70a722017-11-28 14:57:10 -08002218 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002219 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2220 {kMediaStream1}, 1, &opts);
2221 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2222 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002223
2224 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002225 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002226
2227 ASSERT_TRUE(offer.get() != NULL);
2228 const ContentInfo* ac = offer->GetContentByName("audio");
2229 const ContentInfo* vc = offer->GetContentByName("video");
2230 const ContentInfo* dc = offer->GetContentByName("data");
2231 ASSERT_TRUE(ac != NULL);
2232 ASSERT_TRUE(vc != NULL);
2233 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002234 const AudioContentDescription* acd = ac->media_description()->as_audio();
2235 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002236 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002237 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002238 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239
2240 const StreamParamsVec& audio_streams = acd->streams();
2241 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002242 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002243 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2244 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2245 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2246 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2247 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2248 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2249
2250 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2251 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002252 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002253
2254 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002255 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002256 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002257
2258 const StreamParamsVec& video_streams = vcd->streams();
2259 ASSERT_EQ(1U, video_streams.size());
2260 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2261 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2262 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2263 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2264
2265 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002266 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002267 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002268
2269 const StreamParamsVec& data_streams = dcd->streams();
2270 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002271 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002272 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2273 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2274 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2275 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2276 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2277 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2278
2279 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002280 dcd->bandwidth()); // default bandwidth (auto)
2281 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002282 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002283
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002284 // Update the offer. Add a new video track that is not synched to the
2285 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002286 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2287 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002288 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002289 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2290 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002291 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002292 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2293 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002294 std::unique_ptr<SessionDescription> updated_offer(
2295 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002296
2297 ASSERT_TRUE(updated_offer.get() != NULL);
2298 ac = updated_offer->GetContentByName("audio");
2299 vc = updated_offer->GetContentByName("video");
2300 dc = updated_offer->GetContentByName("data");
2301 ASSERT_TRUE(ac != NULL);
2302 ASSERT_TRUE(vc != NULL);
2303 ASSERT_TRUE(dc != NULL);
2304 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002305 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002306 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002307 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002308 const RtpDataContentDescription* updated_dcd =
2309 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310
2311 EXPECT_EQ(acd->type(), updated_acd->type());
2312 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2313 EXPECT_EQ(vcd->type(), updated_vcd->type());
2314 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2315 EXPECT_EQ(dcd->type(), updated_dcd->type());
2316 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002317 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002318 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002319 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002320 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002321 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002322 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2323
2324 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2325 ASSERT_EQ(2U, updated_audio_streams.size());
2326 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2327 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2328 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2329 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2330 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2331
2332 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2333 ASSERT_EQ(2U, updated_video_streams.size());
2334 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2335 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002336 // All the media streams in one PeerConnection share one RTCP CNAME.
2337 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002338
2339 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2340 ASSERT_EQ(2U, updated_data_streams.size());
2341 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2342 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2343 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2344 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2345 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002346 // The stream correctly got the CNAME from the MediaSessionOptions.
2347 // The Expected RTCP CNAME is the default one as we are using the default
2348 // MediaSessionOptions.
2349 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002350}
2351
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002352// Create an offer with simulcast video stream.
2353TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2354 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002355 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2356 RtpTransceiverDirection::kRecvOnly, kActive,
2357 &opts);
2358 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2359 RtpTransceiverDirection::kSendRecv, kActive,
2360 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002361 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002362 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2363 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002364 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002365
2366 ASSERT_TRUE(offer.get() != NULL);
2367 const ContentInfo* vc = offer->GetContentByName("video");
2368 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002369 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002370
2371 const StreamParamsVec& video_streams = vcd->streams();
2372 ASSERT_EQ(1U, video_streams.size());
2373 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2374 const SsrcGroup* sim_ssrc_group =
2375 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2376 ASSERT_TRUE(sim_ssrc_group != NULL);
2377 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2378}
2379
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002380MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2381 const RidDescription& rid1 = ::testing::get<0>(arg);
2382 const RidDescription& rid2 = ::testing::get<1>(arg);
2383 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2384}
2385
2386static void CheckSimulcastInSessionDescription(
2387 const SessionDescription* description,
2388 const std::string& content_name,
2389 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002390 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002391 ASSERT_NE(description, nullptr);
2392 const ContentInfo* content = description->GetContentByName(content_name);
2393 ASSERT_NE(content, nullptr);
2394 const MediaContentDescription* cd = content->media_description();
2395 ASSERT_NE(cd, nullptr);
2396 const StreamParamsVec& streams = cd->streams();
2397 ASSERT_THAT(streams, SizeIs(1));
2398 const StreamParams& stream = streams[0];
2399 ASSERT_THAT(stream.ssrcs, IsEmpty());
2400 EXPECT_TRUE(stream.has_rids());
2401 const std::vector<RidDescription> rids = stream.rids();
2402
2403 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2404
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002405 EXPECT_TRUE(cd->HasSimulcast());
2406 const SimulcastDescription& simulcast = cd->simulcast_description();
2407 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2408 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2409
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002410 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002411}
2412
2413// Create an offer with spec-compliant simulcast video stream.
2414TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2415 MediaSessionOptions opts;
2416 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2417 RtpTransceiverDirection::kSendRecv, kActive,
2418 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002419 std::vector<RidDescription> send_rids;
2420 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2421 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2422 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2423 SimulcastLayerList simulcast_layers;
2424 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2425 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2426 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2427 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2428 {kMediaStream1}, send_rids,
2429 simulcast_layers, 0, &opts);
2430 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2431
2432 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002433 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002434}
2435
2436// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2437// In this scenario, RIDs do not need to be negotiated (there is only one).
2438TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2439 MediaSessionOptions opts;
2440 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2441 RtpTransceiverDirection::kSendRecv, kActive,
2442 &opts);
2443 RidDescription rid("f", RidDirection::kSend);
2444 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2445 {kMediaStream1}, {rid},
2446 SimulcastLayerList(), 0, &opts);
2447 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2448
2449 ASSERT_NE(offer.get(), nullptr);
2450 const ContentInfo* content = offer->GetContentByName("video");
2451 ASSERT_NE(content, nullptr);
2452 const MediaContentDescription* cd = content->media_description();
2453 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002454 const StreamParamsVec& streams = cd->streams();
2455 ASSERT_THAT(streams, SizeIs(1));
2456 const StreamParams& stream = streams[0];
2457 ASSERT_THAT(stream.ssrcs, IsEmpty());
2458 EXPECT_FALSE(stream.has_rids());
2459 EXPECT_FALSE(cd->HasSimulcast());
2460}
2461
2462// Create an answer with spec-compliant simulcast video stream.
2463// In this scenario, the SFU is the caller requesting that we send Simulcast.
2464TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2465 MediaSessionOptions offer_opts;
2466 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2467 RtpTransceiverDirection::kSendRecv, kActive,
2468 &offer_opts);
2469 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2470 {kMediaStream1}, 1, &offer_opts);
2471 std::unique_ptr<SessionDescription> offer =
2472 f1_.CreateOffer(offer_opts, nullptr);
2473
2474 MediaSessionOptions answer_opts;
2475 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2476 RtpTransceiverDirection::kSendRecv, kActive,
2477 &answer_opts);
2478
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002479 std::vector<RidDescription> rid_descriptions{
2480 RidDescription("f", RidDirection::kSend),
2481 RidDescription("h", RidDirection::kSend),
2482 RidDescription("q", RidDirection::kSend),
2483 };
2484 SimulcastLayerList simulcast_layers;
2485 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2486 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2487 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2488 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2489 {kMediaStream1}, rid_descriptions,
2490 simulcast_layers, 0, &answer_opts);
2491 std::unique_ptr<SessionDescription> answer =
2492 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2493
2494 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002495 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002496}
2497
2498// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2499// In this scenario, RIDs do not need to be negotiated (there is only one).
2500// Note that RID Direction is not the same as the transceiver direction.
2501TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2502 MediaSessionOptions offer_opts;
2503 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2504 RtpTransceiverDirection::kSendRecv, kActive,
2505 &offer_opts);
2506 RidDescription rid_offer("f", RidDirection::kSend);
2507 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2508 {kMediaStream1}, {rid_offer},
2509 SimulcastLayerList(), 0, &offer_opts);
2510 std::unique_ptr<SessionDescription> offer =
2511 f1_.CreateOffer(offer_opts, nullptr);
2512
2513 MediaSessionOptions answer_opts;
2514 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2515 RtpTransceiverDirection::kSendRecv, kActive,
2516 &answer_opts);
2517
2518 RidDescription rid_answer("f", RidDirection::kReceive);
2519 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2520 {kMediaStream1}, {rid_answer},
2521 SimulcastLayerList(), 0, &answer_opts);
2522 std::unique_ptr<SessionDescription> answer =
2523 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2524
2525 ASSERT_NE(answer.get(), nullptr);
2526 const ContentInfo* content = offer->GetContentByName("video");
2527 ASSERT_NE(content, nullptr);
2528 const MediaContentDescription* cd = content->media_description();
2529 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002530 const StreamParamsVec& streams = cd->streams();
2531 ASSERT_THAT(streams, SizeIs(1));
2532 const StreamParams& stream = streams[0];
2533 ASSERT_THAT(stream.ssrcs, IsEmpty());
2534 EXPECT_FALSE(stream.has_rids());
2535 EXPECT_FALSE(cd->HasSimulcast());
2536}
2537
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002538// Create an audio and video answer to a standard video offer with:
2539// - one video track
2540// - two audio tracks
2541// - two data tracks
2542// and ensure it matches what we expect. Also updates the initial answer by
2543// adding a new video track and removes one of the audio tracks.
2544TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2545 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002546 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2547 RtpTransceiverDirection::kRecvOnly, kActive,
2548 &offer_opts);
2549 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2550 RtpTransceiverDirection::kRecvOnly, kActive,
2551 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002552 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002553 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2554 RtpTransceiverDirection::kRecvOnly, kActive,
2555 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002556 f1_.set_secure(SEC_ENABLED);
2557 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002558 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002559
zhihuang1c378ed2017-08-17 14:10:50 -07002560 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002561 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2562 RtpTransceiverDirection::kSendRecv, kActive,
2563 &answer_opts);
2564 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2565 RtpTransceiverDirection::kSendRecv, kActive,
2566 &answer_opts);
2567 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2568 {kMediaStream1}, 1, &answer_opts);
2569 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2570 {kMediaStream1}, 1, &answer_opts);
2571 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2572 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002573
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002574 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2575 RtpTransceiverDirection::kSendRecv, kActive,
2576 &answer_opts);
2577 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2578 {kMediaStream1}, 1, &answer_opts);
2579 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2580 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002581 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002582
Steve Anton6fe1fba2018-12-11 10:15:23 -08002583 std::unique_ptr<SessionDescription> answer =
2584 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002585
2586 ASSERT_TRUE(answer.get() != NULL);
2587 const ContentInfo* ac = answer->GetContentByName("audio");
2588 const ContentInfo* vc = answer->GetContentByName("video");
2589 const ContentInfo* dc = answer->GetContentByName("data");
2590 ASSERT_TRUE(ac != NULL);
2591 ASSERT_TRUE(vc != NULL);
2592 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002593 const AudioContentDescription* acd = ac->media_description()->as_audio();
2594 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002595 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002596 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2597 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2598 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002599
2600 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002601 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002602
2603 const StreamParamsVec& audio_streams = acd->streams();
2604 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002605 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002606 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2607 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2608 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2609 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2610 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2611 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2612
2613 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2614 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2615
2616 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002617 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002618
2619 const StreamParamsVec& video_streams = vcd->streams();
2620 ASSERT_EQ(1U, video_streams.size());
2621 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2622 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2623 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2624 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2625
2626 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002627 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002628
2629 const StreamParamsVec& data_streams = dcd->streams();
2630 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002631 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002632 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2633 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2634 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2635 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2636 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2637 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2638
2639 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002640 dcd->bandwidth()); // default bandwidth (auto)
2641 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642
2643 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002644 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002645 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2646 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002647 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2648 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002649 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002650 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002651
2652 ASSERT_TRUE(updated_answer.get() != NULL);
2653 ac = updated_answer->GetContentByName("audio");
2654 vc = updated_answer->GetContentByName("video");
2655 dc = updated_answer->GetContentByName("data");
2656 ASSERT_TRUE(ac != NULL);
2657 ASSERT_TRUE(vc != NULL);
2658 ASSERT_TRUE(dc != NULL);
2659 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002660 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002662 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002663 const RtpDataContentDescription* updated_dcd =
2664 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002665
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002666 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002667 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002668 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002669 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002670 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002671 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2672
2673 EXPECT_EQ(acd->type(), updated_acd->type());
2674 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2675 EXPECT_EQ(vcd->type(), updated_vcd->type());
2676 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2677 EXPECT_EQ(dcd->type(), updated_dcd->type());
2678 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2679
2680 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2681 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002682 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002683
2684 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2685 ASSERT_EQ(2U, updated_video_streams.size());
2686 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2687 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002688 // All media streams in one PeerConnection share one CNAME.
2689 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002690
2691 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2692 ASSERT_EQ(1U, updated_data_streams.size());
2693 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2694}
2695
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696// Create an updated offer after creating an answer to the original offer and
2697// verify that the codecs that were part of the original answer are not changed
2698// in the updated offer.
2699TEST_F(MediaSessionDescriptionFactoryTest,
2700 RespondentCreatesOfferAfterCreatingAnswer) {
2701 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002702 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002703
Steve Anton6fe1fba2018-12-11 10:15:23 -08002704 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2705 std::unique_ptr<SessionDescription> answer =
2706 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707
2708 const AudioContentDescription* acd =
2709 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002710 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711
2712 const VideoContentDescription* vcd =
2713 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002714 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002715
kwiberg31022942016-03-11 14:18:21 -08002716 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002717 f2_.CreateOffer(opts, answer.get()));
2718
2719 // The expected audio codecs are the common audio codecs from the first
2720 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2721 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002722 // TODO(wu): |updated_offer| should not include the codec
2723 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002724 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002725 kAudioCodecsAnswer[0],
2726 kAudioCodecsAnswer[1],
2727 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002728 };
2729
2730 // The expected video codecs are the common video codecs from the first
2731 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2732 // preference order.
2733 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002734 kVideoCodecsAnswer[0],
2735 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002736 };
2737
2738 const AudioContentDescription* updated_acd =
2739 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002740 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002741
2742 const VideoContentDescription* updated_vcd =
2743 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002744 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002745}
2746
Steve Anton5c72e712018-12-10 14:25:30 -08002747// Test that a reoffer does not reuse audio codecs from a previous media section
2748// that is being recycled.
2749TEST_F(MediaSessionDescriptionFactoryTest,
2750 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002751 f1_.set_video_codecs({}, {});
2752 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002753
2754 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002755 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2756 RtpTransceiverDirection::kSendRecv, kActive,
2757 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002758 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2759 std::unique_ptr<SessionDescription> answer =
2760 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002761
2762 // Recycle the media section by changing its mid.
2763 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002764 std::unique_ptr<SessionDescription> reoffer =
2765 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002766
2767 // Expect that the results of the first negotiation are ignored. If the m=
2768 // section was not recycled the payload types would match the initial offerer.
2769 const AudioContentDescription* acd =
2770 GetFirstAudioContentDescription(reoffer.get());
2771 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2772}
2773
2774// Test that a reoffer does not reuse video codecs from a previous media section
2775// that is being recycled.
2776TEST_F(MediaSessionDescriptionFactoryTest,
2777 ReOfferDoesNotReUseRecycledVideoCodecs) {
2778 f1_.set_audio_codecs({}, {});
2779 f2_.set_audio_codecs({}, {});
2780
2781 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002782 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2783 RtpTransceiverDirection::kSendRecv, kActive,
2784 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002785 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2786 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002787
2788 // Recycle the media section by changing its mid.
2789 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002790 std::unique_ptr<SessionDescription> reoffer =
2791 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002792
2793 // Expect that the results of the first negotiation are ignored. If the m=
2794 // section was not recycled the payload types would match the initial offerer.
2795 const VideoContentDescription* vcd =
2796 GetFirstVideoContentDescription(reoffer.get());
2797 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2798}
2799
2800// Test that a reanswer does not reuse audio codecs from a previous media
2801// section that is being recycled.
2802TEST_F(MediaSessionDescriptionFactoryTest,
2803 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002804 f1_.set_video_codecs({}, {});
2805 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002806
2807 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2808 // second offer/answer is forward (|f1_| as offerer).
2809 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002810 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2811 RtpTransceiverDirection::kSendRecv, kActive,
2812 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002813 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2814 std::unique_ptr<SessionDescription> answer =
2815 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002816
2817 // Recycle the media section by changing its mid.
2818 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002819 std::unique_ptr<SessionDescription> reoffer =
2820 f1_.CreateOffer(opts, answer.get());
2821 std::unique_ptr<SessionDescription> reanswer =
2822 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002823
2824 // Expect that the results of the first negotiation are ignored. If the m=
2825 // section was not recycled the payload types would match the initial offerer.
2826 const AudioContentDescription* acd =
2827 GetFirstAudioContentDescription(reanswer.get());
2828 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2829}
2830
2831// Test that a reanswer does not reuse video codecs from a previous media
2832// section that is being recycled.
2833TEST_F(MediaSessionDescriptionFactoryTest,
2834 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2835 f1_.set_audio_codecs({}, {});
2836 f2_.set_audio_codecs({}, {});
2837
2838 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2839 // second offer/answer is forward (|f1_| as offerer).
2840 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002841 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2842 RtpTransceiverDirection::kSendRecv, kActive,
2843 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002844 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2845 std::unique_ptr<SessionDescription> answer =
2846 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002847
2848 // Recycle the media section by changing its mid.
2849 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002850 std::unique_ptr<SessionDescription> reoffer =
2851 f1_.CreateOffer(opts, answer.get());
2852 std::unique_ptr<SessionDescription> reanswer =
2853 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002854
2855 // Expect that the results of the first negotiation are ignored. If the m=
2856 // section was not recycled the payload types would match the initial offerer.
2857 const VideoContentDescription* vcd =
2858 GetFirstVideoContentDescription(reanswer.get());
2859 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2860}
2861
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002862// Create an updated offer after creating an answer to the original offer and
2863// verify that the codecs that were part of the original answer are not changed
2864// in the updated offer. In this test Rtx is enabled.
2865TEST_F(MediaSessionDescriptionFactoryTest,
2866 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2867 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002868 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2869 RtpTransceiverDirection::kRecvOnly, kActive,
2870 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002871 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002872 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002873 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002874 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002875
2876 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002877 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002878 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002879 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002880
Steve Anton6fe1fba2018-12-11 10:15:23 -08002881 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002882 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002883 std::unique_ptr<SessionDescription> answer =
2884 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002885
2886 const VideoContentDescription* vcd =
2887 GetFirstVideoContentDescription(answer.get());
2888
2889 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002890 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2891 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002892
2893 EXPECT_EQ(expected_codecs, vcd->codecs());
2894
deadbeef67cf2c12016-04-13 10:07:16 -07002895 // Now, make sure we get same result (except for the order) if |f2_| creates
2896 // an updated offer even though the default payload types between |f1_| and
2897 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002898 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002899 f2_.CreateOffer(opts, answer.get()));
2900 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002901 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002902 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2903
2904 const VideoContentDescription* updated_vcd =
2905 GetFirstVideoContentDescription(updated_answer.get());
2906
2907 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2908}
2909
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002910// Regression test for:
2911// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2912// Existing codecs should always appear before new codecs in re-offers. But
2913// under a specific set of circumstances, the existing RTX codec was ending up
2914// added to the end of the list.
2915TEST_F(MediaSessionDescriptionFactoryTest,
2916 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2917 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002918 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2919 RtpTransceiverDirection::kRecvOnly, kActive,
2920 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002921 // We specifically choose different preferred payload types for VP8 to
2922 // trigger the issue.
2923 cricket::VideoCodec vp8_offerer(100, "VP8");
2924 cricket::VideoCodec vp8_offerer_rtx =
2925 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2926 cricket::VideoCodec vp8_answerer(110, "VP8");
2927 cricket::VideoCodec vp8_answerer_rtx =
2928 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2929 cricket::VideoCodec vp9(120, "VP9");
2930 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2931
2932 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2933 // We also specifically cause the answerer to prefer VP9, such that if it
2934 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2935 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2936 vp8_answerer_rtx};
2937
Johannes Kron3e983682020-03-29 22:17:00 +02002938 f1_.set_video_codecs(f1_codecs, f1_codecs);
2939 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002940 std::vector<AudioCodec> audio_codecs;
2941 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2942 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2943
2944 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002945 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002946 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002947 std::unique_ptr<SessionDescription> answer =
2948 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002949
2950 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2951 // But if the bug is triggered, RTX for VP8 ends up last.
2952 std::unique_ptr<SessionDescription> updated_offer(
2953 f2_.CreateOffer(opts, answer.get()));
2954
2955 const VideoContentDescription* vcd =
2956 GetFirstVideoContentDescription(updated_offer.get());
2957 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2958 ASSERT_EQ(4u, codecs.size());
2959 EXPECT_EQ(vp8_offerer, codecs[0]);
2960 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2961 EXPECT_EQ(vp9, codecs[2]);
2962 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002963}
2964
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002965// Create an updated offer that adds video after creating an audio only answer
2966// to the original offer. This test verifies that if a video codec and the RTX
2967// codec have the same default payload type as an audio codec that is already in
2968// use, the added codecs payload types are changed.
2969TEST_F(MediaSessionDescriptionFactoryTest,
2970 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2971 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002972 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002973 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002974 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002975
2976 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002977 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2978 RtpTransceiverDirection::kRecvOnly, kActive,
2979 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980
Steve Anton6fe1fba2018-12-11 10:15:23 -08002981 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2982 std::unique_ptr<SessionDescription> answer =
2983 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002984
2985 const AudioContentDescription* acd =
2986 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002987 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002988
2989 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2990 // reference be the same as an audio codec that was negotiated in the
2991 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002992 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002993 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002994
2995 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2996 int used_pl_type = acd->codecs()[0].id;
2997 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002998 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002999 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003000
kwiberg31022942016-03-11 14:18:21 -08003001 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003002 f2_.CreateOffer(opts, answer.get()));
3003 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003004 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003005 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3006
3007 const AudioContentDescription* updated_acd =
3008 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003009 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003010
3011 const VideoContentDescription* updated_vcd =
3012 GetFirstVideoContentDescription(updated_answer.get());
3013
3014 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003015 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003016 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003017 EXPECT_NE(used_pl_type, new_h264_pl_type);
3018 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003019 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003020 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3021 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3022}
3023
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003024// Create an updated offer with RTX after creating an answer to an offer
3025// without RTX, and with different default payload types.
3026// Verify that the added RTX codec references the correct payload type.
3027TEST_F(MediaSessionDescriptionFactoryTest,
3028 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3029 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003030 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003031
3032 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3033 // This creates rtx for H264 with the payload type |f2_| uses.
3034 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003035 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003036
Steve Anton6fe1fba2018-12-11 10:15:23 -08003037 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003038 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003039 std::unique_ptr<SessionDescription> answer =
3040 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003041
3042 const VideoContentDescription* vcd =
3043 GetFirstVideoContentDescription(answer.get());
3044
3045 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3046 EXPECT_EQ(expected_codecs, vcd->codecs());
3047
3048 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
3049 // updated offer, even though the default payload types are different from
3050 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08003051 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003052 f2_.CreateOffer(opts, answer.get()));
3053 ASSERT_TRUE(updated_offer);
3054
3055 const VideoContentDescription* updated_vcd =
3056 GetFirstVideoContentDescription(updated_offer.get());
3057
3058 // New offer should attempt to add H263, and RTX for H264.
3059 expected_codecs.push_back(kVideoCodecs2[1]);
3060 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3061 &expected_codecs);
3062 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3063}
3064
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003065// Test that RTX is ignored when there is no associated payload type parameter.
3066TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3067 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003068 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3069 RtpTransceiverDirection::kRecvOnly, kActive,
3070 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003071 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003072 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003073 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003074 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003075
3076 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003077 // This creates RTX for H264 with the payload type |f2_| uses.
3078 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003079 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003080
Steve Anton6fe1fba2018-12-11 10:15:23 -08003081 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003082 ASSERT_TRUE(offer.get() != NULL);
3083 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3084 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3085 // is possible to test that that RTX is dropped when
3086 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003087 MediaContentDescription* media_desc =
3088 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3089 ASSERT_TRUE(media_desc);
3090 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003091 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003092 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003093 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003094 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003095 }
3096 }
3097 desc->set_codecs(codecs);
3098
Steve Anton6fe1fba2018-12-11 10:15:23 -08003099 std::unique_ptr<SessionDescription> answer =
3100 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003101
Steve Anton64b626b2019-01-28 17:25:26 -08003102 EXPECT_THAT(
3103 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3104 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003105}
3106
3107// Test that RTX will be filtered out in the answer if its associated payload
3108// type doesn't match the local value.
3109TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3110 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003111 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3112 RtpTransceiverDirection::kRecvOnly, kActive,
3113 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003114 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3115 // This creates RTX for H264 in sender.
3116 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003117 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003118
3119 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3120 // This creates RTX for H263 in receiver.
3121 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003122 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003123
Steve Anton6fe1fba2018-12-11 10:15:23 -08003124 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003125 ASSERT_TRUE(offer.get() != NULL);
3126 // Associated payload type doesn't match, therefore, RTX codec is removed in
3127 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003128 std::unique_ptr<SessionDescription> answer =
3129 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003130
Steve Anton64b626b2019-01-28 17:25:26 -08003131 EXPECT_THAT(
3132 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3133 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003134}
3135
3136// Test that when multiple RTX codecs are offered, only the matched RTX codec
3137// is added in the answer, and the unsupported RTX codec is filtered out.
3138TEST_F(MediaSessionDescriptionFactoryTest,
3139 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3140 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003141 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3142 RtpTransceiverDirection::kRecvOnly, kActive,
3143 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003144 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3145 // This creates RTX for H264-SVC in sender.
3146 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003147 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003148
3149 // This creates RTX for H264 in sender.
3150 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003151 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003152
3153 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3154 // This creates RTX for H264 in receiver.
3155 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003156 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003157
3158 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3159 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003160 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003161 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003162 std::unique_ptr<SessionDescription> answer =
3163 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003164 const VideoContentDescription* vcd =
3165 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003166 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3167 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3168 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003169
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003170 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003171}
3172
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003173// Test that after one RTX codec has been negotiated, a new offer can attempt
3174// to add another.
3175TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3176 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003177 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3178 RtpTransceiverDirection::kRecvOnly, kActive,
3179 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003180 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3181 // This creates RTX for H264 for the offerer.
3182 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003183 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003184
Steve Anton6fe1fba2018-12-11 10:15:23 -08003185 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003186 ASSERT_TRUE(offer);
3187 const VideoContentDescription* vcd =
3188 GetFirstVideoContentDescription(offer.get());
3189
3190 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3191 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3192 &expected_codecs);
3193 EXPECT_EQ(expected_codecs, vcd->codecs());
3194
3195 // Now, attempt to add RTX for H264-SVC.
3196 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003197 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003198
kwiberg31022942016-03-11 14:18:21 -08003199 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003200 f1_.CreateOffer(opts, offer.get()));
3201 ASSERT_TRUE(updated_offer);
3202 vcd = GetFirstVideoContentDescription(updated_offer.get());
3203
3204 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3205 &expected_codecs);
3206 EXPECT_EQ(expected_codecs, vcd->codecs());
3207}
3208
Noah Richards2e7a0982015-05-18 14:02:54 -07003209// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3210// generated for each simulcast ssrc and correctly grouped.
3211TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3212 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003213 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3214 RtpTransceiverDirection::kSendRecv, kActive,
3215 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003216 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003217 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3218 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003219
3220 // Use a single real codec, and then add RTX for it.
3221 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003222 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003223 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003224 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003225
3226 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3227 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003228 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003229 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003230 MediaContentDescription* media_desc =
3231 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3232 ASSERT_TRUE(media_desc);
3233 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003234 const StreamParamsVec& streams = desc->streams();
3235 // Single stream.
3236 ASSERT_EQ(1u, streams.size());
3237 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3238 EXPECT_EQ(6u, streams[0].ssrcs.size());
3239 // And should have a SIM group for the simulcast.
3240 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3241 // And a FID group for RTX.
3242 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003243 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003244 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3245 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003246 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003247 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3248 EXPECT_EQ(3u, fid_ssrcs.size());
3249}
3250
brandtr03d5fb12016-11-22 03:37:59 -08003251// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3252// together with a FEC-FR grouping.
3253TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3254 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003255 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3256 RtpTransceiverDirection::kSendRecv, kActive,
3257 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003258 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003259 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3260 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003261
3262 // Use a single real codec, and then add FlexFEC for it.
3263 std::vector<VideoCodec> f1_codecs;
3264 f1_codecs.push_back(VideoCodec(97, "H264"));
3265 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003266 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003267
3268 // Ensure that the offer has a single FlexFEC ssrc and that
3269 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003270 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003271 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003272 MediaContentDescription* media_desc =
3273 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3274 ASSERT_TRUE(media_desc);
3275 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003276 const StreamParamsVec& streams = desc->streams();
3277 // Single stream.
3278 ASSERT_EQ(1u, streams.size());
3279 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3280 EXPECT_EQ(2u, streams[0].ssrcs.size());
3281 // And should have a FEC-FR group for FlexFEC.
3282 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3283 std::vector<uint32_t> primary_ssrcs;
3284 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3285 ASSERT_EQ(1u, primary_ssrcs.size());
3286 uint32_t flexfec_ssrc;
3287 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3288 EXPECT_NE(flexfec_ssrc, 0u);
3289}
3290
3291// Test that FlexFEC is disabled for simulcast.
3292// TODO(brandtr): Remove this test when we support simulcast, either through
3293// multiple FlexfecSenders, or through multistream protection.
3294TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3295 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003296 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3297 RtpTransceiverDirection::kSendRecv, kActive,
3298 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003299 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003300 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3301 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003302
3303 // Use a single real codec, and then add FlexFEC for it.
3304 std::vector<VideoCodec> f1_codecs;
3305 f1_codecs.push_back(VideoCodec(97, "H264"));
3306 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003307 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003308
3309 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3310 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003311 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003312 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003313 MediaContentDescription* media_desc =
3314 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3315 ASSERT_TRUE(media_desc);
3316 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003317 const StreamParamsVec& streams = desc->streams();
3318 // Single stream.
3319 ASSERT_EQ(1u, streams.size());
3320 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3321 EXPECT_EQ(3u, streams[0].ssrcs.size());
3322 // And should have a SIM group for the simulcast.
3323 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3324 // And not a FEC-FR group for FlexFEC.
3325 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3326 std::vector<uint32_t> primary_ssrcs;
3327 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3328 EXPECT_EQ(3u, primary_ssrcs.size());
3329 for (uint32_t primary_ssrc : primary_ssrcs) {
3330 uint32_t flexfec_ssrc;
3331 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3332 }
3333}
3334
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003335// Create an updated offer after creating an answer to the original offer and
3336// verify that the RTP header extensions that were part of the original answer
3337// are not changed in the updated offer.
3338TEST_F(MediaSessionDescriptionFactoryTest,
3339 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3340 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003341 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003342
Markus Handell6f727da2020-06-12 15:24:54 +00003343 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3344 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3345 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3346 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3347
Steve Anton6fe1fba2018-12-11 10:15:23 -08003348 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3349 std::unique_ptr<SessionDescription> answer =
3350 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003351
Yves Gerey665174f2018-06-19 15:03:05 +02003352 EXPECT_EQ(
3353 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3354 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3355 EXPECT_EQ(
3356 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3357 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003358
kwiberg31022942016-03-11 14:18:21 -08003359 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003360 f2_.CreateOffer(opts, answer.get()));
3361
3362 // The expected RTP header extensions in the new offer are the resulting
3363 // extensions from the first offer/answer exchange plus the extensions only
3364 // |f2_| offer.
3365 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003366 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003367 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003368 kAudioRtpExtensionAnswer[0],
3369 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003370 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003371 };
3372
3373 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003374 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003375 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003376 kVideoRtpExtensionAnswer[0],
3377 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003378 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003379 };
3380
3381 const AudioContentDescription* updated_acd =
3382 GetFirstAudioContentDescription(updated_offer.get());
3383 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3384 updated_acd->rtp_header_extensions());
3385
3386 const VideoContentDescription* updated_vcd =
3387 GetFirstVideoContentDescription(updated_offer.get());
3388 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3389 updated_vcd->rtp_header_extensions());
3390}
3391
deadbeefa5b273a2015-08-20 17:30:13 -07003392// Verify that if the same RTP extension URI is used for audio and video, the
3393// same ID is used. Also verify that the ID isn't changed when creating an
3394// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003395TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003396 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003397 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003398
Markus Handell6f727da2020-06-12 15:24:54 +00003399 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3400 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3401
Steve Anton6fe1fba2018-12-11 10:15:23 -08003402 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003403
3404 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3405 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003406 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003407 kVideoRtpExtension3[0],
3408 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003409 };
3410
Yves Gerey665174f2018-06-19 15:03:05 +02003411 EXPECT_EQ(
3412 MAKE_VECTOR(kAudioRtpExtension3),
3413 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3414 EXPECT_EQ(
3415 MAKE_VECTOR(kExpectedVideoRtpExtension),
3416 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003417
3418 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003419 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003420 f1_.CreateOffer(opts, offer.get()));
3421
3422 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003423 GetFirstAudioContentDescription(updated_offer.get())
3424 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003425 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003426 GetFirstVideoContentDescription(updated_offer.get())
3427 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003428}
3429
jbauch5869f502017-06-29 12:31:36 -07003430// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3431TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3432 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003433 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003434
3435 f1_.set_enable_encrypted_rtp_header_extensions(true);
3436 f2_.set_enable_encrypted_rtp_header_extensions(true);
3437
Markus Handell6f727da2020-06-12 15:24:54 +00003438 f1_.set_audio_rtp_header_extensions(
3439 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3440 f1_.set_video_rtp_header_extensions(
3441 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3442
Steve Anton6fe1fba2018-12-11 10:15:23 -08003443 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003444
3445 // The extensions that are shared between audio and video should use the same
3446 // id.
3447 const RtpExtension kExpectedVideoRtpExtension[] = {
3448 kVideoRtpExtension3ForEncryption[0],
3449 kAudioRtpExtension3ForEncryptionOffer[1],
3450 kAudioRtpExtension3ForEncryptionOffer[2],
3451 };
3452
Yves Gerey665174f2018-06-19 15:03:05 +02003453 EXPECT_EQ(
3454 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3455 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3456 EXPECT_EQ(
3457 MAKE_VECTOR(kExpectedVideoRtpExtension),
3458 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003459
3460 // Nothing should change when creating a new offer
3461 std::unique_ptr<SessionDescription> updated_offer(
3462 f1_.CreateOffer(opts, offer.get()));
3463
3464 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003465 GetFirstAudioContentDescription(updated_offer.get())
3466 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003467 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003468 GetFirstVideoContentDescription(updated_offer.get())
3469 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003470}
3471
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003472TEST(MediaSessionDescription, CopySessionDescription) {
3473 SessionDescription source;
3474 cricket::ContentGroup group(cricket::CN_AUDIO);
3475 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003476 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003477 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003478 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3479 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003480 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003481 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003482 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003483 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3484 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003485 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003486
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003487 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003488 ASSERT_TRUE(copy.get() != NULL);
3489 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3490 const ContentInfo* ac = copy->GetContentByName("audio");
3491 const ContentInfo* vc = copy->GetContentByName("video");
3492 ASSERT_TRUE(ac != NULL);
3493 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003494 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003495 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003496 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3497 EXPECT_EQ(1u, acd->first_ssrc());
3498
Steve Anton5adfafd2017-12-20 16:34:00 -08003499 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003500 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003501 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3502 EXPECT_EQ(2u, vcd->first_ssrc());
3503}
3504
3505// The below TestTransportInfoXXX tests create different offers/answers, and
3506// ensure the TransportInfo in the SessionDescription matches what we expect.
3507TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3508 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003509 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3510 RtpTransceiverDirection::kRecvOnly, kActive,
3511 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003512 TestTransportInfo(true, options, false);
3513}
3514
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003515TEST_F(MediaSessionDescriptionFactoryTest,
3516 TestTransportInfoOfferIceRenomination) {
3517 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003518 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3519 RtpTransceiverDirection::kRecvOnly, kActive,
3520 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003521 options.media_description_options[0]
3522 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003523 TestTransportInfo(true, options, false);
3524}
3525
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003526TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3527 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003528 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3529 RtpTransceiverDirection::kRecvOnly, kActive,
3530 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003531 TestTransportInfo(true, options, true);
3532}
3533
3534TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3535 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003536 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3537 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3538 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003539 TestTransportInfo(true, options, false);
3540}
3541
3542TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003543 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003544 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003545 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3546 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3547 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003548 TestTransportInfo(true, options, true);
3549}
3550
3551TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3552 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003553 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3554 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3555 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003556 options.bundle_enabled = true;
3557 TestTransportInfo(true, options, false);
3558}
3559
3560TEST_F(MediaSessionDescriptionFactoryTest,
3561 TestTransportInfoOfferBundleCurrent) {
3562 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003563 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3564 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3565 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003566 options.bundle_enabled = true;
3567 TestTransportInfo(true, options, true);
3568}
3569
3570TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3571 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003572 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3573 RtpTransceiverDirection::kRecvOnly, kActive,
3574 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003575 TestTransportInfo(false, options, false);
3576}
3577
3578TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003579 TestTransportInfoAnswerIceRenomination) {
3580 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003581 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3582 RtpTransceiverDirection::kRecvOnly, kActive,
3583 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003584 options.media_description_options[0]
3585 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003586 TestTransportInfo(false, options, false);
3587}
3588
3589TEST_F(MediaSessionDescriptionFactoryTest,
3590 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003591 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003592 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3593 RtpTransceiverDirection::kRecvOnly, kActive,
3594 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003595 TestTransportInfo(false, options, true);
3596}
3597
3598TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3599 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003600 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3601 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3602 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003603 TestTransportInfo(false, options, false);
3604}
3605
3606TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003607 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003608 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003609 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3610 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3611 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003612 TestTransportInfo(false, options, true);
3613}
3614
3615TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3616 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003617 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3618 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3619 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003620 options.bundle_enabled = true;
3621 TestTransportInfo(false, options, false);
3622}
3623
3624TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003625 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003626 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003627 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3628 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3629 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003630 options.bundle_enabled = true;
3631 TestTransportInfo(false, options, true);
3632}
3633
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003634TEST_F(MediaSessionDescriptionFactoryTest,
3635 TestTransportInfoOfferBundlesTransportOptions) {
3636 MediaSessionOptions options;
3637 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3638
3639 cricket::OpaqueTransportParameters audio_params;
3640 audio_params.protocol = "audio-transport";
3641 audio_params.parameters = "audio-params";
3642 FindFirstMediaDescriptionByMid("audio", &options)
3643 ->transport_options.opaque_parameters = audio_params;
3644
3645 cricket::OpaqueTransportParameters video_params;
3646 video_params.protocol = "video-transport";
3647 video_params.parameters = "video-params";
3648 FindFirstMediaDescriptionByMid("video", &options)
3649 ->transport_options.opaque_parameters = video_params;
3650
3651 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3652}
3653
3654TEST_F(MediaSessionDescriptionFactoryTest,
3655 TestTransportInfoAnswerBundlesTransportOptions) {
3656 MediaSessionOptions options;
3657 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3658
3659 cricket::OpaqueTransportParameters audio_params;
3660 audio_params.protocol = "audio-transport";
3661 audio_params.parameters = "audio-params";
3662 FindFirstMediaDescriptionByMid("audio", &options)
3663 ->transport_options.opaque_parameters = audio_params;
3664
3665 cricket::OpaqueTransportParameters video_params;
3666 video_params.protocol = "video-transport";
3667 video_params.parameters = "video-params";
3668 FindFirstMediaDescriptionByMid("video", &options)
3669 ->transport_options.opaque_parameters = video_params;
3670
3671 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3672}
3673
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003674TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3675 MediaSessionOptions options;
3676 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3677 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3678 &options);
3679
3680 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3681 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3682 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3683
3684 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3685
3686 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3687 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3688 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3689}
3690
3691TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3692 MediaSessionOptions options;
3693 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3694 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3695 &options);
3696
3697 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3698 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3699 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3700
3701 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3702 std::unique_ptr<SessionDescription> answer =
3703 f1_.CreateAnswer(offer.get(), options, nullptr);
3704
3705 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3706 "foo");
3707 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3708 "bar");
3709 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3710}
3711
3712TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3713 MediaSessionOptions options;
3714 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3715 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3716 &options);
3717
3718 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3719
3720 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3721 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3722 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3723
3724 std::unique_ptr<SessionDescription> answer =
3725 f1_.CreateAnswer(offer.get(), options, nullptr);
3726
3727 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3728 absl::nullopt);
3729 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3730 absl::nullopt);
3731 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3732 absl::nullopt);
3733}
3734
3735TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3736 MediaSessionOptions options;
3737 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3738 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3739 &options);
3740
3741 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3742 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3743 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3744
3745 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3746
3747 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3748 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3749 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3750
3751 std::unique_ptr<SessionDescription> answer =
3752 f1_.CreateAnswer(offer.get(), options, nullptr);
3753
3754 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3755 absl::nullopt);
3756 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3757 absl::nullopt);
3758 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3759 absl::nullopt);
3760}
3761
3762TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3763 MediaSessionOptions options;
3764 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3765 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3766 &options);
3767
3768 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3769 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3770 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3771
3772 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3773
3774 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3775 absl::nullopt;
3776 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3777 absl::nullopt;
3778 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3779 absl::nullopt;
3780
3781 std::unique_ptr<SessionDescription> answer =
3782 f1_.CreateAnswer(offer.get(), options, nullptr);
3783
3784 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3785 absl::nullopt);
3786 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3787 absl::nullopt);
3788 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3789 absl::nullopt);
3790}
3791
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003792// Create an offer with bundle enabled and verify the crypto parameters are
3793// the common set of the available cryptos.
3794TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3795 TestCryptoWithBundle(true);
3796}
3797
3798// Create an answer with bundle enabled and verify the crypto parameters are
3799// the common set of the available cryptos.
3800TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3801 TestCryptoWithBundle(false);
3802}
3803
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003804// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3805// DTLS is not enabled locally.
3806TEST_F(MediaSessionDescriptionFactoryTest,
3807 TestOfferDtlsSavpfWithoutDtlsFailed) {
3808 f1_.set_secure(SEC_ENABLED);
3809 f2_.set_secure(SEC_ENABLED);
3810 tdf1_.set_secure(SEC_DISABLED);
3811 tdf2_.set_secure(SEC_DISABLED);
3812
Steve Anton6fe1fba2018-12-11 10:15:23 -08003813 std::unique_ptr<SessionDescription> offer =
3814 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003815 ASSERT_TRUE(offer.get() != NULL);
3816 ContentInfo* offer_content = offer->GetContentByName("audio");
3817 ASSERT_TRUE(offer_content != NULL);
3818 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003819 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003820 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3821
Steve Anton6fe1fba2018-12-11 10:15:23 -08003822 std::unique_ptr<SessionDescription> answer =
3823 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003824 ASSERT_TRUE(answer != NULL);
3825 ContentInfo* answer_content = answer->GetContentByName("audio");
3826 ASSERT_TRUE(answer_content != NULL);
3827
3828 ASSERT_TRUE(answer_content->rejected);
3829}
3830
3831// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3832// UDP/TLS/RTP/SAVPF.
3833TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3834 f1_.set_secure(SEC_ENABLED);
3835 f2_.set_secure(SEC_ENABLED);
3836 tdf1_.set_secure(SEC_ENABLED);
3837 tdf2_.set_secure(SEC_ENABLED);
3838
Steve Anton6fe1fba2018-12-11 10:15:23 -08003839 std::unique_ptr<SessionDescription> offer =
3840 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003841 ASSERT_TRUE(offer.get() != NULL);
3842 ContentInfo* offer_content = offer->GetContentByName("audio");
3843 ASSERT_TRUE(offer_content != NULL);
3844 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003845 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003846 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3847
Steve Anton6fe1fba2018-12-11 10:15:23 -08003848 std::unique_ptr<SessionDescription> answer =
3849 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003850 ASSERT_TRUE(answer != NULL);
3851
3852 const ContentInfo* answer_content = answer->GetContentByName("audio");
3853 ASSERT_TRUE(answer_content != NULL);
3854 ASSERT_FALSE(answer_content->rejected);
3855
3856 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003857 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003858 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003859}
3860
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003861// Test that we include both SDES and DTLS in the offer, but only include SDES
3862// in the answer if DTLS isn't negotiated.
3863TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3864 f1_.set_secure(SEC_ENABLED);
3865 f2_.set_secure(SEC_ENABLED);
3866 tdf1_.set_secure(SEC_ENABLED);
3867 tdf2_.set_secure(SEC_DISABLED);
3868 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003869 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003870 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003871 const cricket::MediaContentDescription* audio_media_desc;
3872 const cricket::MediaContentDescription* video_media_desc;
3873 const cricket::TransportDescription* audio_trans_desc;
3874 const cricket::TransportDescription* video_trans_desc;
3875
3876 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003877 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003878 ASSERT_TRUE(offer.get() != NULL);
3879
Steve Antonb1c1de12017-12-21 15:14:30 -08003880 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003881 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003882 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003883 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003884 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003885 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3886
3887 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3888 ASSERT_TRUE(audio_trans_desc != NULL);
3889 video_trans_desc = offer->GetTransportDescriptionByName("video");
3890 ASSERT_TRUE(video_trans_desc != NULL);
3891 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3892 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3893
3894 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003895 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003896 ASSERT_TRUE(answer.get() != NULL);
3897
Steve Antonb1c1de12017-12-21 15:14:30 -08003898 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003899 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003900 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003901 ASSERT_TRUE(video_media_desc != NULL);
3902 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3903 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3904
3905 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3906 ASSERT_TRUE(audio_trans_desc != NULL);
3907 video_trans_desc = answer->GetTransportDescriptionByName("video");
3908 ASSERT_TRUE(video_trans_desc != NULL);
3909 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3910 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3911
3912 // Enable DTLS; the answer should now only have DTLS support.
3913 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003914 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003915 ASSERT_TRUE(answer.get() != NULL);
3916
Steve Antonb1c1de12017-12-21 15:14:30 -08003917 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003918 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003919 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003920 ASSERT_TRUE(video_media_desc != NULL);
3921 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3922 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003923 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3924 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003925
3926 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3927 ASSERT_TRUE(audio_trans_desc != NULL);
3928 video_trans_desc = answer->GetTransportDescriptionByName("video");
3929 ASSERT_TRUE(video_trans_desc != NULL);
3930 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3931 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003932
3933 // Try creating offer again. DTLS enabled now, crypto's should be empty
3934 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003935 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003936 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003937 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003938 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003939 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003940 ASSERT_TRUE(video_media_desc != NULL);
3941 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3942 EXPECT_TRUE(video_media_desc->cryptos().empty());
3943
3944 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3945 ASSERT_TRUE(audio_trans_desc != NULL);
3946 video_trans_desc = offer->GetTransportDescriptionByName("video");
3947 ASSERT_TRUE(video_trans_desc != NULL);
3948 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3949 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003950}
3951
3952// Test that an answer can't be created if cryptos are required but the offer is
3953// unsecure.
3954TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003955 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003956 f1_.set_secure(SEC_DISABLED);
3957 tdf1_.set_secure(SEC_DISABLED);
3958 f2_.set_secure(SEC_REQUIRED);
3959 tdf1_.set_secure(SEC_ENABLED);
3960
Steve Anton6fe1fba2018-12-11 10:15:23 -08003961 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003962 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003963 std::unique_ptr<SessionDescription> answer =
3964 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003965 EXPECT_TRUE(answer.get() == NULL);
3966}
3967
3968// Test that we accept a DTLS offer without SDES and create an appropriate
3969// answer.
3970TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3971 f1_.set_secure(SEC_DISABLED);
3972 f2_.set_secure(SEC_ENABLED);
3973 tdf1_.set_secure(SEC_ENABLED);
3974 tdf2_.set_secure(SEC_ENABLED);
3975 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003976 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3977 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3978 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003979
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003980 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003981 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003982 ASSERT_TRUE(offer.get() != NULL);
3983
3984 const AudioContentDescription* audio_offer =
3985 GetFirstAudioContentDescription(offer.get());
3986 ASSERT_TRUE(audio_offer->cryptos().empty());
3987 const VideoContentDescription* video_offer =
3988 GetFirstVideoContentDescription(offer.get());
3989 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003990 const RtpDataContentDescription* data_offer =
3991 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003992 ASSERT_TRUE(data_offer->cryptos().empty());
3993
3994 const cricket::TransportDescription* audio_offer_trans_desc =
3995 offer->GetTransportDescriptionByName("audio");
3996 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3997 const cricket::TransportDescription* video_offer_trans_desc =
3998 offer->GetTransportDescriptionByName("video");
3999 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
4000 const cricket::TransportDescription* data_offer_trans_desc =
4001 offer->GetTransportDescriptionByName("data");
4002 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
4003
4004 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004005 std::unique_ptr<SessionDescription> answer =
4006 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004007 ASSERT_TRUE(answer.get() != NULL);
4008
4009 const cricket::TransportDescription* audio_answer_trans_desc =
4010 answer->GetTransportDescriptionByName("audio");
4011 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
4012 const cricket::TransportDescription* video_answer_trans_desc =
4013 answer->GetTransportDescriptionByName("video");
4014 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
4015 const cricket::TransportDescription* data_answer_trans_desc =
4016 answer->GetTransportDescriptionByName("data");
4017 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
4018}
4019
4020// Verifies if vad_enabled option is set to false, CN codecs are not present in
4021// offer or answer.
4022TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
4023 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004024 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004025 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004026 ASSERT_TRUE(offer.get() != NULL);
4027 const ContentInfo* audio_content = offer->GetContentByName("audio");
4028 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
4029
4030 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08004031 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004032 ASSERT_TRUE(offer.get() != NULL);
4033 audio_content = offer->GetContentByName("audio");
4034 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08004035 std::unique_ptr<SessionDescription> answer =
4036 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004037 ASSERT_TRUE(answer.get() != NULL);
4038 audio_content = answer->GetContentByName("audio");
4039 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
4040}
deadbeef44f08192015-12-15 16:20:09 -08004041
zhihuang1c378ed2017-08-17 14:10:50 -07004042// Test that the generated MIDs match the existing offer.
4043TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08004044 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004045 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
4046 RtpTransceiverDirection::kRecvOnly, kActive,
4047 &opts);
4048 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
4049 RtpTransceiverDirection::kRecvOnly, kActive,
4050 &opts);
deadbeef44f08192015-12-15 16:20:09 -08004051 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004052 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
4053 RtpTransceiverDirection::kSendRecv, kActive,
4054 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004055 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004056 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08004057 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08004058 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07004059
deadbeef44f08192015-12-15 16:20:09 -08004060 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
4061 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
4062 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
4063 ASSERT_TRUE(audio_content != nullptr);
4064 ASSERT_TRUE(video_content != nullptr);
4065 ASSERT_TRUE(data_content != nullptr);
4066 EXPECT_EQ("audio_modified", audio_content->name);
4067 EXPECT_EQ("video_modified", video_content->name);
4068 EXPECT_EQ("data_modified", data_content->name);
4069}
zhihuangcf5b37c2016-05-05 11:44:35 -07004070
zhihuang1c378ed2017-08-17 14:10:50 -07004071// The following tests verify that the unified plan SDP is supported.
4072// Test that we can create an offer with multiple media sections of same media
4073// type.
4074TEST_F(MediaSessionDescriptionFactoryTest,
4075 CreateOfferWithMultipleAVMediaSections) {
4076 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004077 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4078 RtpTransceiverDirection::kSendRecv, kActive,
4079 &opts);
4080 AttachSenderToMediaDescriptionOptions(
4081 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004082
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004083 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4084 RtpTransceiverDirection::kSendRecv, kActive,
4085 &opts);
4086 AttachSenderToMediaDescriptionOptions(
4087 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004088
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004089 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4090 RtpTransceiverDirection::kSendRecv, kActive,
4091 &opts);
4092 AttachSenderToMediaDescriptionOptions(
4093 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004094
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004095 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4096 RtpTransceiverDirection::kSendRecv, kActive,
4097 &opts);
4098 AttachSenderToMediaDescriptionOptions(
4099 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004100 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004101 ASSERT_TRUE(offer);
4102
4103 ASSERT_EQ(4u, offer->contents().size());
4104 EXPECT_FALSE(offer->contents()[0].rejected);
4105 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004106 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004107 ASSERT_EQ(1u, acd->streams().size());
4108 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004109 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004110
4111 EXPECT_FALSE(offer->contents()[1].rejected);
4112 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004113 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004114 ASSERT_EQ(1u, vcd->streams().size());
4115 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004116 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004117
4118 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004119 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004120 ASSERT_EQ(1u, acd->streams().size());
4121 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004122 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004123
4124 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004125 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004126 ASSERT_EQ(1u, vcd->streams().size());
4127 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004128 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004129}
4130
4131// Test that we can create an answer with multiple media sections of same media
4132// type.
4133TEST_F(MediaSessionDescriptionFactoryTest,
4134 CreateAnswerWithMultipleAVMediaSections) {
4135 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004136 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4137 RtpTransceiverDirection::kSendRecv, kActive,
4138 &opts);
4139 AttachSenderToMediaDescriptionOptions(
4140 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004141
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004142 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4143 RtpTransceiverDirection::kSendRecv, kActive,
4144 &opts);
4145 AttachSenderToMediaDescriptionOptions(
4146 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004147
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004148 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4149 RtpTransceiverDirection::kSendRecv, kActive,
4150 &opts);
4151 AttachSenderToMediaDescriptionOptions(
4152 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004153
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004154 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4155 RtpTransceiverDirection::kSendRecv, kActive,
4156 &opts);
4157 AttachSenderToMediaDescriptionOptions(
4158 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004159
Steve Anton6fe1fba2018-12-11 10:15:23 -08004160 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004161 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004162 std::unique_ptr<SessionDescription> answer =
4163 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004164
4165 ASSERT_EQ(4u, answer->contents().size());
4166 EXPECT_FALSE(answer->contents()[0].rejected);
4167 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004168 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004169 ASSERT_EQ(1u, acd->streams().size());
4170 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004171 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004172
4173 EXPECT_FALSE(answer->contents()[1].rejected);
4174 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004175 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004176 ASSERT_EQ(1u, vcd->streams().size());
4177 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004178 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004179
4180 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004181 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004182 ASSERT_EQ(1u, acd->streams().size());
4183 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004184 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004185
4186 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004187 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004188 ASSERT_EQ(1u, vcd->streams().size());
4189 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004190 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004191}
4192
4193// Test that the media section will be rejected in offer if the corresponding
4194// MediaDescriptionOptions is stopped by the offerer.
4195TEST_F(MediaSessionDescriptionFactoryTest,
4196 CreateOfferWithMediaSectionStoppedByOfferer) {
4197 // Create an offer with two audio sections and one of them is stopped.
4198 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004199 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4200 RtpTransceiverDirection::kSendRecv, kActive,
4201 &offer_opts);
4202 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4203 RtpTransceiverDirection::kInactive, kStopped,
4204 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004205 std::unique_ptr<SessionDescription> offer =
4206 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004207 ASSERT_TRUE(offer);
4208 ASSERT_EQ(2u, offer->contents().size());
4209 EXPECT_FALSE(offer->contents()[0].rejected);
4210 EXPECT_TRUE(offer->contents()[1].rejected);
4211}
4212
4213// Test that the media section will be rejected in answer if the corresponding
4214// MediaDescriptionOptions is stopped by the offerer.
4215TEST_F(MediaSessionDescriptionFactoryTest,
4216 CreateAnswerWithMediaSectionStoppedByOfferer) {
4217 // Create an offer with two audio sections and one of them is stopped.
4218 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004219 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4220 RtpTransceiverDirection::kSendRecv, kActive,
4221 &offer_opts);
4222 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4223 RtpTransceiverDirection::kInactive, kStopped,
4224 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004225 std::unique_ptr<SessionDescription> offer =
4226 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004227 ASSERT_TRUE(offer);
4228 ASSERT_EQ(2u, offer->contents().size());
4229 EXPECT_FALSE(offer->contents()[0].rejected);
4230 EXPECT_TRUE(offer->contents()[1].rejected);
4231
4232 // Create an answer based on the offer.
4233 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004234 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4235 RtpTransceiverDirection::kSendRecv, kActive,
4236 &answer_opts);
4237 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4238 RtpTransceiverDirection::kSendRecv, kActive,
4239 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004240 std::unique_ptr<SessionDescription> answer =
4241 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004242 ASSERT_EQ(2u, answer->contents().size());
4243 EXPECT_FALSE(answer->contents()[0].rejected);
4244 EXPECT_TRUE(answer->contents()[1].rejected);
4245}
4246
4247// Test that the media section will be rejected in answer if the corresponding
4248// MediaDescriptionOptions is stopped by the answerer.
4249TEST_F(MediaSessionDescriptionFactoryTest,
4250 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4251 // Create an offer with two audio sections.
4252 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004253 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4254 RtpTransceiverDirection::kSendRecv, kActive,
4255 &offer_opts);
4256 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4257 RtpTransceiverDirection::kSendRecv, kActive,
4258 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004259 std::unique_ptr<SessionDescription> offer =
4260 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004261 ASSERT_TRUE(offer);
4262 ASSERT_EQ(2u, offer->contents().size());
4263 ASSERT_FALSE(offer->contents()[0].rejected);
4264 ASSERT_FALSE(offer->contents()[1].rejected);
4265
4266 // The answerer rejects one of the audio sections.
4267 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004268 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4269 RtpTransceiverDirection::kSendRecv, kActive,
4270 &answer_opts);
4271 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4272 RtpTransceiverDirection::kInactive, kStopped,
4273 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004274 std::unique_ptr<SessionDescription> answer =
4275 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004276 ASSERT_EQ(2u, answer->contents().size());
4277 EXPECT_FALSE(answer->contents()[0].rejected);
4278 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004279
4280 // The TransportInfo of the rejected m= section is expected to be added in the
4281 // answer.
4282 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004283}
4284
4285// Test the generated media sections has the same order of the
4286// corresponding MediaDescriptionOptions.
4287TEST_F(MediaSessionDescriptionFactoryTest,
4288 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4289 MediaSessionOptions opts;
4290 // This tests put video section first because normally audio comes first by
4291 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004292 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4293 RtpTransceiverDirection::kSendRecv, kActive,
4294 &opts);
4295 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4296 RtpTransceiverDirection::kSendRecv, kActive,
4297 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004298 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004299
4300 ASSERT_TRUE(offer);
4301 ASSERT_EQ(2u, offer->contents().size());
4302 EXPECT_EQ("video", offer->contents()[0].name);
4303 EXPECT_EQ("audio", offer->contents()[1].name);
4304}
4305
4306// Test that different media sections using the same codec have same payload
4307// type.
4308TEST_F(MediaSessionDescriptionFactoryTest,
4309 PayloadTypesSharedByMediaSectionsOfSameType) {
4310 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004311 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4312 RtpTransceiverDirection::kSendRecv, kActive,
4313 &opts);
4314 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4315 RtpTransceiverDirection::kSendRecv, kActive,
4316 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004317 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004318 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004319 ASSERT_TRUE(offer);
4320 ASSERT_EQ(2u, offer->contents().size());
4321 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004322 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004323 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004324 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004325 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4326 ASSERT_EQ(2u, vcd1->codecs().size());
4327 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4328 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4329 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4330 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4331
4332 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004333 std::unique_ptr<SessionDescription> answer =
4334 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004335 ASSERT_TRUE(answer);
4336 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004337 vcd1 = answer->contents()[0].media_description()->as_video();
4338 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004339 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4340 ASSERT_EQ(1u, vcd1->codecs().size());
4341 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4342 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4343}
4344
4345// Test that the codec preference order per media section is respected in
4346// subsequent offer.
4347TEST_F(MediaSessionDescriptionFactoryTest,
4348 CreateOfferRespectsCodecPreferenceOrder) {
4349 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004350 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4351 RtpTransceiverDirection::kSendRecv, kActive,
4352 &opts);
4353 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4354 RtpTransceiverDirection::kSendRecv, kActive,
4355 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004356 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004357 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004358 ASSERT_TRUE(offer);
4359 ASSERT_EQ(2u, offer->contents().size());
4360 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004361 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004362 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004363 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004364 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4365 EXPECT_EQ(video_codecs, vcd1->codecs());
4366 EXPECT_EQ(video_codecs, vcd2->codecs());
4367
4368 // Change the codec preference of the first video section and create a
4369 // follow-up offer.
4370 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4371 vcd1->set_codecs(video_codecs_reverse);
4372 std::unique_ptr<SessionDescription> updated_offer(
4373 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004374 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4375 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004376 // The video codec preference order should be respected.
4377 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4378 EXPECT_EQ(video_codecs, vcd2->codecs());
4379}
4380
4381// Test that the codec preference order per media section is respected in
4382// the answer.
4383TEST_F(MediaSessionDescriptionFactoryTest,
4384 CreateAnswerRespectsCodecPreferenceOrder) {
4385 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004386 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4387 RtpTransceiverDirection::kSendRecv, kActive,
4388 &opts);
4389 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4390 RtpTransceiverDirection::kSendRecv, kActive,
4391 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004392 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004393 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004394 ASSERT_TRUE(offer);
4395 ASSERT_EQ(2u, offer->contents().size());
4396 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004397 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004398 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004399 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004400 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4401 EXPECT_EQ(video_codecs, vcd1->codecs());
4402 EXPECT_EQ(video_codecs, vcd2->codecs());
4403
4404 // Change the codec preference of the first video section and create an
4405 // answer.
4406 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4407 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004408 std::unique_ptr<SessionDescription> answer =
4409 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004410 vcd1 = answer->contents()[0].media_description()->as_video();
4411 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004412 // The video codec preference order should be respected.
4413 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4414 EXPECT_EQ(video_codecs, vcd2->codecs());
4415}
4416
Zhi Huang6f367472017-11-22 13:20:02 -08004417// Test that when creating an answer, the codecs use local parameters instead of
4418// the remote ones.
4419TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4420 const std::string audio_param_name = "audio_param";
4421 const std::string audio_value1 = "audio_v1";
4422 const std::string audio_value2 = "audio_v2";
4423 const std::string video_param_name = "video_param";
4424 const std::string video_value1 = "video_v1";
4425 const std::string video_value2 = "video_v2";
4426
4427 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4428 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4429 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4430 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4431
4432 // Set the parameters for codecs.
4433 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4434 video_codecs1[0].SetParam(video_param_name, video_value1);
4435 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4436 video_codecs2[0].SetParam(video_param_name, video_value2);
4437
4438 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004439 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004440 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004441 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004442
4443 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004444 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4445 RtpTransceiverDirection::kSendRecv, kActive,
4446 &opts);
4447 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4448 RtpTransceiverDirection::kSendRecv, kActive,
4449 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004450
Steve Anton6fe1fba2018-12-11 10:15:23 -08004451 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004452 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004453 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4454 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004455 std::string value;
4456 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4457 EXPECT_EQ(audio_value1, value);
4458 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4459 EXPECT_EQ(video_value1, value);
4460
Steve Anton6fe1fba2018-12-11 10:15:23 -08004461 std::unique_ptr<SessionDescription> answer =
4462 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004463 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004464 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4465 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004466 // Use the parameters from the local codecs.
4467 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4468 EXPECT_EQ(audio_value2, value);
4469 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4470 EXPECT_EQ(video_value2, value);
4471}
4472
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004473// Test that matching packetization-mode is part of the criteria for matching
4474// H264 codecs (in addition to profile-level-id). Previously, this was not the
4475// case, so the first H264 codec with the same profile-level-id would match and
4476// the payload type in the answer would be incorrect.
4477// This is a regression test for bugs.webrtc.org/8808
4478TEST_F(MediaSessionDescriptionFactoryTest,
4479 H264MatchCriteriaIncludesPacketizationMode) {
4480 // Create two H264 codecs with the same profile level ID and different
4481 // packetization modes.
4482 VideoCodec h264_pm0(96, "H264");
4483 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4484 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4485 VideoCodec h264_pm1(97, "H264");
4486 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4487 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4488
4489 // Offerer will send both codecs, answerer should choose the one with matching
4490 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004491 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4492 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004493
4494 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004495 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4496 RtpTransceiverDirection::kSendRecv, kActive,
4497 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004498
Steve Anton6fe1fba2018-12-11 10:15:23 -08004499 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004500 ASSERT_TRUE(offer);
4501
Steve Anton6fe1fba2018-12-11 10:15:23 -08004502 std::unique_ptr<SessionDescription> answer =
4503 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004504 ASSERT_TRUE(answer);
4505
4506 // Answer should have one negotiated codec with packetization-mode=1 using the
4507 // offered payload type.
4508 ASSERT_EQ(1u, answer->contents().size());
4509 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4510 ASSERT_EQ(1u, answer_vcd->codecs().size());
4511 auto answer_codec = answer_vcd->codecs()[0];
4512 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4513}
4514
zhihuangcf5b37c2016-05-05 11:44:35 -07004515class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4516 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004517 MediaProtocolTest()
4518 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004519 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4520 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004521 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4522 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004523 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004524 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4525 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004526 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4527 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004528 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004529 f1_.set_secure(SEC_ENABLED);
4530 f2_.set_secure(SEC_ENABLED);
4531 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004532 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004533 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004534 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004535 tdf1_.set_secure(SEC_ENABLED);
4536 tdf2_.set_secure(SEC_ENABLED);
4537 }
4538
4539 protected:
4540 MediaSessionDescriptionFactory f1_;
4541 MediaSessionDescriptionFactory f2_;
4542 TransportDescriptionFactory tdf1_;
4543 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004544 UniqueRandomIdGenerator ssrc_generator1;
4545 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004546};
4547
4548TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4549 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004550 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004551 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004552 ASSERT_TRUE(offer.get() != nullptr);
4553 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004554 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004555 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004556 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004557 std::unique_ptr<SessionDescription> answer =
4558 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004559 const ContentInfo* ac = answer->GetContentByName("audio");
4560 const ContentInfo* vc = answer->GetContentByName("video");
4561 ASSERT_TRUE(ac != nullptr);
4562 ASSERT_TRUE(vc != nullptr);
4563 EXPECT_FALSE(ac->rejected); // the offer is accepted
4564 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004565 const AudioContentDescription* acd = ac->media_description()->as_audio();
4566 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004567 EXPECT_EQ(GetParam(), acd->protocol());
4568 EXPECT_EQ(GetParam(), vcd->protocol());
4569}
4570
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004571INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4572 MediaProtocolTest,
4573 ::testing::ValuesIn(kMediaProtocols));
4574INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4575 MediaProtocolTest,
4576 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004577
4578TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4579 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004580 UniqueRandomIdGenerator ssrc_generator;
4581 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004582 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4583 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4584
4585 // The merged list of codecs should contain any send codecs that are also
4586 // nominally in the recieve codecs list. Payload types should be picked from
4587 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4588 // (set to 1). This equals what happens when the send codecs are used in an
4589 // offer and the receive codecs are used in the following answer.
4590 const std::vector<AudioCodec> sendrecv_codecs =
4591 MAKE_VECTOR(kAudioCodecsAnswer);
4592 const std::vector<AudioCodec> no_codecs;
4593
4594 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4595 << "Please don't change shared test data!";
4596 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4597 << "Please don't change shared test data!";
4598 // Alter iLBC send codec to have zero channels, to test that that is handled
4599 // properly.
4600 send_codecs[1].channels = 0;
4601
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004602 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004603 // are handled properly.
4604 recv_codecs[2].name = "ilbc";
4605
4606 // Test proper merge
4607 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004608 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4609 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4610 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004611
4612 // Test empty send codecs list
4613 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004614 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4615 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4616 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004617
4618 // Test empty recv codecs list
4619 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004620 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4621 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4622 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004623
4624 // Test all empty codec lists
4625 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004626 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4627 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4628 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004629}
4630
4631namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004632// Compare the two vectors of codecs ignoring the payload type.
4633template <class Codec>
4634bool CodecsMatch(const std::vector<Codec>& codecs1,
4635 const std::vector<Codec>& codecs2) {
4636 if (codecs1.size() != codecs2.size()) {
4637 return false;
4638 }
4639
4640 for (size_t i = 0; i < codecs1.size(); ++i) {
4641 if (!codecs1[i].Matches(codecs2[i])) {
4642 return false;
4643 }
4644 }
4645 return true;
4646}
4647
Steve Anton4e70a722017-11-28 14:57:10 -08004648void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004649 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004650 UniqueRandomIdGenerator ssrc_generator;
4651 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004652 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4653 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4654 const std::vector<AudioCodec> sendrecv_codecs =
4655 MAKE_VECTOR(kAudioCodecsAnswer);
4656 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004657
4658 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004659 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4660 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004661
Steve Anton4e70a722017-11-28 14:57:10 -08004662 if (direction == RtpTransceiverDirection::kSendRecv ||
4663 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004664 AttachSenderToMediaDescriptionOptions(
4665 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004666 }
ossu075af922016-06-14 03:29:38 -07004667
Steve Anton6fe1fba2018-12-11 10:15:23 -08004668 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004669 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004670 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004671
4672 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004673 // that the codecs put in are right. This happens when we neither want to
4674 // send nor receive audio. The checks are still in place if at some point
4675 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004676 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004677 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004678 // sendrecv and inactive should both present lists as if the channel was
4679 // to be used for sending and receiving. Inactive essentially means it
4680 // might eventually be used anything, but we don't know more at this
4681 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004682 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004683 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004684 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004685 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004686 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004687 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004688 }
4689 }
4690}
4691
4692static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004693 AudioCodec(0, "codec0", 16000, -1, 1),
4694 AudioCodec(1, "codec1", 8000, 13300, 1),
4695 AudioCodec(2, "codec2", 8000, 64000, 1),
4696 AudioCodec(3, "codec3", 8000, 64000, 1),
4697 AudioCodec(4, "codec4", 8000, 0, 2),
4698 AudioCodec(5, "codec5", 32000, 0, 1),
4699 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004700
zhihuang1c378ed2017-08-17 14:10:50 -07004701/* The codecs groups below are chosen as per the matrix below. The objective
4702 * is to have different sets of codecs in the inputs, to get unique sets of
4703 * codecs after negotiation, depending on offer and answer communication
4704 * directions. One-way directions in the offer should either result in the
4705 * opposite direction in the answer, or an inactive answer. Regardless, the
4706 * choice of codecs should be as if the answer contained the opposite
4707 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004708 *
4709 * | Offer | Answer | Result
4710 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4711 * 0 | x - - | - x - | x - - - -
4712 * 1 | x x x | - x - | x - - x -
4713 * 2 | - x - | x - - | - x - - -
4714 * 3 | x x x | x - - | - x x - -
4715 * 4 | - x - | x x x | - x - - -
4716 * 5 | x - - | x x x | x - - - -
4717 * 6 | x x x | x x x | x x x x x
4718 */
4719// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004720static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4721static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004722// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4723// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004724static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4725static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004726// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004727static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4728static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4729static const int kResultSendrecv_SendCodecs[] = {3, 6};
4730static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4731static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004732
4733template <typename T, int IDXS>
4734std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4735 std::vector<T> out;
4736 out.reserve(IDXS);
4737 for (int idx : indices)
4738 out.push_back(array[idx]);
4739
4740 return out;
4741}
4742
Steve Anton4e70a722017-11-28 14:57:10 -08004743void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4744 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004745 bool add_legacy_stream) {
4746 TransportDescriptionFactory offer_tdf;
4747 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004748 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4749 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4750 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004751 offer_factory.set_audio_codecs(
4752 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4753 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4754 answer_factory.set_audio_codecs(
4755 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4756 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4757
ossu075af922016-06-14 03:29:38 -07004758 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004759 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4760 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004761
Steve Anton4e70a722017-11-28 14:57:10 -08004762 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004763 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4764 kAudioTrack1, {kMediaStream1}, 1,
4765 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004766 }
4767
Steve Anton6fe1fba2018-12-11 10:15:23 -08004768 std::unique_ptr<SessionDescription> offer =
4769 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004770 ASSERT_TRUE(offer.get() != NULL);
4771
4772 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004773 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4774 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004775
Steve Anton4e70a722017-11-28 14:57:10 -08004776 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004777 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4778 kAudioTrack1, {kMediaStream1}, 1,
4779 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004780 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004781 std::unique_ptr<SessionDescription> answer =
4782 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004783 const ContentInfo* ac = answer->GetContentByName("audio");
4784
zhihuang1c378ed2017-08-17 14:10:50 -07004785 // If the factory didn't add any audio content to the answer, we cannot
4786 // check that the codecs put in are right. This happens when we neither want
4787 // to send nor receive audio. The checks are still in place if at some point
4788 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004789 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004790 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4791 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004792
ossu075af922016-06-14 03:29:38 -07004793 std::vector<AudioCodec> target_codecs;
4794 // For offers with sendrecv or inactive, we should never reply with more
4795 // codecs than offered, with these codec sets.
4796 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004797 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004798 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4799 kResultSendrecv_SendrecvCodecs);
4800 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004801 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004802 target_codecs =
4803 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004804 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004805 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004806 target_codecs =
4807 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004808 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004809 case RtpTransceiverDirection::kSendRecv:
4810 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004811 target_codecs =
4812 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004813 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004814 target_codecs =
4815 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004816 } else {
4817 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4818 kResultSendrecv_SendrecvCodecs);
4819 }
4820 break;
Markus Handell45c104b2020-03-11 10:51:13 +01004821 default:
4822 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004823 }
4824
zhihuang1c378ed2017-08-17 14:10:50 -07004825 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004826 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004827 bool first = true;
4828 os << "{";
4829 for (const auto& c : codecs) {
4830 os << (first ? " " : ", ") << c.id;
4831 first = false;
4832 }
4833 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004834 return os.Release();
ossu075af922016-06-14 03:29:38 -07004835 };
4836
4837 EXPECT_TRUE(acd->codecs() == target_codecs)
4838 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004839 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4840 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004841 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004842 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4843 << "; got: "
4844 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004845 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004846 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004847 << "Only inactive offers are allowed to not generate any audio "
4848 "content";
ossu075af922016-06-14 03:29:38 -07004849 }
4850}
brandtr03d5fb12016-11-22 03:37:59 -08004851
4852} // namespace
ossu075af922016-06-14 03:29:38 -07004853
4854class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004855 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004856
4857TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004858 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004859}
4860
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004861INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4862 AudioCodecsOfferTest,
4863 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4864 RtpTransceiverDirection::kRecvOnly,
4865 RtpTransceiverDirection::kSendRecv,
4866 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004867
4868class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004869 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4870 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004871 bool>> {};
ossu075af922016-06-14 03:29:38 -07004872
4873TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004874 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4875 ::testing::get<1>(GetParam()),
4876 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004877}
4878
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004879INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004880 MediaSessionDescriptionFactoryTest,
4881 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004882 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4883 RtpTransceiverDirection::kRecvOnly,
4884 RtpTransceiverDirection::kSendRecv,
4885 RtpTransceiverDirection::kInactive),
4886 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4887 RtpTransceiverDirection::kRecvOnly,
4888 RtpTransceiverDirection::kSendRecv,
4889 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004890 ::testing::Bool()));