blob: 5a9002bc4ec4fdc69c06aeda32403dca961f0609 [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));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 } else {
545 EXPECT_TRUE(ti_audio == NULL);
546 }
547 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000548 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700550 auto media_desc_options_it =
551 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 if (options.bundle_enabled) {
553 EXPECT_EQ(ti_audio->description.ice_ufrag,
554 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200555 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 } else {
557 if (has_current_desc) {
558 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
559 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
560 } else {
561 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
562 ti_video->description.ice_ufrag.size());
563 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
564 ti_video->description.ice_pwd.size());
565 }
566 }
zhihuang1c378ed2017-08-17 14:10:50 -0700567 EXPECT_EQ(
568 media_desc_options_it->transport_options.enable_ice_renomination,
569 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570 } else {
571 EXPECT_TRUE(ti_video == NULL);
572 }
573 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
574 if (options.has_data()) {
575 EXPECT_TRUE(ti_data != NULL);
576 if (options.bundle_enabled) {
577 EXPECT_EQ(ti_audio->description.ice_ufrag,
578 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200579 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 } else {
581 if (has_current_desc) {
582 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
583 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
584 } else {
585 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
586 ti_data->description.ice_ufrag.size());
587 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
588 ti_data->description.ice_pwd.size());
589 }
590 }
zhihuang1c378ed2017-08-17 14:10:50 -0700591 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700592 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700593 EXPECT_EQ(
594 media_desc_options_it->transport_options.enable_ice_renomination,
595 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700596
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700598 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 }
600 }
601
602 void TestCryptoWithBundle(bool offer) {
603 f1_.set_secure(SEC_ENABLED);
604 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800605 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
606 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
607 &options);
kwiberg31022942016-03-11 14:18:21 -0800608 std::unique_ptr<SessionDescription> ref_desc;
609 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610 if (offer) {
611 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800612 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800614 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 } else {
616 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800617 ref_desc = f1_.CreateOffer(options, NULL);
618 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800620 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800622 desc->GetContentDescriptionByName("audio");
623 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800625 desc->GetContentDescriptionByName("video");
626 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
628 video_media_desc->cryptos()));
629 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800630 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 audio_media_desc->cryptos()[0].cipher_suite);
632
633 // Verify the selected crypto is one from the reference audio
634 // media content.
635 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800636 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000637 bool found = false;
638 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
639 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200640 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 found = true;
642 break;
643 }
644 }
645 EXPECT_TRUE(found);
646 }
647
648 // This test that the audio and video media direction is set to
649 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700650 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800652 RtpTransceiverDirection direction_in_offer,
653 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700654 MediaSessionOptions offer_opts;
655 AddAudioVideoSections(direction_in_offer, &offer_opts);
656
Steve Anton6fe1fba2018-12-11 10:15:23 -0800657 std::unique_ptr<SessionDescription> offer =
658 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700660 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700662 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664
zhihuang1c378ed2017-08-17 14:10:50 -0700665 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800666 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800667 std::unique_ptr<SessionDescription> answer =
668 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669 const AudioContentDescription* acd_answer =
670 GetFirstAudioContentDescription(answer.get());
671 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
672 const VideoContentDescription* vcd_answer =
673 GetFirstVideoContentDescription(answer.get());
674 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
675 }
676
677 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800678 RTC_DCHECK(content);
679 RTC_CHECK(content->media_description());
680 const cricket::AudioContentDescription* audio_desc =
681 content->media_description()->as_audio();
682 RTC_CHECK(audio_desc);
683 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
684 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800686 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 }
688 return true;
689 }
690
jbauchcb560652016-08-04 05:20:32 -0700691 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
692 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800693 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700694 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700695
jbauchcb560652016-08-04 05:20:32 -0700696 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800697 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700698 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700699
jbauchcb560652016-08-04 05:20:32 -0700700 f1_.set_secure(SEC_ENABLED);
701 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800702 std::unique_ptr<SessionDescription> offer =
703 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700704 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +0200705 if (gcm_offer && gcm_answer) {
706 for (cricket::ContentInfo& content : offer->contents()) {
707 auto cryptos = content.media_description()->cryptos();
708 PreferGcmCryptoParameters(&cryptos);
709 content.media_description()->set_cryptos(cryptos);
710 }
711 }
Steve Anton6fe1fba2018-12-11 10:15:23 -0800712 std::unique_ptr<SessionDescription> answer =
713 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700714 const ContentInfo* ac = answer->GetContentByName("audio");
715 const ContentInfo* vc = answer->GetContentByName("video");
716 ASSERT_TRUE(ac != NULL);
717 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800718 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
719 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800720 const AudioContentDescription* acd = ac->media_description()->as_audio();
721 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700722 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800723 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700724 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700725 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700726 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
727 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700728 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700729 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700730 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700731 }
732 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800733 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200734 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
735 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700736 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700737 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700738 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700739 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700740 }
Steve Antone38a5a12018-11-21 16:05:15 -0800741 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700742 }
743
Johannes Kronce8e8672019-02-22 13:06:44 +0100744 void TestTransportSequenceNumberNegotiation(
745 const cricket::RtpHeaderExtensions& local,
746 const cricket::RtpHeaderExtensions& offered,
747 const cricket::RtpHeaderExtensions& expectedAnswer) {
748 MediaSessionOptions opts;
749 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +0200750 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100751 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
752 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +0200753 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100754 std::unique_ptr<SessionDescription> answer =
755 f2_.CreateAnswer(offer.get(), opts, NULL);
756
757 EXPECT_EQ(
758 expectedAnswer,
759 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
760 EXPECT_EQ(
761 expectedAnswer,
762 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
763 }
764
Markus Handell755c65d2020-06-24 01:06:10 +0200765 std::vector<webrtc::RtpHeaderExtensionCapability>
766 HeaderExtensionCapabilitiesFromRtpExtensions(
767 cricket::RtpHeaderExtensions extensions) {
768 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
769 for (const auto& extension : extensions) {
770 webrtc::RtpHeaderExtensionCapability capability(
771 extension.uri, extension.id,
772 webrtc::RtpTransceiverDirection::kSendRecv);
773 capabilities.push_back(capability);
774 }
775 return capabilities;
776 }
777
778 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
779 cricket::RtpHeaderExtensions video_exts,
780 MediaSessionOptions* opts) {
781 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
782 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
783 for (auto& entry : opts->media_description_options) {
784 switch (entry.type) {
785 case MEDIA_TYPE_AUDIO:
786 entry.header_extensions = audio_caps;
787 break;
788 case MEDIA_TYPE_VIDEO:
789 entry.header_extensions = video_caps;
790 break;
791 default:
792 break;
793 }
794 }
795 }
796
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800798 UniqueRandomIdGenerator ssrc_generator1;
799 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 MediaSessionDescriptionFactory f1_;
801 MediaSessionDescriptionFactory f2_;
802 TransportDescriptionFactory tdf1_;
803 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804};
805
806// Create a typical audio offer, and ensure it matches what we expect.
807TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
808 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800809 std::unique_ptr<SessionDescription> offer =
810 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 ASSERT_TRUE(offer.get() != NULL);
812 const ContentInfo* ac = offer->GetContentByName("audio");
813 const ContentInfo* vc = offer->GetContentByName("video");
814 ASSERT_TRUE(ac != NULL);
815 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800816 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800817 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700819 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700820 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
822 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700823 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800824 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825}
826
827// Create a typical video offer, and ensure it matches what we expect.
828TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
829 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800830 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800832 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 ASSERT_TRUE(offer.get() != NULL);
834 const ContentInfo* ac = offer->GetContentByName("audio");
835 const ContentInfo* vc = offer->GetContentByName("video");
836 ASSERT_TRUE(ac != NULL);
837 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800838 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
839 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800840 const AudioContentDescription* acd = ac->media_description()->as_audio();
841 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700843 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700844 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
846 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700847 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800848 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200850 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700851 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
853 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700854 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800855 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856}
857
858// Test creating an offer with bundle where the Codecs have the same dynamic
859// RTP playlod type. The test verifies that the offer don't contain the
860// duplicate RTP payload types.
861TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200862 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700863 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200864 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
866 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
867
868 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800869 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
870 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800872 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873 const VideoContentDescription* vcd =
874 GetFirstVideoContentDescription(offer.get());
875 const AudioContentDescription* acd =
876 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200877 const RtpDataContentDescription* dcd =
878 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879 ASSERT_TRUE(NULL != vcd);
880 ASSERT_TRUE(NULL != acd);
881 ASSERT_TRUE(NULL != dcd);
882 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
883 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
884 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
885 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
886 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
887 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
888}
889
zhihuang1c378ed2017-08-17 14:10:50 -0700890// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891// after an audio only session has been negotiated.
892TEST_F(MediaSessionDescriptionFactoryTest,
893 TestCreateUpdatedVideoOfferWithBundle) {
894 f1_.set_secure(SEC_ENABLED);
895 f2_.set_secure(SEC_ENABLED);
896 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800897 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
898 RtpTransceiverDirection::kRecvOnly, kActive,
899 &opts);
900 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
901 RtpTransceiverDirection::kInactive, kStopped,
902 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903 opts.data_channel_type = cricket::DCT_NONE;
904 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800905 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
906 std::unique_ptr<SessionDescription> answer =
907 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908
909 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800910 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
911 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
912 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000913 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800914 std::unique_ptr<SessionDescription> updated_offer(
915 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916
917 const AudioContentDescription* acd =
918 GetFirstAudioContentDescription(updated_offer.get());
919 const VideoContentDescription* vcd =
920 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200921 const RtpDataContentDescription* dcd =
922 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923 EXPECT_TRUE(NULL != vcd);
924 EXPECT_TRUE(NULL != acd);
925 EXPECT_TRUE(NULL != dcd);
926
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700927 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800928 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700929 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800930 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700931 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800932 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000933}
deadbeef44f08192015-12-15 16:20:09 -0800934
wu@webrtc.org78187522013-10-07 23:32:02 +0000935// Create a RTP data offer, and ensure it matches what we expect.
936TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000937 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800938 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
939 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800941 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000942 ASSERT_TRUE(offer.get() != NULL);
943 const ContentInfo* ac = offer->GetContentByName("audio");
944 const ContentInfo* dc = offer->GetContentByName("data");
945 ASSERT_TRUE(ac != NULL);
946 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800947 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
948 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800949 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200950 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700952 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700953 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000954 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
955 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700956 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800957 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000958 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200959 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700960 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
Philipp Hanckeafee7082020-10-22 11:55:58 +0200961 EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200962 dcd->bandwidth()); // default bandwidth (auto)
963 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700964 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800965 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000966}
967
wu@webrtc.org78187522013-10-07 23:32:02 +0000968// Create an SCTP data offer with bundle without error.
969TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
970 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000971 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800972 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000973 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800974 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000975 EXPECT_TRUE(offer.get() != NULL);
976 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000977 auto dcd = GetFirstSctpDataContentDescription(offer.get());
978 ASSERT_TRUE(dcd);
979 // Since this transport is insecure, the protocol should be "SCTP".
980 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
981}
982
983// Create an SCTP data offer with bundle without error.
984TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
985 MediaSessionOptions opts;
986 opts.bundle_enabled = true;
987 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
988 f1_.set_secure(SEC_ENABLED);
989 tdf1_.set_secure(SEC_ENABLED);
990 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
991 EXPECT_TRUE(offer.get() != NULL);
992 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
993 auto dcd = GetFirstSctpDataContentDescription(offer.get());
994 ASSERT_TRUE(dcd);
995 // The protocol should now be "UDP/DTLS/SCTP"
996 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000997}
998
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000999// Test creating an sctp data channel from an already generated offer.
1000TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
1001 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001002 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -08001003 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001004 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001005 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001006 ASSERT_TRUE(offer1.get() != NULL);
1007 const ContentInfo* data = offer1->GetContentByName("data");
1008 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001009 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001010
1011 // Now set data_channel_type to 'none' (default) and make sure that the
1012 // datachannel type that gets generated from the previous offer, is of the
1013 // same type.
1014 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -08001015 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001016 f1_.CreateOffer(opts, offer1.get()));
1017 data = offer2->GetContentByName("data");
1018 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001019 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001020}
1021
Steve Anton2bed3972019-01-04 17:04:30 -08001022// Test that if BUNDLE is enabled and all media sections are rejected then the
1023// BUNDLE group is not present in the re-offer.
1024TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
1025 MediaSessionOptions opts;
1026 opts.bundle_enabled = true;
1027 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1028 RtpTransceiverDirection::kSendRecv, kActive,
1029 &opts);
1030 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1031
1032 opts.media_description_options[0].stopped = true;
1033 std::unique_ptr<SessionDescription> reoffer =
1034 f1_.CreateOffer(opts, offer.get());
1035
1036 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1037}
1038
1039// Test that if BUNDLE is enabled and the remote re-offer does not include a
1040// BUNDLE group since all media sections are rejected, then the re-answer also
1041// does not include a BUNDLE group.
1042TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
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 std::unique_ptr<SessionDescription> answer =
1050 f2_.CreateAnswer(offer.get(), opts, nullptr);
1051
1052 opts.media_description_options[0].stopped = true;
1053 std::unique_ptr<SessionDescription> reoffer =
1054 f1_.CreateOffer(opts, offer.get());
1055 std::unique_ptr<SessionDescription> reanswer =
1056 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1057
1058 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1059}
1060
1061// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1062// was rejected then the new offerer-tagged media section is the non-rejected
1063// media section.
1064TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1065 MediaSessionOptions opts;
1066 opts.bundle_enabled = true;
1067 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1068 RtpTransceiverDirection::kSendRecv, kActive,
1069 &opts);
1070 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1071
1072 // Reject the audio m= section and add a video m= section.
1073 opts.media_description_options[0].stopped = true;
1074 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1075 RtpTransceiverDirection::kSendRecv, kActive,
1076 &opts);
1077 std::unique_ptr<SessionDescription> reoffer =
1078 f1_.CreateOffer(opts, offer.get());
1079
1080 const cricket::ContentGroup* bundle_group =
1081 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1082 ASSERT_TRUE(bundle_group);
1083 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1084 EXPECT_TRUE(bundle_group->HasContentName("video"));
1085}
1086
1087// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1088// was rejected and a new media section is added, then the re-answer BUNDLE
1089// group will contain only the non-rejected media section.
1090TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1091 MediaSessionOptions opts;
1092 opts.bundle_enabled = true;
1093 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1094 RtpTransceiverDirection::kSendRecv, kActive,
1095 &opts);
1096 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1097 std::unique_ptr<SessionDescription> answer =
1098 f2_.CreateAnswer(offer.get(), opts, nullptr);
1099
1100 // Reject the audio m= section and add a video m= section.
1101 opts.media_description_options[0].stopped = true;
1102 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1103 RtpTransceiverDirection::kSendRecv, kActive,
1104 &opts);
1105 std::unique_ptr<SessionDescription> reoffer =
1106 f1_.CreateOffer(opts, offer.get());
1107 std::unique_ptr<SessionDescription> reanswer =
1108 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1109
1110 const cricket::ContentGroup* bundle_group =
1111 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1112 ASSERT_TRUE(bundle_group);
1113 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1114 EXPECT_TRUE(bundle_group->HasContentName("video"));
1115}
1116
1117// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1118// and there is still a non-rejected media section that was in the initial
1119// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1120// media section.
1121TEST_F(MediaSessionDescriptionFactoryTest,
1122 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1123 MediaSessionOptions opts;
1124 opts.bundle_enabled = true;
1125 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1126 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1127 std::unique_ptr<SessionDescription> answer =
1128 f2_.CreateAnswer(offer.get(), opts, nullptr);
1129
1130 // Reject the audio m= section.
1131 opts.media_description_options[0].stopped = true;
1132 std::unique_ptr<SessionDescription> reoffer =
1133 f1_.CreateOffer(opts, offer.get());
1134
1135 const TransportDescription* offer_tagged =
1136 offer->GetTransportDescriptionByName("audio");
1137 ASSERT_TRUE(offer_tagged);
1138 const TransportDescription* reoffer_tagged =
1139 reoffer->GetTransportDescriptionByName("video");
1140 ASSERT_TRUE(reoffer_tagged);
1141 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1142 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1143}
1144
1145// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1146// and there is still a non-rejected media section that was in the initial
1147// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1148// media section.
1149TEST_F(MediaSessionDescriptionFactoryTest,
1150 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1151 MediaSessionOptions opts;
1152 opts.bundle_enabled = true;
1153 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1154 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1155 std::unique_ptr<SessionDescription> answer =
1156 f2_.CreateAnswer(offer.get(), opts, nullptr);
1157
1158 // Reject the audio m= section.
1159 opts.media_description_options[0].stopped = true;
1160 std::unique_ptr<SessionDescription> reoffer =
1161 f1_.CreateOffer(opts, offer.get());
1162 std::unique_ptr<SessionDescription> reanswer =
1163 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1164
1165 const TransportDescription* answer_tagged =
1166 answer->GetTransportDescriptionByName("audio");
1167 ASSERT_TRUE(answer_tagged);
1168 const TransportDescription* reanswer_tagged =
1169 reanswer->GetTransportDescriptionByName("video");
1170 ASSERT_TRUE(reanswer_tagged);
1171 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1172 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1173}
1174
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175// Create an audio, video offer without legacy StreamParams.
1176TEST_F(MediaSessionDescriptionFactoryTest,
1177 TestCreateOfferWithoutLegacyStreams) {
1178 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001179 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001180 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181 ASSERT_TRUE(offer.get() != NULL);
1182 const ContentInfo* ac = offer->GetContentByName("audio");
1183 const ContentInfo* vc = offer->GetContentByName("video");
1184 ASSERT_TRUE(ac != NULL);
1185 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001186 const AudioContentDescription* acd = ac->media_description()->as_audio();
1187 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001188
Yves Gerey665174f2018-06-19 15:03:05 +02001189 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1190 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191}
1192
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001193// Creates an audio+video sendonly offer.
1194TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001195 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001196 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001197 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1198 {kMediaStream1}, 1, &opts);
1199 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1200 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001201
Steve Anton6fe1fba2018-12-11 10:15:23 -08001202 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001203 ASSERT_TRUE(offer.get() != NULL);
1204 EXPECT_EQ(2u, offer->contents().size());
1205 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1206 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1207
Steve Anton4e70a722017-11-28 14:57:10 -08001208 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1209 GetMediaDirection(&offer->contents()[0]));
1210 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1211 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001212}
1213
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001214// Verifies that the order of the media contents in the current
1215// SessionDescription is preserved in the new SessionDescription.
1216TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1217 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001218 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001219
kwiberg31022942016-03-11 14:18:21 -08001220 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001221 ASSERT_TRUE(offer1.get() != NULL);
1222 EXPECT_EQ(1u, offer1->contents().size());
1223 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1224
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001225 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1226 RtpTransceiverDirection::kRecvOnly, kActive,
1227 &opts);
kwiberg31022942016-03-11 14:18:21 -08001228 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001229 f1_.CreateOffer(opts, offer1.get()));
1230 ASSERT_TRUE(offer2.get() != NULL);
1231 EXPECT_EQ(2u, offer2->contents().size());
1232 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1233 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1234
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001235 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1236 RtpTransceiverDirection::kRecvOnly, kActive,
1237 &opts);
kwiberg31022942016-03-11 14:18:21 -08001238 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001239 f1_.CreateOffer(opts, offer2.get()));
1240 ASSERT_TRUE(offer3.get() != NULL);
1241 EXPECT_EQ(3u, offer3->contents().size());
1242 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1243 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1244 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001245}
1246
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247// Create a typical audio answer, and ensure it matches what we expect.
1248TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1249 f1_.set_secure(SEC_ENABLED);
1250 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001251 std::unique_ptr<SessionDescription> offer =
1252 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001254 std::unique_ptr<SessionDescription> answer =
1255 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 const ContentInfo* ac = answer->GetContentByName("audio");
1257 const ContentInfo* vc = answer->GetContentByName("video");
1258 ASSERT_TRUE(ac != NULL);
1259 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001260 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001261 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001263 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001264 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001265 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1266 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001267 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001268 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269}
1270
jbauchcb560652016-08-04 05:20:32 -07001271// Create a typical audio answer with GCM ciphers enabled, and ensure it
1272// matches what we expect.
1273TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1274 f1_.set_secure(SEC_ENABLED);
1275 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001276 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001277 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001278 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001279 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +02001280 for (cricket::ContentInfo& content : offer->contents()) {
1281 auto cryptos = content.media_description()->cryptos();
1282 PreferGcmCryptoParameters(&cryptos);
1283 content.media_description()->set_cryptos(cryptos);
1284 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08001285 std::unique_ptr<SessionDescription> answer =
1286 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001287 const ContentInfo* ac = answer->GetContentByName("audio");
1288 const ContentInfo* vc = answer->GetContentByName("video");
1289 ASSERT_TRUE(ac != NULL);
1290 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001291 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001292 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001293 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001294 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001295 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001296 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1297 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001298 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001299 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001300}
1301
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001302// Create a typical video answer, and ensure it matches what we expect.
1303TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1304 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001305 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001306 f1_.set_secure(SEC_ENABLED);
1307 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001308 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001310 std::unique_ptr<SessionDescription> answer =
1311 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 const ContentInfo* ac = answer->GetContentByName("audio");
1313 const ContentInfo* vc = answer->GetContentByName("video");
1314 ASSERT_TRUE(ac != NULL);
1315 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001316 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1317 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001318 const AudioContentDescription* acd = ac->media_description()->as_audio();
1319 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001320 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001321 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001322 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001323 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001324 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001325 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001326 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001327 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001328 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1329 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001330 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001331 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001332}
1333
jbauchcb560652016-08-04 05:20:32 -07001334// Create a typical video answer with GCM ciphers enabled, and ensure it
1335// matches what we expect.
1336TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1337 TestVideoGcmCipher(true, true);
1338}
1339
1340// Create a typical video answer with GCM ciphers enabled for the offer only,
1341// and ensure it matches what we expect.
1342TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1343 TestVideoGcmCipher(true, false);
1344}
1345
1346// Create a typical video answer with GCM ciphers enabled for the answer only,
1347// and ensure it matches what we expect.
1348TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1349 TestVideoGcmCipher(false, true);
1350}
1351
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001352TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001353 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001354 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001355 f1_.set_secure(SEC_ENABLED);
1356 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001357 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001358 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001359 std::unique_ptr<SessionDescription> answer =
1360 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001361 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001362 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001363 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001364 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001365 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1366 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001367 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001368 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001369 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001370 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001371 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001372 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001373 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001374 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001375 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001376 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001377 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001378 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001379 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001380 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001381}
1382
jbauchcb560652016-08-04 05:20:32 -07001383TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001384 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001385 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001386 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001387 f1_.set_secure(SEC_ENABLED);
1388 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001389 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001390 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +02001391 for (cricket::ContentInfo& content : offer->contents()) {
1392 auto cryptos = content.media_description()->cryptos();
1393 PreferGcmCryptoParameters(&cryptos);
1394 content.media_description()->set_cryptos(cryptos);
1395 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08001396 std::unique_ptr<SessionDescription> answer =
1397 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001398 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001399 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001400 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001401 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001402 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1403 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001404 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001405 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001406 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001407 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001408 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001409 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001410 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001411 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001412 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001413 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001414 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001415 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001416 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001417 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001418}
1419
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001420// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1421// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001422TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1423 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001424 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001425 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001426 ASSERT_TRUE(offer.get() != NULL);
1427 ContentInfo* dc_offer = offer->GetContentByName("data");
1428 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001429 SctpDataContentDescription* dcd_offer =
1430 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001431 EXPECT_TRUE(dcd_offer->use_sctpmap());
1432
Steve Anton6fe1fba2018-12-11 10:15:23 -08001433 std::unique_ptr<SessionDescription> answer =
1434 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001435 const ContentInfo* dc_answer = answer->GetContentByName("data");
1436 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001437 const SctpDataContentDescription* dcd_answer =
1438 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001439 EXPECT_TRUE(dcd_answer->use_sctpmap());
1440}
1441
1442// The answer's use_sctpmap flag should match the offer's.
1443TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1444 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001445 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001446 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001447 ASSERT_TRUE(offer.get() != NULL);
1448 ContentInfo* dc_offer = offer->GetContentByName("data");
1449 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001450 SctpDataContentDescription* dcd_offer =
1451 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001452 dcd_offer->set_use_sctpmap(false);
1453
Steve Anton6fe1fba2018-12-11 10:15:23 -08001454 std::unique_ptr<SessionDescription> answer =
1455 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001456 const ContentInfo* dc_answer = answer->GetContentByName("data");
1457 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001458 const SctpDataContentDescription* dcd_answer =
1459 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001460 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001461}
1462
deadbeef8b7e9ad2017-05-25 09:38:55 -07001463// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1464// and "TCP/DTLS/SCTP" offers.
1465TEST_F(MediaSessionDescriptionFactoryTest,
1466 TestCreateDataAnswerToDifferentOfferedProtos) {
1467 // Need to enable DTLS offer/answer generation (disabled by default in this
1468 // test).
1469 f1_.set_secure(SEC_ENABLED);
1470 f2_.set_secure(SEC_ENABLED);
1471 tdf1_.set_secure(SEC_ENABLED);
1472 tdf2_.set_secure(SEC_ENABLED);
1473
1474 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001475 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001476 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001477 ASSERT_TRUE(offer.get() != nullptr);
1478 ContentInfo* dc_offer = offer->GetContentByName("data");
1479 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001480 SctpDataContentDescription* dcd_offer =
1481 dc_offer->media_description()->as_sctp();
1482 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001483
1484 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1485 "TCP/DTLS/SCTP"};
1486 for (const std::string& proto : protos) {
1487 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001488 std::unique_ptr<SessionDescription> answer =
1489 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001490 const ContentInfo* dc_answer = answer->GetContentByName("data");
1491 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001492 const SctpDataContentDescription* dcd_answer =
1493 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001494 EXPECT_FALSE(dc_answer->rejected);
1495 EXPECT_EQ(proto, dcd_answer->protocol());
1496 }
1497}
1498
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001499TEST_F(MediaSessionDescriptionFactoryTest,
1500 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1501 // Need to enable DTLS offer/answer generation (disabled by default in this
1502 // test).
1503 f1_.set_secure(SEC_ENABLED);
1504 f2_.set_secure(SEC_ENABLED);
1505 tdf1_.set_secure(SEC_ENABLED);
1506 tdf2_.set_secure(SEC_ENABLED);
1507
1508 MediaSessionOptions opts;
1509 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1510 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1511 ASSERT_TRUE(offer.get() != nullptr);
1512 ContentInfo* dc_offer = offer->GetContentByName("data");
1513 ASSERT_TRUE(dc_offer != nullptr);
1514 SctpDataContentDescription* dcd_offer =
1515 dc_offer->media_description()->as_sctp();
1516 ASSERT_TRUE(dcd_offer);
1517 dcd_offer->set_max_message_size(1234);
1518 std::unique_ptr<SessionDescription> answer =
1519 f2_.CreateAnswer(offer.get(), opts, nullptr);
1520 const ContentInfo* dc_answer = answer->GetContentByName("data");
1521 ASSERT_TRUE(dc_answer != nullptr);
1522 const SctpDataContentDescription* dcd_answer =
1523 dc_answer->media_description()->as_sctp();
1524 EXPECT_FALSE(dc_answer->rejected);
1525 EXPECT_EQ(1234, dcd_answer->max_message_size());
1526}
1527
1528TEST_F(MediaSessionDescriptionFactoryTest,
1529 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1530 // Need to enable DTLS offer/answer generation (disabled by default in this
1531 // test).
1532 f1_.set_secure(SEC_ENABLED);
1533 f2_.set_secure(SEC_ENABLED);
1534 tdf1_.set_secure(SEC_ENABLED);
1535 tdf2_.set_secure(SEC_ENABLED);
1536
1537 MediaSessionOptions opts;
1538 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1539 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1540 ASSERT_TRUE(offer.get() != nullptr);
1541 ContentInfo* dc_offer = offer->GetContentByName("data");
1542 ASSERT_TRUE(dc_offer != nullptr);
1543 SctpDataContentDescription* dcd_offer =
1544 dc_offer->media_description()->as_sctp();
1545 ASSERT_TRUE(dcd_offer);
1546 dcd_offer->set_max_message_size(0);
1547 std::unique_ptr<SessionDescription> answer =
1548 f2_.CreateAnswer(offer.get(), opts, nullptr);
1549 const ContentInfo* dc_answer = answer->GetContentByName("data");
1550 ASSERT_TRUE(dc_answer != nullptr);
1551 const SctpDataContentDescription* dcd_answer =
1552 dc_answer->media_description()->as_sctp();
1553 EXPECT_FALSE(dc_answer->rejected);
1554 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1555}
1556
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001557// Verifies that the order of the media contents in the offer is preserved in
1558// the answer.
1559TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1560 MediaSessionOptions opts;
1561
1562 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001563 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001564 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001565 ASSERT_TRUE(offer1.get() != NULL);
1566
1567 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001568 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1569 RtpTransceiverDirection::kRecvOnly, kActive,
1570 &opts);
kwiberg31022942016-03-11 14:18:21 -08001571 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001572 f1_.CreateOffer(opts, offer1.get()));
1573 ASSERT_TRUE(offer2.get() != NULL);
1574
1575 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001576 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1577 RtpTransceiverDirection::kRecvOnly, kActive,
1578 &opts);
kwiberg31022942016-03-11 14:18:21 -08001579 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001580 f1_.CreateOffer(opts, offer2.get()));
1581 ASSERT_TRUE(offer3.get() != NULL);
1582
Steve Anton6fe1fba2018-12-11 10:15:23 -08001583 std::unique_ptr<SessionDescription> answer =
1584 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001585 ASSERT_TRUE(answer.get() != NULL);
1586 EXPECT_EQ(3u, answer->contents().size());
1587 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1588 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1589 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1590}
1591
ossu075af922016-06-14 03:29:38 -07001592// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1593// answerer settings.
1594
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001595// This test that the media direction is set to send/receive in an answer if
1596// the offer is send receive.
1597TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001598 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1599 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001600}
1601
1602// This test that the media direction is set to receive only in an answer if
1603// the offer is send only.
1604TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001605 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1606 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001607}
1608
1609// This test that the media direction is set to send only in an answer if
1610// the offer is recv only.
1611TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001612 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1613 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001614}
1615
1616// This test that the media direction is set to inactive in an answer if
1617// the offer is inactive.
1618TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001619 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1620 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001621}
1622
1623// Test that a data content with an unknown protocol is rejected in an answer.
1624TEST_F(MediaSessionDescriptionFactoryTest,
1625 CreateDataAnswerToOfferWithUnknownProtocol) {
1626 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001627 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001628 f1_.set_secure(SEC_ENABLED);
1629 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001630 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001631 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001632 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001633 RtpDataContentDescription* dcd_offer =
1634 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001636 // Offer must be acceptable as an RTP protocol in order to be set.
1637 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001638 dcd_offer->set_protocol(protocol);
1639
Steve Anton6fe1fba2018-12-11 10:15:23 -08001640 std::unique_ptr<SessionDescription> answer =
1641 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001642
1643 const ContentInfo* dc_answer = answer->GetContentByName("data");
1644 ASSERT_TRUE(dc_answer != NULL);
1645 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001646 const RtpDataContentDescription* dcd_answer =
1647 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001648 ASSERT_TRUE(dcd_answer != NULL);
1649 EXPECT_EQ(protocol, dcd_answer->protocol());
1650}
1651
1652// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1653TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001654 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001655 f1_.set_secure(SEC_DISABLED);
1656 f2_.set_secure(SEC_DISABLED);
1657 tdf1_.set_secure(SEC_DISABLED);
1658 tdf2_.set_secure(SEC_DISABLED);
1659
Steve Anton6fe1fba2018-12-11 10:15:23 -08001660 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001661 const AudioContentDescription* offer_acd =
1662 GetFirstAudioContentDescription(offer.get());
1663 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001664 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001665
Steve Anton6fe1fba2018-12-11 10:15:23 -08001666 std::unique_ptr<SessionDescription> answer =
1667 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668
1669 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1670 ASSERT_TRUE(ac_answer != NULL);
1671 EXPECT_FALSE(ac_answer->rejected);
1672
1673 const AudioContentDescription* answer_acd =
1674 GetFirstAudioContentDescription(answer.get());
1675 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001676 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001677}
1678
1679// Create a video offer and answer and ensure the RTP header extensions
1680// matches what we expect.
1681TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1682 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001683 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell755c65d2020-06-24 01:06:10 +02001684 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1685 MAKE_VECTOR(kVideoRtpExtension1), &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001686
Steve Anton6fe1fba2018-12-11 10:15:23 -08001687 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001688 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02001689 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1690 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001691 std::unique_ptr<SessionDescription> answer =
1692 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001693
Yves Gerey665174f2018-06-19 15:03:05 +02001694 EXPECT_EQ(
1695 MAKE_VECTOR(kAudioRtpExtension1),
1696 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1697 EXPECT_EQ(
1698 MAKE_VECTOR(kVideoRtpExtension1),
1699 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1700 EXPECT_EQ(
1701 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1702 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1703 EXPECT_EQ(
1704 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1705 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001706}
1707
Johannes Kronce8e8672019-02-22 13:06:44 +01001708// Create a audio/video offer and answer and ensure that the
1709// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1710// supported and should take precedence even though not listed among locally
1711// supported extensions.
1712TEST_F(MediaSessionDescriptionFactoryTest,
1713 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1714 TestTransportSequenceNumberNegotiation(
1715 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1716 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1717 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1718}
1719TEST_F(MediaSessionDescriptionFactoryTest,
1720 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1721 TestTransportSequenceNumberNegotiation(
1722 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1723 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1724 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1725}
1726TEST_F(MediaSessionDescriptionFactoryTest,
1727 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1728 TestTransportSequenceNumberNegotiation(
1729 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1730 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1731 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1732}
1733
jbauch5869f502017-06-29 12:31:36 -07001734TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001735 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1736 MediaSessionOptions opts;
1737 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1738
Markus Handell755c65d2020-06-24 01:06:10 +02001739 SetAudioVideoRtpHeaderExtensions(
1740 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1741 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001742 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001743 SetAudioVideoRtpHeaderExtensions(
1744 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1745 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001746 std::unique_ptr<SessionDescription> answer =
1747 f2_.CreateAnswer(offer.get(), opts, nullptr);
1748 EXPECT_THAT(
1749 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001750 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001751 EXPECT_THAT(
1752 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001753 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001754}
1755
1756TEST_F(MediaSessionDescriptionFactoryTest,
1757 TestNegotiateFrameDescriptorWhenExposedLocally) {
1758 MediaSessionOptions opts;
1759 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1760
Markus Handell755c65d2020-06-24 01:06:10 +02001761 SetAudioVideoRtpHeaderExtensions(
1762 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1763 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001764 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1765 std::unique_ptr<SessionDescription> answer =
1766 f2_.CreateAnswer(offer.get(), opts, nullptr);
1767 EXPECT_THAT(
1768 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001769 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001770 EXPECT_THAT(
1771 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell755c65d2020-06-24 01:06:10 +02001772 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001773}
1774
1775TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001776 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1777 MediaSessionOptions opts;
1778 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1779
1780 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell755c65d2020-06-24 01:06:10 +02001781 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Markus Handell6f727da2020-06-12 15:24:54 +00001782 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001783 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1784 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001785 std::unique_ptr<SessionDescription> answer =
1786 f2_.CreateAnswer(offer.get(), opts, nullptr);
1787 EXPECT_THAT(
1788 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1789 ElementsAre(offer_dd));
1790}
1791
1792TEST_F(MediaSessionDescriptionFactoryTest,
1793 NegotiateDependencyDescriptorWhenExposedLocally) {
1794 MediaSessionOptions opts;
1795 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1796
1797 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1798 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell755c65d2020-06-24 01:06:10 +02001799 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001800 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001801 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001802 std::unique_ptr<SessionDescription> answer =
1803 f2_.CreateAnswer(offer.get(), opts, nullptr);
1804 EXPECT_THAT(
1805 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1806 ElementsAre(offer_dd));
1807}
1808
1809TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001810 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1811 MediaSessionOptions opts;
1812 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1813
1814 const cricket::RtpHeaderExtensions offered_extensions = {
1815 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1816 const cricket::RtpHeaderExtensions local_extensions = {
1817 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001818 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1819 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001820 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001821 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001822 std::unique_ptr<SessionDescription> answer =
1823 f2_.CreateAnswer(offer.get(), opts, nullptr);
1824 EXPECT_THAT(
1825 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1826 ElementsAreArray(offered_extensions));
1827 EXPECT_THAT(
1828 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1829 ElementsAreArray(offered_extensions));
1830}
1831
1832TEST_F(MediaSessionDescriptionFactoryTest,
1833 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1834 MediaSessionOptions opts;
1835 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1836
1837 const cricket::RtpHeaderExtensions offered_extensions = {
1838 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1839 const cricket::RtpHeaderExtensions local_extensions = {
1840 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001841 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1842 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001843 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001844 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001845 std::unique_ptr<SessionDescription> answer =
1846 f2_.CreateAnswer(offer.get(), opts, nullptr);
1847 EXPECT_THAT(
1848 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1849 ElementsAreArray(offered_extensions));
1850 EXPECT_THAT(
1851 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1852 ElementsAreArray(offered_extensions));
1853}
1854
1855TEST_F(MediaSessionDescriptionFactoryTest,
1856 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1857 MediaSessionOptions opts;
1858 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1859
1860 const cricket::RtpHeaderExtensions offered_extensions = {
1861 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1862 const cricket::RtpHeaderExtensions local_extensions = {
1863 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell755c65d2020-06-24 01:06:10 +02001864 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1865 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001866 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell755c65d2020-06-24 01:06:10 +02001867 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001868 std::unique_ptr<SessionDescription> answer =
1869 f2_.CreateAnswer(offer.get(), opts, nullptr);
1870 EXPECT_THAT(
1871 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1872 IsEmpty());
1873 EXPECT_THAT(
1874 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1875 IsEmpty());
1876}
1877
1878TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handell755c65d2020-06-24 01:06:10 +02001879 OffersUnstoppedExtensionsWithAudioVideoExtensionStopped) {
1880 MediaSessionOptions opts;
1881 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1882 RtpTransceiverDirection::kSendRecv, kActive,
1883 &opts);
1884 opts.media_description_options.back().header_extensions = {
1885 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1886 RtpTransceiverDirection::kStopped),
1887 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1888 RtpTransceiverDirection::kSendOnly)};
1889 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1890 RtpTransceiverDirection::kSendRecv, kActive,
1891 &opts);
1892 opts.media_description_options.back().header_extensions = {
1893 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1894 RtpTransceiverDirection::kStopped),
1895 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1896 RtpTransceiverDirection::kSendOnly)};
1897 auto offer = f1_.CreateOffer(opts, nullptr);
1898 EXPECT_THAT(
1899 offer->contents(),
1900 ElementsAre(
1901 Property(&ContentInfo::media_description,
1902 Pointee(Property(
1903 &MediaContentDescription::rtp_header_extensions,
1904 ElementsAre(Field(&RtpExtension::uri, "uri2"))))),
1905 Property(&ContentInfo::media_description,
1906 Pointee(Property(
1907 &MediaContentDescription::rtp_header_extensions,
1908 ElementsAre(Field(&RtpExtension::uri, "uri3")))))));
1909}
1910
1911TEST_F(MediaSessionDescriptionFactoryTest,
1912 OffersUnstoppedExtensionsWithAudioExtensionStopped) {
1913 MediaSessionOptions opts;
1914 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1915 RtpTransceiverDirection::kSendRecv, kActive,
1916 &opts);
1917 opts.media_description_options.back().header_extensions = {
1918 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1919 RtpTransceiverDirection::kSendOnly),
1920 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1921 RtpTransceiverDirection::kStopped)};
1922 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1923 RtpTransceiverDirection::kSendRecv, kActive,
1924 &opts);
1925 opts.media_description_options.back().header_extensions = {
1926 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1927 RtpTransceiverDirection::kSendRecv),
1928 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1929 RtpTransceiverDirection::kSendOnly)};
1930 auto offer = f1_.CreateOffer(opts, nullptr);
1931 EXPECT_THAT(
1932 offer->contents(),
1933 ElementsAre(
1934 Property(&ContentInfo::media_description,
1935 Pointee(Property(
1936 &MediaContentDescription::rtp_header_extensions,
1937 ElementsAre(Field(&RtpExtension::uri, "uri1"))))),
1938 Property(
1939 &ContentInfo::media_description,
1940 Pointee(Property(
1941 &MediaContentDescription::rtp_header_extensions,
1942 UnorderedElementsAre(Field(&RtpExtension::uri, "uri3"),
1943 Field(&RtpExtension::uri, "uri42")))))));
1944}
1945
1946TEST_F(MediaSessionDescriptionFactoryTest,
1947 OffersUnstoppedExtensionsWithVideoExtensionStopped) {
1948 MediaSessionOptions opts;
1949 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1950 RtpTransceiverDirection::kSendRecv, kActive,
1951 &opts);
1952 opts.media_description_options.back().header_extensions = {
1953 webrtc::RtpHeaderExtensionCapability("uri1", 5,
1954 RtpTransceiverDirection::kSendOnly),
1955 webrtc::RtpHeaderExtensionCapability("uri2", 7,
1956 RtpTransceiverDirection::kSendRecv)};
1957 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1958 RtpTransceiverDirection::kSendRecv, kActive,
1959 &opts);
1960 opts.media_description_options.back().header_extensions = {
1961 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1962 RtpTransceiverDirection::kSendRecv),
1963 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1964 RtpTransceiverDirection::kStopped)};
1965 auto offer = f1_.CreateOffer(opts, nullptr);
1966 EXPECT_THAT(
1967 offer->contents(),
1968 ElementsAre(
1969 Property(
1970 &ContentInfo::media_description,
1971 Pointee(Property(
1972 &MediaContentDescription::rtp_header_extensions,
1973 UnorderedElementsAre(Field(&RtpExtension::uri, "uri1"),
1974 Field(&RtpExtension::uri, "uri2"))))),
1975 Property(&ContentInfo::media_description,
1976 Pointee(Property(
1977 &MediaContentDescription::rtp_header_extensions,
1978 ElementsAre(Field(&RtpExtension::uri, "uri42")))))));
1979}
1980
1981TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1982 MediaSessionOptions opts;
1983 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1984 RtpTransceiverDirection::kSendRecv, kActive,
1985 &opts);
1986 opts.media_description_options.back().header_extensions = {
1987 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1988 RtpTransceiverDirection::kStopped),
1989 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1990 RtpTransceiverDirection::kSendOnly),
1991 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1992 RtpTransceiverDirection::kRecvOnly),
1993 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1994 RtpTransceiverDirection::kSendRecv)};
1995 auto offer = f1_.CreateOffer(opts, nullptr);
1996 opts.media_description_options.back().header_extensions = {
1997 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1998 RtpTransceiverDirection::kSendOnly),
1999 webrtc::RtpHeaderExtensionCapability("uri2", 3,
2000 RtpTransceiverDirection::kRecvOnly),
2001 webrtc::RtpHeaderExtensionCapability("uri3", 2,
2002 RtpTransceiverDirection::kStopped),
2003 webrtc::RtpHeaderExtensionCapability("uri4", 1,
2004 RtpTransceiverDirection::kSendRecv)};
2005 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
2006 EXPECT_THAT(
2007 answer->contents(),
2008 ElementsAre(Property(
2009 &ContentInfo::media_description,
2010 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2011 ElementsAre(Field(&RtpExtension::uri, "uri2"),
2012 Field(&RtpExtension::uri, "uri4")))))));
2013}
2014
2015TEST_F(MediaSessionDescriptionFactoryTest,
2016 AppendsUnstoppedExtensionsToCurrentDescription) {
2017 MediaSessionOptions opts;
2018 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2019 RtpTransceiverDirection::kSendRecv, kActive,
2020 &opts);
2021 opts.media_description_options.back().header_extensions = {
2022 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2023 RtpTransceiverDirection::kSendRecv)};
2024 auto offer = f1_.CreateOffer(opts, nullptr);
2025 opts.media_description_options.back().header_extensions = {
2026 webrtc::RtpHeaderExtensionCapability("uri1", 2,
2027 RtpTransceiverDirection::kSendRecv),
2028 webrtc::RtpHeaderExtensionCapability("uri2", 3,
2029 RtpTransceiverDirection::kRecvOnly),
2030 webrtc::RtpHeaderExtensionCapability("uri3", 5,
2031 RtpTransceiverDirection::kStopped),
2032 webrtc::RtpHeaderExtensionCapability("uri4", 6,
2033 RtpTransceiverDirection::kSendRecv)};
2034 auto offer2 = f1_.CreateOffer(opts, offer.get());
2035 EXPECT_THAT(
2036 offer2->contents(),
2037 ElementsAre(Property(
2038 &ContentInfo::media_description,
2039 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2040 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2041 Field(&RtpExtension::uri, "uri2"),
2042 Field(&RtpExtension::uri, "uri4")))))));
2043}
2044
2045TEST_F(MediaSessionDescriptionFactoryTest,
2046 AppendsStoppedExtensionIfKnownAndPresentInTheOffer) {
2047 MediaSessionOptions opts;
2048 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2049 RtpTransceiverDirection::kSendRecv, kActive,
2050 &opts);
2051 opts.media_description_options.back().header_extensions = {
2052 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2053 RtpTransceiverDirection::kSendRecv),
2054 webrtc::RtpHeaderExtensionCapability("uri2", 1,
2055 RtpTransceiverDirection::kSendRecv)};
2056 auto offer = f1_.CreateOffer(opts, nullptr);
2057
2058 // Now add "uri2" as stopped to the options verify that the offer contains
2059 // uri2 since it's already present since before.
2060 opts.media_description_options.back().header_extensions = {
2061 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2062 RtpTransceiverDirection::kSendRecv),
2063 webrtc::RtpHeaderExtensionCapability("uri2", 2,
2064 RtpTransceiverDirection::kStopped)};
2065 auto offer2 = f1_.CreateOffer(opts, offer.get());
2066 EXPECT_THAT(
2067 offer2->contents(),
2068 ElementsAre(Property(
2069 &ContentInfo::media_description,
2070 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2071 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2072 Field(&RtpExtension::uri, "uri2")))))));
2073}
2074
2075TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002076 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07002077 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002078 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002079
2080 f1_.set_enable_encrypted_rtp_header_extensions(true);
2081 f2_.set_enable_encrypted_rtp_header_extensions(true);
2082
Markus Handell755c65d2020-06-24 01:06:10 +02002083 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2084 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002085 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002086 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002087 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2088 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002089 std::unique_ptr<SessionDescription> answer =
2090 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002091
Yves Gerey665174f2018-06-19 15:03:05 +02002092 EXPECT_EQ(
2093 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2094 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2095 EXPECT_EQ(
2096 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2097 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2098 EXPECT_EQ(
2099 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
2100 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2101 EXPECT_EQ(
2102 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
2103 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002104}
2105
2106TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002107 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07002108 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002109 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002110
2111 f1_.set_enable_encrypted_rtp_header_extensions(true);
2112
Markus Handell755c65d2020-06-24 01:06:10 +02002113 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2114 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002115 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002116 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002117 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2118 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002119 std::unique_ptr<SessionDescription> answer =
2120 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002121
Yves Gerey665174f2018-06-19 15:03:05 +02002122 EXPECT_EQ(
2123 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2124 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2125 EXPECT_EQ(
2126 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2127 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2128 EXPECT_EQ(
2129 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2130 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2131 EXPECT_EQ(
2132 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2133 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002134}
2135
2136TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002137 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07002138 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002139 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002140
2141 f2_.set_enable_encrypted_rtp_header_extensions(true);
2142
Markus Handell755c65d2020-06-24 01:06:10 +02002143 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2144 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002145 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002146 ASSERT_TRUE(offer.get() != NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02002147 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2148 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002149 std::unique_ptr<SessionDescription> answer =
2150 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002151
Yves Gerey665174f2018-06-19 15:03:05 +02002152 EXPECT_EQ(
2153 MAKE_VECTOR(kAudioRtpExtension1),
2154 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2155 EXPECT_EQ(
2156 MAKE_VECTOR(kVideoRtpExtension1),
2157 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2158 EXPECT_EQ(
2159 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2160 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2161 EXPECT_EQ(
2162 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2163 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002164}
2165
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002166// Create an audio, video, data answer without legacy StreamParams.
2167TEST_F(MediaSessionDescriptionFactoryTest,
2168 TestCreateAnswerWithoutLegacyStreams) {
2169 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002170 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2171 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002172 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002173 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002174 std::unique_ptr<SessionDescription> answer =
2175 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002176 const ContentInfo* ac = answer->GetContentByName("audio");
2177 const ContentInfo* vc = answer->GetContentByName("video");
2178 const ContentInfo* dc = answer->GetContentByName("data");
2179 ASSERT_TRUE(ac != NULL);
2180 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002181 const AudioContentDescription* acd = ac->media_description()->as_audio();
2182 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002183 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002184
2185 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2186 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
2187 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
2188}
2189
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002190// Create a typical video answer, and ensure it matches what we expect.
2191TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2192 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002193 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
2194 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
2195 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002196
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002198 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
2199 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
2200 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002201
kwiberg31022942016-03-11 14:18:21 -08002202 std::unique_ptr<SessionDescription> offer;
2203 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002204
2205 offer_opts.rtcp_mux_enabled = true;
2206 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002207 offer = f1_.CreateOffer(offer_opts, NULL);
2208 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2210 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002211 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002212 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2213 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002214 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002215 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2216 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002217 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002218 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2219 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002220 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002221
2222 offer_opts.rtcp_mux_enabled = true;
2223 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002224 offer = f1_.CreateOffer(offer_opts, NULL);
2225 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002226 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2227 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002228 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002229 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2230 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002231 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002232 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2233 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002234 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002235 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2236 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002237 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002238
2239 offer_opts.rtcp_mux_enabled = false;
2240 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002241 offer = f1_.CreateOffer(offer_opts, NULL);
2242 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002243 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2244 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002245 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002246 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2247 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002248 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002249 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2250 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002251 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002252 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2253 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002254 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002255
2256 offer_opts.rtcp_mux_enabled = false;
2257 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002258 offer = f1_.CreateOffer(offer_opts, NULL);
2259 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002260 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2261 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002262 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002263 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2264 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002265 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002266 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2267 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002268 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002269 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2270 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002271 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002272}
2273
2274// Create an audio-only answer to a video offer.
2275TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2276 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002277 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2278 RtpTransceiverDirection::kRecvOnly, kActive,
2279 &opts);
2280 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2281 RtpTransceiverDirection::kRecvOnly, kActive,
2282 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002283 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002284 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002285
2286 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002287 std::unique_ptr<SessionDescription> answer =
2288 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002289 const ContentInfo* ac = answer->GetContentByName("audio");
2290 const ContentInfo* vc = answer->GetContentByName("video");
2291 ASSERT_TRUE(ac != NULL);
2292 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002293 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002294 EXPECT_TRUE(vc->rejected);
2295}
2296
2297// Create an audio-only answer to an offer with data.
2298TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002299 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002300 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002301 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2302 RtpTransceiverDirection::kRecvOnly, kActive,
2303 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002304 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002305 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002306
2307 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002308 std::unique_ptr<SessionDescription> answer =
2309 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310 const ContentInfo* ac = answer->GetContentByName("audio");
2311 const ContentInfo* dc = answer->GetContentByName("data");
2312 ASSERT_TRUE(ac != NULL);
2313 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002314 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002315 EXPECT_TRUE(dc->rejected);
2316}
2317
2318// Create an answer that rejects the contents which are rejected in the offer.
2319TEST_F(MediaSessionDescriptionFactoryTest,
2320 CreateAnswerToOfferWithRejectedMedia) {
2321 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002322 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2323 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002324 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002325 ASSERT_TRUE(offer.get() != NULL);
2326 ContentInfo* ac = offer->GetContentByName("audio");
2327 ContentInfo* vc = offer->GetContentByName("video");
2328 ContentInfo* dc = offer->GetContentByName("data");
2329 ASSERT_TRUE(ac != NULL);
2330 ASSERT_TRUE(vc != NULL);
2331 ASSERT_TRUE(dc != NULL);
2332 ac->rejected = true;
2333 vc->rejected = true;
2334 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002335 std::unique_ptr<SessionDescription> answer =
2336 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002337 ac = answer->GetContentByName("audio");
2338 vc = answer->GetContentByName("video");
2339 dc = answer->GetContentByName("data");
2340 ASSERT_TRUE(ac != NULL);
2341 ASSERT_TRUE(vc != NULL);
2342 ASSERT_TRUE(dc != NULL);
2343 EXPECT_TRUE(ac->rejected);
2344 EXPECT_TRUE(vc->rejected);
2345 EXPECT_TRUE(dc->rejected);
2346}
2347
Johannes Kron0854eb62018-10-10 22:33:20 +02002348TEST_F(MediaSessionDescriptionFactoryTest,
2349 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2350 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002351 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002352 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002353 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002354 ASSERT_TRUE(offer.get() != NULL);
2355 std::unique_ptr<SessionDescription> answer_no_support(
2356 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002357 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002358
2359 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002360 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002361 ASSERT_TRUE(offer.get() != NULL);
2362 std::unique_ptr<SessionDescription> answer_support(
2363 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002364 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002365}
2366
2367TEST_F(MediaSessionDescriptionFactoryTest,
2368 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2369 MediaSessionOptions opts;
2370 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002371 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002372 MediaContentDescription* video_offer =
2373 offer->GetContentDescriptionByName("video");
2374 ASSERT_TRUE(video_offer);
2375 MediaContentDescription* audio_offer =
2376 offer->GetContentDescriptionByName("audio");
2377 ASSERT_TRUE(audio_offer);
2378
2379 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002380 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2381 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002382
2383 ASSERT_TRUE(offer.get() != NULL);
2384 std::unique_ptr<SessionDescription> answer_no_support(
2385 f2_.CreateAnswer(offer.get(), opts, NULL));
2386 MediaContentDescription* video_answer =
2387 answer_no_support->GetContentDescriptionByName("video");
2388 MediaContentDescription* audio_answer =
2389 answer_no_support->GetContentDescriptionByName("audio");
2390 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002391 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002392 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002393 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002394
2395 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002396 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2397 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002398 ASSERT_TRUE(offer.get() != NULL);
2399 std::unique_ptr<SessionDescription> answer_support(
2400 f2_.CreateAnswer(offer.get(), opts, NULL));
2401 video_answer = answer_support->GetContentDescriptionByName("video");
2402 audio_answer = answer_support->GetContentDescriptionByName("audio");
2403 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002404 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002405 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002406 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002407}
2408
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002409// Create an audio and video offer with:
2410// - one video track
2411// - two audio tracks
2412// - two data tracks
2413// and ensure it matches what we expect. Also updates the initial offer by
2414// adding a new video track and replaces one of the audio tracks.
2415TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2416 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002417 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002418 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2419 {kMediaStream1}, 1, &opts);
2420 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2421 {kMediaStream1}, 1, &opts);
2422 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2423 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002424
Steve Anton4e70a722017-11-28 14:57:10 -08002425 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002426 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2427 {kMediaStream1}, 1, &opts);
2428 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2429 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002430
2431 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002432 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002433
2434 ASSERT_TRUE(offer.get() != NULL);
2435 const ContentInfo* ac = offer->GetContentByName("audio");
2436 const ContentInfo* vc = offer->GetContentByName("video");
2437 const ContentInfo* dc = offer->GetContentByName("data");
2438 ASSERT_TRUE(ac != NULL);
2439 ASSERT_TRUE(vc != NULL);
2440 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002441 const AudioContentDescription* acd = ac->media_description()->as_audio();
2442 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002443 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002444 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002445 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002446
2447 const StreamParamsVec& audio_streams = acd->streams();
2448 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002449 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002450 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2451 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2452 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2453 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2454 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2455 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2456
2457 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2458 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002459 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002460
2461 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002462 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002463 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002464
2465 const StreamParamsVec& video_streams = vcd->streams();
2466 ASSERT_EQ(1U, video_streams.size());
2467 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2468 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2469 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2470 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2471
2472 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002473 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002474 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002475
2476 const StreamParamsVec& data_streams = dcd->streams();
2477 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002478 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002479 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2480 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2481 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2482 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2483 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2484 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2485
Philipp Hanckeafee7082020-10-22 11:55:58 +02002486 EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002487 dcd->bandwidth()); // default bandwidth (auto)
2488 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002489 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002490
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002491 // Update the offer. Add a new video track that is not synched to the
2492 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002493 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2494 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002495 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002496 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2497 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002498 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002499 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2500 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002501 std::unique_ptr<SessionDescription> updated_offer(
2502 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002503
2504 ASSERT_TRUE(updated_offer.get() != NULL);
2505 ac = updated_offer->GetContentByName("audio");
2506 vc = updated_offer->GetContentByName("video");
2507 dc = updated_offer->GetContentByName("data");
2508 ASSERT_TRUE(ac != NULL);
2509 ASSERT_TRUE(vc != NULL);
2510 ASSERT_TRUE(dc != NULL);
2511 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002512 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002513 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002514 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002515 const RtpDataContentDescription* updated_dcd =
2516 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002517
2518 EXPECT_EQ(acd->type(), updated_acd->type());
2519 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2520 EXPECT_EQ(vcd->type(), updated_vcd->type());
2521 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2522 EXPECT_EQ(dcd->type(), updated_dcd->type());
2523 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002524 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002525 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002526 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002527 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002528 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002529 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2530
2531 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2532 ASSERT_EQ(2U, updated_audio_streams.size());
2533 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2534 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2535 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2536 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2537 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2538
2539 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2540 ASSERT_EQ(2U, updated_video_streams.size());
2541 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2542 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002543 // All the media streams in one PeerConnection share one RTCP CNAME.
2544 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002545
2546 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2547 ASSERT_EQ(2U, updated_data_streams.size());
2548 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2549 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2550 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2551 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2552 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002553 // The stream correctly got the CNAME from the MediaSessionOptions.
2554 // The Expected RTCP CNAME is the default one as we are using the default
2555 // MediaSessionOptions.
2556 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002557}
2558
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002559// Create an offer with simulcast video stream.
2560TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2561 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002562 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2563 RtpTransceiverDirection::kRecvOnly, kActive,
2564 &opts);
2565 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2566 RtpTransceiverDirection::kSendRecv, kActive,
2567 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002568 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002569 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2570 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002571 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002572
2573 ASSERT_TRUE(offer.get() != NULL);
2574 const ContentInfo* vc = offer->GetContentByName("video");
2575 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002576 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002577
2578 const StreamParamsVec& video_streams = vcd->streams();
2579 ASSERT_EQ(1U, video_streams.size());
2580 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2581 const SsrcGroup* sim_ssrc_group =
2582 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2583 ASSERT_TRUE(sim_ssrc_group != NULL);
2584 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2585}
2586
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002587MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2588 const RidDescription& rid1 = ::testing::get<0>(arg);
2589 const RidDescription& rid2 = ::testing::get<1>(arg);
2590 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2591}
2592
2593static void CheckSimulcastInSessionDescription(
2594 const SessionDescription* description,
2595 const std::string& content_name,
2596 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002597 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002598 ASSERT_NE(description, nullptr);
2599 const ContentInfo* content = description->GetContentByName(content_name);
2600 ASSERT_NE(content, nullptr);
2601 const MediaContentDescription* cd = content->media_description();
2602 ASSERT_NE(cd, nullptr);
2603 const StreamParamsVec& streams = cd->streams();
2604 ASSERT_THAT(streams, SizeIs(1));
2605 const StreamParams& stream = streams[0];
2606 ASSERT_THAT(stream.ssrcs, IsEmpty());
2607 EXPECT_TRUE(stream.has_rids());
2608 const std::vector<RidDescription> rids = stream.rids();
2609
2610 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2611
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002612 EXPECT_TRUE(cd->HasSimulcast());
2613 const SimulcastDescription& simulcast = cd->simulcast_description();
2614 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2615 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2616
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002617 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002618}
2619
2620// Create an offer with spec-compliant simulcast video stream.
2621TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2622 MediaSessionOptions opts;
2623 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2624 RtpTransceiverDirection::kSendRecv, kActive,
2625 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002626 std::vector<RidDescription> send_rids;
2627 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2628 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2629 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2630 SimulcastLayerList simulcast_layers;
2631 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2632 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2633 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2634 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2635 {kMediaStream1}, send_rids,
2636 simulcast_layers, 0, &opts);
2637 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2638
2639 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002640 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002641}
2642
2643// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2644// In this scenario, RIDs do not need to be negotiated (there is only one).
2645TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2646 MediaSessionOptions opts;
2647 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2648 RtpTransceiverDirection::kSendRecv, kActive,
2649 &opts);
2650 RidDescription rid("f", RidDirection::kSend);
2651 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2652 {kMediaStream1}, {rid},
2653 SimulcastLayerList(), 0, &opts);
2654 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2655
2656 ASSERT_NE(offer.get(), nullptr);
2657 const ContentInfo* content = offer->GetContentByName("video");
2658 ASSERT_NE(content, nullptr);
2659 const MediaContentDescription* cd = content->media_description();
2660 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002661 const StreamParamsVec& streams = cd->streams();
2662 ASSERT_THAT(streams, SizeIs(1));
2663 const StreamParams& stream = streams[0];
2664 ASSERT_THAT(stream.ssrcs, IsEmpty());
2665 EXPECT_FALSE(stream.has_rids());
2666 EXPECT_FALSE(cd->HasSimulcast());
2667}
2668
2669// Create an answer with spec-compliant simulcast video stream.
2670// In this scenario, the SFU is the caller requesting that we send Simulcast.
2671TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2672 MediaSessionOptions offer_opts;
2673 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2674 RtpTransceiverDirection::kSendRecv, kActive,
2675 &offer_opts);
2676 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2677 {kMediaStream1}, 1, &offer_opts);
2678 std::unique_ptr<SessionDescription> offer =
2679 f1_.CreateOffer(offer_opts, nullptr);
2680
2681 MediaSessionOptions answer_opts;
2682 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2683 RtpTransceiverDirection::kSendRecv, kActive,
2684 &answer_opts);
2685
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002686 std::vector<RidDescription> rid_descriptions{
2687 RidDescription("f", RidDirection::kSend),
2688 RidDescription("h", RidDirection::kSend),
2689 RidDescription("q", RidDirection::kSend),
2690 };
2691 SimulcastLayerList simulcast_layers;
2692 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2693 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2694 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2695 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2696 {kMediaStream1}, rid_descriptions,
2697 simulcast_layers, 0, &answer_opts);
2698 std::unique_ptr<SessionDescription> answer =
2699 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2700
2701 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002702 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002703}
2704
2705// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2706// In this scenario, RIDs do not need to be negotiated (there is only one).
2707// Note that RID Direction is not the same as the transceiver direction.
2708TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2709 MediaSessionOptions offer_opts;
2710 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2711 RtpTransceiverDirection::kSendRecv, kActive,
2712 &offer_opts);
2713 RidDescription rid_offer("f", RidDirection::kSend);
2714 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2715 {kMediaStream1}, {rid_offer},
2716 SimulcastLayerList(), 0, &offer_opts);
2717 std::unique_ptr<SessionDescription> offer =
2718 f1_.CreateOffer(offer_opts, nullptr);
2719
2720 MediaSessionOptions answer_opts;
2721 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2722 RtpTransceiverDirection::kSendRecv, kActive,
2723 &answer_opts);
2724
2725 RidDescription rid_answer("f", RidDirection::kReceive);
2726 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2727 {kMediaStream1}, {rid_answer},
2728 SimulcastLayerList(), 0, &answer_opts);
2729 std::unique_ptr<SessionDescription> answer =
2730 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2731
2732 ASSERT_NE(answer.get(), nullptr);
2733 const ContentInfo* content = offer->GetContentByName("video");
2734 ASSERT_NE(content, nullptr);
2735 const MediaContentDescription* cd = content->media_description();
2736 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002737 const StreamParamsVec& streams = cd->streams();
2738 ASSERT_THAT(streams, SizeIs(1));
2739 const StreamParams& stream = streams[0];
2740 ASSERT_THAT(stream.ssrcs, IsEmpty());
2741 EXPECT_FALSE(stream.has_rids());
2742 EXPECT_FALSE(cd->HasSimulcast());
2743}
2744
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002745// Create an audio and video answer to a standard video offer with:
2746// - one video track
2747// - two audio tracks
2748// - two data tracks
2749// and ensure it matches what we expect. Also updates the initial answer by
2750// adding a new video track and removes one of the audio tracks.
2751TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2752 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002753 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2754 RtpTransceiverDirection::kRecvOnly, kActive,
2755 &offer_opts);
2756 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2757 RtpTransceiverDirection::kRecvOnly, kActive,
2758 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002759 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002760 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2761 RtpTransceiverDirection::kRecvOnly, kActive,
2762 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002763 f1_.set_secure(SEC_ENABLED);
2764 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002765 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002766
zhihuang1c378ed2017-08-17 14:10:50 -07002767 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002768 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2769 RtpTransceiverDirection::kSendRecv, kActive,
2770 &answer_opts);
2771 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2772 RtpTransceiverDirection::kSendRecv, kActive,
2773 &answer_opts);
2774 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2775 {kMediaStream1}, 1, &answer_opts);
2776 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2777 {kMediaStream1}, 1, &answer_opts);
2778 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2779 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002780
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002781 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2782 RtpTransceiverDirection::kSendRecv, kActive,
2783 &answer_opts);
2784 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2785 {kMediaStream1}, 1, &answer_opts);
2786 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2787 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002788 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002789
Steve Anton6fe1fba2018-12-11 10:15:23 -08002790 std::unique_ptr<SessionDescription> answer =
2791 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002792
2793 ASSERT_TRUE(answer.get() != NULL);
2794 const ContentInfo* ac = answer->GetContentByName("audio");
2795 const ContentInfo* vc = answer->GetContentByName("video");
2796 const ContentInfo* dc = answer->GetContentByName("data");
2797 ASSERT_TRUE(ac != NULL);
2798 ASSERT_TRUE(vc != NULL);
2799 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002800 const AudioContentDescription* acd = ac->media_description()->as_audio();
2801 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002802 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002803 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2804 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2805 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002806
2807 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002808 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002809
2810 const StreamParamsVec& audio_streams = acd->streams();
2811 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002812 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002813 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2814 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2815 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2816 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2817 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2818 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2819
2820 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2821 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2822
2823 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002824 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002825
2826 const StreamParamsVec& video_streams = vcd->streams();
2827 ASSERT_EQ(1U, video_streams.size());
2828 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2829 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2830 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2831 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2832
2833 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002834 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002835
2836 const StreamParamsVec& data_streams = dcd->streams();
2837 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002838 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002839 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2840 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2841 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2842 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2843 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2844 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2845
Philipp Hanckeafee7082020-10-22 11:55:58 +02002846 EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002847 dcd->bandwidth()); // default bandwidth (auto)
2848 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002849
2850 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002851 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002852 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2853 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002854 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2855 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002856 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002857 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002858
2859 ASSERT_TRUE(updated_answer.get() != NULL);
2860 ac = updated_answer->GetContentByName("audio");
2861 vc = updated_answer->GetContentByName("video");
2862 dc = updated_answer->GetContentByName("data");
2863 ASSERT_TRUE(ac != NULL);
2864 ASSERT_TRUE(vc != NULL);
2865 ASSERT_TRUE(dc != NULL);
2866 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002867 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002868 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002869 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002870 const RtpDataContentDescription* updated_dcd =
2871 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002872
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002873 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002875 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002876 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002877 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002878 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2879
2880 EXPECT_EQ(acd->type(), updated_acd->type());
2881 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2882 EXPECT_EQ(vcd->type(), updated_vcd->type());
2883 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2884 EXPECT_EQ(dcd->type(), updated_dcd->type());
2885 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2886
2887 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2888 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002889 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002890
2891 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2892 ASSERT_EQ(2U, updated_video_streams.size());
2893 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2894 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002895 // All media streams in one PeerConnection share one CNAME.
2896 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002897
2898 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2899 ASSERT_EQ(1U, updated_data_streams.size());
2900 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2901}
2902
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002903// Create an updated offer after creating an answer to the original offer and
2904// verify that the codecs that were part of the original answer are not changed
2905// in the updated offer.
2906TEST_F(MediaSessionDescriptionFactoryTest,
2907 RespondentCreatesOfferAfterCreatingAnswer) {
2908 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002909 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002910
Steve Anton6fe1fba2018-12-11 10:15:23 -08002911 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2912 std::unique_ptr<SessionDescription> answer =
2913 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002914
2915 const AudioContentDescription* acd =
2916 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002917 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002918
2919 const VideoContentDescription* vcd =
2920 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002921 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002922
kwiberg31022942016-03-11 14:18:21 -08002923 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002924 f2_.CreateOffer(opts, answer.get()));
2925
2926 // The expected audio codecs are the common audio codecs from the first
2927 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2928 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002929 // TODO(wu): |updated_offer| should not include the codec
2930 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002931 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002932 kAudioCodecsAnswer[0],
2933 kAudioCodecsAnswer[1],
2934 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002935 };
2936
2937 // The expected video codecs are the common video codecs from the first
2938 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2939 // preference order.
2940 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002941 kVideoCodecsAnswer[0],
2942 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002943 };
2944
2945 const AudioContentDescription* updated_acd =
2946 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002947 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002948
2949 const VideoContentDescription* updated_vcd =
2950 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002951 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002952}
2953
Steve Anton5c72e712018-12-10 14:25:30 -08002954// Test that a reoffer does not reuse audio codecs from a previous media section
2955// that is being recycled.
2956TEST_F(MediaSessionDescriptionFactoryTest,
2957 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002958 f1_.set_video_codecs({}, {});
2959 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002960
2961 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002962 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2963 RtpTransceiverDirection::kSendRecv, kActive,
2964 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002965 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2966 std::unique_ptr<SessionDescription> answer =
2967 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002968
2969 // Recycle the media section by changing its mid.
2970 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002971 std::unique_ptr<SessionDescription> reoffer =
2972 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002973
2974 // Expect that the results of the first negotiation are ignored. If the m=
2975 // section was not recycled the payload types would match the initial offerer.
2976 const AudioContentDescription* acd =
2977 GetFirstAudioContentDescription(reoffer.get());
2978 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2979}
2980
2981// Test that a reoffer does not reuse video codecs from a previous media section
2982// that is being recycled.
2983TEST_F(MediaSessionDescriptionFactoryTest,
2984 ReOfferDoesNotReUseRecycledVideoCodecs) {
2985 f1_.set_audio_codecs({}, {});
2986 f2_.set_audio_codecs({}, {});
2987
2988 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002989 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2990 RtpTransceiverDirection::kSendRecv, kActive,
2991 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002992 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2993 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002994
2995 // Recycle the media section by changing its mid.
2996 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002997 std::unique_ptr<SessionDescription> reoffer =
2998 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002999
3000 // Expect that the results of the first negotiation are ignored. If the m=
3001 // section was not recycled the payload types would match the initial offerer.
3002 const VideoContentDescription* vcd =
3003 GetFirstVideoContentDescription(reoffer.get());
3004 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
3005}
3006
3007// Test that a reanswer does not reuse audio codecs from a previous media
3008// section that is being recycled.
3009TEST_F(MediaSessionDescriptionFactoryTest,
3010 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02003011 f1_.set_video_codecs({}, {});
3012 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08003013
3014 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
3015 // second offer/answer is forward (|f1_| as offerer).
3016 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003017 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
3018 RtpTransceiverDirection::kSendRecv, kActive,
3019 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003020 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
3021 std::unique_ptr<SessionDescription> answer =
3022 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08003023
3024 // Recycle the media section by changing its mid.
3025 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08003026 std::unique_ptr<SessionDescription> reoffer =
3027 f1_.CreateOffer(opts, answer.get());
3028 std::unique_ptr<SessionDescription> reanswer =
3029 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003030
3031 // Expect that the results of the first negotiation are ignored. If the m=
3032 // section was not recycled the payload types would match the initial offerer.
3033 const AudioContentDescription* acd =
3034 GetFirstAudioContentDescription(reanswer.get());
3035 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
3036}
3037
3038// Test that a reanswer does not reuse video codecs from a previous media
3039// section that is being recycled.
3040TEST_F(MediaSessionDescriptionFactoryTest,
3041 ReAnswerDoesNotReUseRecycledVideoCodecs) {
3042 f1_.set_audio_codecs({}, {});
3043 f2_.set_audio_codecs({}, {});
3044
3045 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
3046 // second offer/answer is forward (|f1_| as offerer).
3047 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003048 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
3049 RtpTransceiverDirection::kSendRecv, kActive,
3050 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003051 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
3052 std::unique_ptr<SessionDescription> answer =
3053 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08003054
3055 // Recycle the media section by changing its mid.
3056 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08003057 std::unique_ptr<SessionDescription> reoffer =
3058 f1_.CreateOffer(opts, answer.get());
3059 std::unique_ptr<SessionDescription> reanswer =
3060 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08003061
3062 // Expect that the results of the first negotiation are ignored. If the m=
3063 // section was not recycled the payload types would match the initial offerer.
3064 const VideoContentDescription* vcd =
3065 GetFirstVideoContentDescription(reanswer.get());
3066 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
3067}
3068
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003069// Create an updated offer after creating an answer to the original offer and
3070// verify that the codecs that were part of the original answer are not changed
3071// in the updated offer. In this test Rtx is enabled.
3072TEST_F(MediaSessionDescriptionFactoryTest,
3073 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
3074 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003075 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3076 RtpTransceiverDirection::kRecvOnly, kActive,
3077 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003078 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003079 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003080 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003081 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003082
3083 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003084 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003085 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003086 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003087
Steve Anton6fe1fba2018-12-11 10:15:23 -08003088 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003089 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003090 std::unique_ptr<SessionDescription> answer =
3091 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003092
3093 const VideoContentDescription* vcd =
3094 GetFirstVideoContentDescription(answer.get());
3095
3096 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003097 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3098 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003099
3100 EXPECT_EQ(expected_codecs, vcd->codecs());
3101
deadbeef67cf2c12016-04-13 10:07:16 -07003102 // Now, make sure we get same result (except for the order) if |f2_| creates
3103 // an updated offer even though the default payload types between |f1_| and
3104 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08003105 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003106 f2_.CreateOffer(opts, answer.get()));
3107 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003108 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003109 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3110
3111 const VideoContentDescription* updated_vcd =
3112 GetFirstVideoContentDescription(updated_answer.get());
3113
3114 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3115}
3116
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003117// Regression test for:
3118// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
3119// Existing codecs should always appear before new codecs in re-offers. But
3120// under a specific set of circumstances, the existing RTX codec was ending up
3121// added to the end of the list.
3122TEST_F(MediaSessionDescriptionFactoryTest,
3123 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
3124 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003125 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3126 RtpTransceiverDirection::kRecvOnly, kActive,
3127 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003128 // We specifically choose different preferred payload types for VP8 to
3129 // trigger the issue.
3130 cricket::VideoCodec vp8_offerer(100, "VP8");
3131 cricket::VideoCodec vp8_offerer_rtx =
3132 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
3133 cricket::VideoCodec vp8_answerer(110, "VP8");
3134 cricket::VideoCodec vp8_answerer_rtx =
3135 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
3136 cricket::VideoCodec vp9(120, "VP9");
3137 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
3138
3139 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
3140 // We also specifically cause the answerer to prefer VP9, such that if it
3141 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
3142 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
3143 vp8_answerer_rtx};
3144
Johannes Kron3e983682020-03-29 22:17:00 +02003145 f1_.set_video_codecs(f1_codecs, f1_codecs);
3146 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003147 std::vector<AudioCodec> audio_codecs;
3148 f1_.set_audio_codecs(audio_codecs, audio_codecs);
3149 f2_.set_audio_codecs(audio_codecs, audio_codecs);
3150
3151 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003152 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003153 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003154 std::unique_ptr<SessionDescription> answer =
3155 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003156
3157 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
3158 // But if the bug is triggered, RTX for VP8 ends up last.
3159 std::unique_ptr<SessionDescription> updated_offer(
3160 f2_.CreateOffer(opts, answer.get()));
3161
3162 const VideoContentDescription* vcd =
3163 GetFirstVideoContentDescription(updated_offer.get());
3164 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
3165 ASSERT_EQ(4u, codecs.size());
3166 EXPECT_EQ(vp8_offerer, codecs[0]);
3167 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
3168 EXPECT_EQ(vp9, codecs[2]);
3169 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003170}
3171
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003172// Create an updated offer that adds video after creating an audio only answer
3173// to the original offer. This test verifies that if a video codec and the RTX
3174// codec have the same default payload type as an audio codec that is already in
3175// use, the added codecs payload types are changed.
3176TEST_F(MediaSessionDescriptionFactoryTest,
3177 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
3178 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003179 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003180 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003181 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003182
3183 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003184 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3185 RtpTransceiverDirection::kRecvOnly, kActive,
3186 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003187
Steve Anton6fe1fba2018-12-11 10:15:23 -08003188 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3189 std::unique_ptr<SessionDescription> answer =
3190 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003191
3192 const AudioContentDescription* acd =
3193 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003194 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003195
3196 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
3197 // reference be the same as an audio codec that was negotiated in the
3198 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07003199 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08003200 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003201
3202 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3203 int used_pl_type = acd->codecs()[0].id;
3204 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003205 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003206 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003207
kwiberg31022942016-03-11 14:18:21 -08003208 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003209 f2_.CreateOffer(opts, answer.get()));
3210 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003211 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003212 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3213
3214 const AudioContentDescription* updated_acd =
3215 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003216 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003217
3218 const VideoContentDescription* updated_vcd =
3219 GetFirstVideoContentDescription(updated_answer.get());
3220
3221 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003222 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003223 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003224 EXPECT_NE(used_pl_type, new_h264_pl_type);
3225 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003226 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003227 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3228 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3229}
3230
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003231// Create an updated offer with RTX after creating an answer to an offer
3232// without RTX, and with different default payload types.
3233// Verify that the added RTX codec references the correct payload type.
3234TEST_F(MediaSessionDescriptionFactoryTest,
3235 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3236 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003237 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003238
3239 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3240 // This creates rtx for H264 with the payload type |f2_| uses.
3241 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003242 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003243
Steve Anton6fe1fba2018-12-11 10:15:23 -08003244 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003245 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003246 std::unique_ptr<SessionDescription> answer =
3247 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003248
3249 const VideoContentDescription* vcd =
3250 GetFirstVideoContentDescription(answer.get());
3251
3252 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3253 EXPECT_EQ(expected_codecs, vcd->codecs());
3254
3255 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
3256 // updated offer, even though the default payload types are different from
3257 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08003258 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003259 f2_.CreateOffer(opts, answer.get()));
3260 ASSERT_TRUE(updated_offer);
3261
3262 const VideoContentDescription* updated_vcd =
3263 GetFirstVideoContentDescription(updated_offer.get());
3264
3265 // New offer should attempt to add H263, and RTX for H264.
3266 expected_codecs.push_back(kVideoCodecs2[1]);
3267 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3268 &expected_codecs);
3269 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3270}
3271
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003272// Test that RTX is ignored when there is no associated payload type parameter.
3273TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3274 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003275 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3276 RtpTransceiverDirection::kRecvOnly, kActive,
3277 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003278 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003279 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003280 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003281 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003282
3283 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003284 // This creates RTX for H264 with the payload type |f2_| uses.
3285 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003286 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003287
Steve Anton6fe1fba2018-12-11 10:15:23 -08003288 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003289 ASSERT_TRUE(offer.get() != NULL);
3290 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3291 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3292 // is possible to test that that RTX is dropped when
3293 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003294 MediaContentDescription* media_desc =
3295 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3296 ASSERT_TRUE(media_desc);
3297 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003298 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003299 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003300 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003301 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003302 }
3303 }
3304 desc->set_codecs(codecs);
3305
Steve Anton6fe1fba2018-12-11 10:15:23 -08003306 std::unique_ptr<SessionDescription> answer =
3307 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003308
Steve Anton64b626b2019-01-28 17:25:26 -08003309 EXPECT_THAT(
3310 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3311 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003312}
3313
3314// Test that RTX will be filtered out in the answer if its associated payload
3315// type doesn't match the local value.
3316TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3317 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003318 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3319 RtpTransceiverDirection::kRecvOnly, kActive,
3320 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003321 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3322 // This creates RTX for H264 in sender.
3323 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003324 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003325
3326 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3327 // This creates RTX for H263 in receiver.
3328 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003329 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003330
Steve Anton6fe1fba2018-12-11 10:15:23 -08003331 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003332 ASSERT_TRUE(offer.get() != NULL);
3333 // Associated payload type doesn't match, therefore, RTX codec is removed in
3334 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003335 std::unique_ptr<SessionDescription> answer =
3336 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003337
Steve Anton64b626b2019-01-28 17:25:26 -08003338 EXPECT_THAT(
3339 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3340 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003341}
3342
3343// Test that when multiple RTX codecs are offered, only the matched RTX codec
3344// is added in the answer, and the unsupported RTX codec is filtered out.
3345TEST_F(MediaSessionDescriptionFactoryTest,
3346 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3347 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003348 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3349 RtpTransceiverDirection::kRecvOnly, kActive,
3350 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003351 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3352 // This creates RTX for H264-SVC in sender.
3353 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003354 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003355
3356 // This creates RTX for H264 in sender.
3357 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003358 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003359
3360 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3361 // This creates RTX for H264 in receiver.
3362 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003363 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003364
3365 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3366 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003367 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003368 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003369 std::unique_ptr<SessionDescription> answer =
3370 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003371 const VideoContentDescription* vcd =
3372 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003373 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3374 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3375 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003376
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003377 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003378}
3379
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003380// Test that after one RTX codec has been negotiated, a new offer can attempt
3381// to add another.
3382TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3383 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003384 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3385 RtpTransceiverDirection::kRecvOnly, kActive,
3386 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003387 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3388 // This creates RTX for H264 for the offerer.
3389 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003390 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003391
Steve Anton6fe1fba2018-12-11 10:15:23 -08003392 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003393 ASSERT_TRUE(offer);
3394 const VideoContentDescription* vcd =
3395 GetFirstVideoContentDescription(offer.get());
3396
3397 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3398 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3399 &expected_codecs);
3400 EXPECT_EQ(expected_codecs, vcd->codecs());
3401
3402 // Now, attempt to add RTX for H264-SVC.
3403 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003404 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003405
kwiberg31022942016-03-11 14:18:21 -08003406 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003407 f1_.CreateOffer(opts, offer.get()));
3408 ASSERT_TRUE(updated_offer);
3409 vcd = GetFirstVideoContentDescription(updated_offer.get());
3410
3411 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3412 &expected_codecs);
3413 EXPECT_EQ(expected_codecs, vcd->codecs());
3414}
3415
Noah Richards2e7a0982015-05-18 14:02:54 -07003416// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3417// generated for each simulcast ssrc and correctly grouped.
3418TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3419 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003420 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3421 RtpTransceiverDirection::kSendRecv, kActive,
3422 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003423 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003424 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3425 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003426
3427 // Use a single real codec, and then add RTX for it.
3428 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003429 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003430 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003431 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003432
3433 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3434 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003435 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003436 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003437 MediaContentDescription* media_desc =
3438 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3439 ASSERT_TRUE(media_desc);
3440 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003441 const StreamParamsVec& streams = desc->streams();
3442 // Single stream.
3443 ASSERT_EQ(1u, streams.size());
3444 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3445 EXPECT_EQ(6u, streams[0].ssrcs.size());
3446 // And should have a SIM group for the simulcast.
3447 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3448 // And a FID group for RTX.
3449 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003450 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003451 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3452 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003453 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003454 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3455 EXPECT_EQ(3u, fid_ssrcs.size());
3456}
3457
brandtr03d5fb12016-11-22 03:37:59 -08003458// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3459// together with a FEC-FR grouping.
3460TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3461 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003462 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3463 RtpTransceiverDirection::kSendRecv, kActive,
3464 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003465 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003466 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3467 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003468
3469 // Use a single real codec, and then add FlexFEC for it.
3470 std::vector<VideoCodec> f1_codecs;
3471 f1_codecs.push_back(VideoCodec(97, "H264"));
3472 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003473 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003474
3475 // Ensure that the offer has a single FlexFEC ssrc and that
3476 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003477 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003478 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003479 MediaContentDescription* media_desc =
3480 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3481 ASSERT_TRUE(media_desc);
3482 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003483 const StreamParamsVec& streams = desc->streams();
3484 // Single stream.
3485 ASSERT_EQ(1u, streams.size());
3486 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3487 EXPECT_EQ(2u, streams[0].ssrcs.size());
3488 // And should have a FEC-FR group for FlexFEC.
3489 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3490 std::vector<uint32_t> primary_ssrcs;
3491 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3492 ASSERT_EQ(1u, primary_ssrcs.size());
3493 uint32_t flexfec_ssrc;
3494 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3495 EXPECT_NE(flexfec_ssrc, 0u);
3496}
3497
3498// Test that FlexFEC is disabled for simulcast.
3499// TODO(brandtr): Remove this test when we support simulcast, either through
3500// multiple FlexfecSenders, or through multistream protection.
3501TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3502 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003503 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3504 RtpTransceiverDirection::kSendRecv, kActive,
3505 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003506 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003507 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3508 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003509
3510 // Use a single real codec, and then add FlexFEC for it.
3511 std::vector<VideoCodec> f1_codecs;
3512 f1_codecs.push_back(VideoCodec(97, "H264"));
3513 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003514 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003515
3516 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3517 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003518 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003519 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003520 MediaContentDescription* media_desc =
3521 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3522 ASSERT_TRUE(media_desc);
3523 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003524 const StreamParamsVec& streams = desc->streams();
3525 // Single stream.
3526 ASSERT_EQ(1u, streams.size());
3527 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3528 EXPECT_EQ(3u, streams[0].ssrcs.size());
3529 // And should have a SIM group for the simulcast.
3530 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3531 // And not a FEC-FR group for FlexFEC.
3532 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3533 std::vector<uint32_t> primary_ssrcs;
3534 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3535 EXPECT_EQ(3u, primary_ssrcs.size());
3536 for (uint32_t primary_ssrc : primary_ssrcs) {
3537 uint32_t flexfec_ssrc;
3538 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3539 }
3540}
3541
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003542// Create an updated offer after creating an answer to the original offer and
3543// verify that the RTP header extensions that were part of the original answer
3544// are not changed in the updated offer.
3545TEST_F(MediaSessionDescriptionFactoryTest,
3546 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3547 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003548 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003549
Markus Handell755c65d2020-06-24 01:06:10 +02003550 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3551 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003552 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell755c65d2020-06-24 01:06:10 +02003553 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3554 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003555 std::unique_ptr<SessionDescription> answer =
3556 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003557
Yves Gerey665174f2018-06-19 15:03:05 +02003558 EXPECT_EQ(
3559 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3560 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3561 EXPECT_EQ(
3562 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3563 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003564
kwiberg31022942016-03-11 14:18:21 -08003565 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003566 f2_.CreateOffer(opts, answer.get()));
3567
3568 // The expected RTP header extensions in the new offer are the resulting
3569 // extensions from the first offer/answer exchange plus the extensions only
3570 // |f2_| offer.
3571 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003572 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003573 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003574 kAudioRtpExtensionAnswer[0],
3575 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003576 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003577 };
3578
3579 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003580 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003581 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003582 kVideoRtpExtensionAnswer[0],
3583 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003584 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003585 };
3586
3587 const AudioContentDescription* updated_acd =
3588 GetFirstAudioContentDescription(updated_offer.get());
3589 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3590 updated_acd->rtp_header_extensions());
3591
3592 const VideoContentDescription* updated_vcd =
3593 GetFirstVideoContentDescription(updated_offer.get());
3594 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3595 updated_vcd->rtp_header_extensions());
3596}
3597
deadbeefa5b273a2015-08-20 17:30:13 -07003598// Verify that if the same RTP extension URI is used for audio and video, the
3599// same ID is used. Also verify that the ID isn't changed when creating an
3600// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003601TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003602 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003603 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003604
Markus Handell755c65d2020-06-24 01:06:10 +02003605 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3606 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003607 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003608
3609 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3610 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003611 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003612 kVideoRtpExtension3[0],
3613 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003614 };
3615
Yves Gerey665174f2018-06-19 15:03:05 +02003616 EXPECT_EQ(
3617 MAKE_VECTOR(kAudioRtpExtension3),
3618 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3619 EXPECT_EQ(
3620 MAKE_VECTOR(kExpectedVideoRtpExtension),
3621 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003622
3623 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003624 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003625 f1_.CreateOffer(opts, offer.get()));
3626
3627 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003628 GetFirstAudioContentDescription(updated_offer.get())
3629 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003630 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003631 GetFirstVideoContentDescription(updated_offer.get())
3632 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003633}
3634
jbauch5869f502017-06-29 12:31:36 -07003635// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3636TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3637 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003638 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003639
3640 f1_.set_enable_encrypted_rtp_header_extensions(true);
3641 f2_.set_enable_encrypted_rtp_header_extensions(true);
3642
Markus Handell755c65d2020-06-24 01:06:10 +02003643 SetAudioVideoRtpHeaderExtensions(
3644 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3645 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003646 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003647
3648 // The extensions that are shared between audio and video should use the same
3649 // id.
3650 const RtpExtension kExpectedVideoRtpExtension[] = {
3651 kVideoRtpExtension3ForEncryption[0],
3652 kAudioRtpExtension3ForEncryptionOffer[1],
3653 kAudioRtpExtension3ForEncryptionOffer[2],
3654 };
3655
Yves Gerey665174f2018-06-19 15:03:05 +02003656 EXPECT_EQ(
3657 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3658 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3659 EXPECT_EQ(
3660 MAKE_VECTOR(kExpectedVideoRtpExtension),
3661 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003662
3663 // Nothing should change when creating a new offer
3664 std::unique_ptr<SessionDescription> updated_offer(
3665 f1_.CreateOffer(opts, offer.get()));
3666
3667 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003668 GetFirstAudioContentDescription(updated_offer.get())
3669 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003670 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003671 GetFirstVideoContentDescription(updated_offer.get())
3672 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003673}
3674
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003675TEST(MediaSessionDescription, CopySessionDescription) {
3676 SessionDescription source;
3677 cricket::ContentGroup group(cricket::CN_AUDIO);
3678 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003679 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003680 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003681 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3682 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003683 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003684 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003685 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003686 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3687 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003688 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003689
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003690 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003691 ASSERT_TRUE(copy.get() != NULL);
3692 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3693 const ContentInfo* ac = copy->GetContentByName("audio");
3694 const ContentInfo* vc = copy->GetContentByName("video");
3695 ASSERT_TRUE(ac != NULL);
3696 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003697 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003698 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003699 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3700 EXPECT_EQ(1u, acd->first_ssrc());
3701
Steve Anton5adfafd2017-12-20 16:34:00 -08003702 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003703 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003704 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3705 EXPECT_EQ(2u, vcd->first_ssrc());
3706}
3707
3708// The below TestTransportInfoXXX tests create different offers/answers, and
3709// ensure the TransportInfo in the SessionDescription matches what we expect.
3710TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3711 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003712 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3713 RtpTransceiverDirection::kRecvOnly, kActive,
3714 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003715 TestTransportInfo(true, options, false);
3716}
3717
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003718TEST_F(MediaSessionDescriptionFactoryTest,
3719 TestTransportInfoOfferIceRenomination) {
3720 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003721 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3722 RtpTransceiverDirection::kRecvOnly, kActive,
3723 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003724 options.media_description_options[0]
3725 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003726 TestTransportInfo(true, options, false);
3727}
3728
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003729TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3730 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003731 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3732 RtpTransceiverDirection::kRecvOnly, kActive,
3733 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003734 TestTransportInfo(true, options, true);
3735}
3736
3737TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3738 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003739 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3740 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3741 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003742 TestTransportInfo(true, options, false);
3743}
3744
3745TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003746 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003747 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003748 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3749 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3750 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003751 TestTransportInfo(true, options, true);
3752}
3753
3754TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3755 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003756 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3757 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3758 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003759 options.bundle_enabled = true;
3760 TestTransportInfo(true, options, false);
3761}
3762
3763TEST_F(MediaSessionDescriptionFactoryTest,
3764 TestTransportInfoOfferBundleCurrent) {
3765 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003766 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3767 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3768 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003769 options.bundle_enabled = true;
3770 TestTransportInfo(true, options, true);
3771}
3772
3773TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3774 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003775 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3776 RtpTransceiverDirection::kRecvOnly, kActive,
3777 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003778 TestTransportInfo(false, options, false);
3779}
3780
3781TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003782 TestTransportInfoAnswerIceRenomination) {
3783 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003784 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3785 RtpTransceiverDirection::kRecvOnly, kActive,
3786 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003787 options.media_description_options[0]
3788 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003789 TestTransportInfo(false, options, false);
3790}
3791
3792TEST_F(MediaSessionDescriptionFactoryTest,
3793 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003794 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003795 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3796 RtpTransceiverDirection::kRecvOnly, kActive,
3797 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003798 TestTransportInfo(false, options, true);
3799}
3800
3801TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3802 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003803 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3804 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3805 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003806 TestTransportInfo(false, options, false);
3807}
3808
3809TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003810 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003811 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003812 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3813 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3814 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003815 TestTransportInfo(false, options, true);
3816}
3817
3818TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3819 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003820 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3821 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3822 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003823 options.bundle_enabled = true;
3824 TestTransportInfo(false, options, false);
3825}
3826
3827TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003828 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003829 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003830 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3831 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3832 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003833 options.bundle_enabled = true;
3834 TestTransportInfo(false, options, true);
3835}
3836
3837// Create an offer with bundle enabled and verify the crypto parameters are
3838// the common set of the available cryptos.
3839TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3840 TestCryptoWithBundle(true);
3841}
3842
3843// Create an answer with bundle enabled and verify the crypto parameters are
3844// the common set of the available cryptos.
3845TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3846 TestCryptoWithBundle(false);
3847}
3848
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003849// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3850// DTLS is not enabled locally.
3851TEST_F(MediaSessionDescriptionFactoryTest,
3852 TestOfferDtlsSavpfWithoutDtlsFailed) {
3853 f1_.set_secure(SEC_ENABLED);
3854 f2_.set_secure(SEC_ENABLED);
3855 tdf1_.set_secure(SEC_DISABLED);
3856 tdf2_.set_secure(SEC_DISABLED);
3857
Steve Anton6fe1fba2018-12-11 10:15:23 -08003858 std::unique_ptr<SessionDescription> offer =
3859 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003860 ASSERT_TRUE(offer.get() != NULL);
3861 ContentInfo* offer_content = offer->GetContentByName("audio");
3862 ASSERT_TRUE(offer_content != NULL);
3863 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003864 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003865 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3866
Steve Anton6fe1fba2018-12-11 10:15:23 -08003867 std::unique_ptr<SessionDescription> answer =
3868 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003869 ASSERT_TRUE(answer != NULL);
3870 ContentInfo* answer_content = answer->GetContentByName("audio");
3871 ASSERT_TRUE(answer_content != NULL);
3872
3873 ASSERT_TRUE(answer_content->rejected);
3874}
3875
3876// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3877// UDP/TLS/RTP/SAVPF.
3878TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3879 f1_.set_secure(SEC_ENABLED);
3880 f2_.set_secure(SEC_ENABLED);
3881 tdf1_.set_secure(SEC_ENABLED);
3882 tdf2_.set_secure(SEC_ENABLED);
3883
Steve Anton6fe1fba2018-12-11 10:15:23 -08003884 std::unique_ptr<SessionDescription> offer =
3885 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003886 ASSERT_TRUE(offer.get() != NULL);
3887 ContentInfo* offer_content = offer->GetContentByName("audio");
3888 ASSERT_TRUE(offer_content != NULL);
3889 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003890 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003891 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3892
Steve Anton6fe1fba2018-12-11 10:15:23 -08003893 std::unique_ptr<SessionDescription> answer =
3894 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003895 ASSERT_TRUE(answer != NULL);
3896
3897 const ContentInfo* answer_content = answer->GetContentByName("audio");
3898 ASSERT_TRUE(answer_content != NULL);
3899 ASSERT_FALSE(answer_content->rejected);
3900
3901 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003902 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003903 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003904}
3905
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003906// Test that we include both SDES and DTLS in the offer, but only include SDES
3907// in the answer if DTLS isn't negotiated.
3908TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3909 f1_.set_secure(SEC_ENABLED);
3910 f2_.set_secure(SEC_ENABLED);
3911 tdf1_.set_secure(SEC_ENABLED);
3912 tdf2_.set_secure(SEC_DISABLED);
3913 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003914 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003915 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003916 const cricket::MediaContentDescription* audio_media_desc;
3917 const cricket::MediaContentDescription* video_media_desc;
3918 const cricket::TransportDescription* audio_trans_desc;
3919 const cricket::TransportDescription* video_trans_desc;
3920
3921 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003922 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003923 ASSERT_TRUE(offer.get() != NULL);
3924
Steve Antonb1c1de12017-12-21 15:14:30 -08003925 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003926 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003927 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003928 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003929 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003930 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3931
3932 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3933 ASSERT_TRUE(audio_trans_desc != NULL);
3934 video_trans_desc = offer->GetTransportDescriptionByName("video");
3935 ASSERT_TRUE(video_trans_desc != NULL);
3936 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3937 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3938
3939 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003940 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003941 ASSERT_TRUE(answer.get() != NULL);
3942
Steve Antonb1c1de12017-12-21 15:14:30 -08003943 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003944 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003945 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003946 ASSERT_TRUE(video_media_desc != NULL);
3947 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3948 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3949
3950 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3951 ASSERT_TRUE(audio_trans_desc != NULL);
3952 video_trans_desc = answer->GetTransportDescriptionByName("video");
3953 ASSERT_TRUE(video_trans_desc != NULL);
3954 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3955 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3956
3957 // Enable DTLS; the answer should now only have DTLS support.
3958 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003959 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003960 ASSERT_TRUE(answer.get() != NULL);
3961
Steve Antonb1c1de12017-12-21 15:14:30 -08003962 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003963 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003964 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003965 ASSERT_TRUE(video_media_desc != NULL);
3966 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3967 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003968 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3969 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003970
3971 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3972 ASSERT_TRUE(audio_trans_desc != NULL);
3973 video_trans_desc = answer->GetTransportDescriptionByName("video");
3974 ASSERT_TRUE(video_trans_desc != NULL);
3975 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3976 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003977
3978 // Try creating offer again. DTLS enabled now, crypto's should be empty
3979 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003980 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003981 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003982 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003983 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003984 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003985 ASSERT_TRUE(video_media_desc != NULL);
3986 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3987 EXPECT_TRUE(video_media_desc->cryptos().empty());
3988
3989 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3990 ASSERT_TRUE(audio_trans_desc != NULL);
3991 video_trans_desc = offer->GetTransportDescriptionByName("video");
3992 ASSERT_TRUE(video_trans_desc != NULL);
3993 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3994 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003995}
3996
3997// Test that an answer can't be created if cryptos are required but the offer is
3998// unsecure.
3999TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004000 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004001 f1_.set_secure(SEC_DISABLED);
4002 tdf1_.set_secure(SEC_DISABLED);
4003 f2_.set_secure(SEC_REQUIRED);
4004 tdf1_.set_secure(SEC_ENABLED);
4005
Steve Anton6fe1fba2018-12-11 10:15:23 -08004006 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004007 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004008 std::unique_ptr<SessionDescription> answer =
4009 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004010 EXPECT_TRUE(answer.get() == NULL);
4011}
4012
4013// Test that we accept a DTLS offer without SDES and create an appropriate
4014// answer.
4015TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
4016 f1_.set_secure(SEC_DISABLED);
4017 f2_.set_secure(SEC_ENABLED);
4018 tdf1_.set_secure(SEC_ENABLED);
4019 tdf2_.set_secure(SEC_ENABLED);
4020 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004021 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
4022 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
4023 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004024
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004025 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004026 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004027 ASSERT_TRUE(offer.get() != NULL);
4028
4029 const AudioContentDescription* audio_offer =
4030 GetFirstAudioContentDescription(offer.get());
4031 ASSERT_TRUE(audio_offer->cryptos().empty());
4032 const VideoContentDescription* video_offer =
4033 GetFirstVideoContentDescription(offer.get());
4034 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004035 const RtpDataContentDescription* data_offer =
4036 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004037 ASSERT_TRUE(data_offer->cryptos().empty());
4038
4039 const cricket::TransportDescription* audio_offer_trans_desc =
4040 offer->GetTransportDescriptionByName("audio");
4041 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
4042 const cricket::TransportDescription* video_offer_trans_desc =
4043 offer->GetTransportDescriptionByName("video");
4044 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
4045 const cricket::TransportDescription* data_offer_trans_desc =
4046 offer->GetTransportDescriptionByName("data");
4047 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
4048
4049 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004050 std::unique_ptr<SessionDescription> answer =
4051 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004052 ASSERT_TRUE(answer.get() != NULL);
4053
4054 const cricket::TransportDescription* audio_answer_trans_desc =
4055 answer->GetTransportDescriptionByName("audio");
4056 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
4057 const cricket::TransportDescription* video_answer_trans_desc =
4058 answer->GetTransportDescriptionByName("video");
4059 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
4060 const cricket::TransportDescription* data_answer_trans_desc =
4061 answer->GetTransportDescriptionByName("data");
4062 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
4063}
4064
4065// Verifies if vad_enabled option is set to false, CN codecs are not present in
4066// offer or answer.
4067TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
4068 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004069 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004070 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004071 ASSERT_TRUE(offer.get() != NULL);
4072 const ContentInfo* audio_content = offer->GetContentByName("audio");
4073 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
4074
4075 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08004076 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004077 ASSERT_TRUE(offer.get() != NULL);
4078 audio_content = offer->GetContentByName("audio");
4079 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08004080 std::unique_ptr<SessionDescription> answer =
4081 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004082 ASSERT_TRUE(answer.get() != NULL);
4083 audio_content = answer->GetContentByName("audio");
4084 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
4085}
deadbeef44f08192015-12-15 16:20:09 -08004086
zhihuang1c378ed2017-08-17 14:10:50 -07004087// Test that the generated MIDs match the existing offer.
4088TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08004089 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004090 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
4091 RtpTransceiverDirection::kRecvOnly, kActive,
4092 &opts);
4093 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
4094 RtpTransceiverDirection::kRecvOnly, kActive,
4095 &opts);
deadbeef44f08192015-12-15 16:20:09 -08004096 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004097 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
4098 RtpTransceiverDirection::kSendRecv, kActive,
4099 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004100 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004101 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08004102 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08004103 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07004104
deadbeef44f08192015-12-15 16:20:09 -08004105 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
4106 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
4107 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
4108 ASSERT_TRUE(audio_content != nullptr);
4109 ASSERT_TRUE(video_content != nullptr);
4110 ASSERT_TRUE(data_content != nullptr);
4111 EXPECT_EQ("audio_modified", audio_content->name);
4112 EXPECT_EQ("video_modified", video_content->name);
4113 EXPECT_EQ("data_modified", data_content->name);
4114}
zhihuangcf5b37c2016-05-05 11:44:35 -07004115
zhihuang1c378ed2017-08-17 14:10:50 -07004116// The following tests verify that the unified plan SDP is supported.
4117// Test that we can create an offer with multiple media sections of same media
4118// type.
4119TEST_F(MediaSessionDescriptionFactoryTest,
4120 CreateOfferWithMultipleAVMediaSections) {
4121 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004122 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4123 RtpTransceiverDirection::kSendRecv, kActive,
4124 &opts);
4125 AttachSenderToMediaDescriptionOptions(
4126 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004127
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004128 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4129 RtpTransceiverDirection::kSendRecv, kActive,
4130 &opts);
4131 AttachSenderToMediaDescriptionOptions(
4132 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004133
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004134 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4135 RtpTransceiverDirection::kSendRecv, kActive,
4136 &opts);
4137 AttachSenderToMediaDescriptionOptions(
4138 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004139
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004140 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4141 RtpTransceiverDirection::kSendRecv, kActive,
4142 &opts);
4143 AttachSenderToMediaDescriptionOptions(
4144 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004145 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004146 ASSERT_TRUE(offer);
4147
4148 ASSERT_EQ(4u, offer->contents().size());
4149 EXPECT_FALSE(offer->contents()[0].rejected);
4150 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004151 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004152 ASSERT_EQ(1u, acd->streams().size());
4153 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004154 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004155
4156 EXPECT_FALSE(offer->contents()[1].rejected);
4157 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004158 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004159 ASSERT_EQ(1u, vcd->streams().size());
4160 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004161 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004162
4163 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004164 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004165 ASSERT_EQ(1u, acd->streams().size());
4166 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004167 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004168
4169 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004170 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004171 ASSERT_EQ(1u, vcd->streams().size());
4172 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004173 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004174}
4175
4176// Test that we can create an answer with multiple media sections of same media
4177// type.
4178TEST_F(MediaSessionDescriptionFactoryTest,
4179 CreateAnswerWithMultipleAVMediaSections) {
4180 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004181 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4182 RtpTransceiverDirection::kSendRecv, kActive,
4183 &opts);
4184 AttachSenderToMediaDescriptionOptions(
4185 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004186
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004187 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4188 RtpTransceiverDirection::kSendRecv, kActive,
4189 &opts);
4190 AttachSenderToMediaDescriptionOptions(
4191 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004192
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004193 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4194 RtpTransceiverDirection::kSendRecv, kActive,
4195 &opts);
4196 AttachSenderToMediaDescriptionOptions(
4197 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004198
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004199 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4200 RtpTransceiverDirection::kSendRecv, kActive,
4201 &opts);
4202 AttachSenderToMediaDescriptionOptions(
4203 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004204
Steve Anton6fe1fba2018-12-11 10:15:23 -08004205 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004206 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004207 std::unique_ptr<SessionDescription> answer =
4208 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004209
4210 ASSERT_EQ(4u, answer->contents().size());
4211 EXPECT_FALSE(answer->contents()[0].rejected);
4212 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004213 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004214 ASSERT_EQ(1u, acd->streams().size());
4215 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004216 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004217
4218 EXPECT_FALSE(answer->contents()[1].rejected);
4219 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004220 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004221 ASSERT_EQ(1u, vcd->streams().size());
4222 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004223 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004224
4225 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004226 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004227 ASSERT_EQ(1u, acd->streams().size());
4228 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004229 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004230
4231 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004232 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004233 ASSERT_EQ(1u, vcd->streams().size());
4234 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004235 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004236}
4237
4238// Test that the media section will be rejected in offer if the corresponding
4239// MediaDescriptionOptions is stopped by the offerer.
4240TEST_F(MediaSessionDescriptionFactoryTest,
4241 CreateOfferWithMediaSectionStoppedByOfferer) {
4242 // Create an offer with two audio sections and one of them is stopped.
4243 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004244 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4245 RtpTransceiverDirection::kSendRecv, kActive,
4246 &offer_opts);
4247 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4248 RtpTransceiverDirection::kInactive, kStopped,
4249 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004250 std::unique_ptr<SessionDescription> offer =
4251 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004252 ASSERT_TRUE(offer);
4253 ASSERT_EQ(2u, offer->contents().size());
4254 EXPECT_FALSE(offer->contents()[0].rejected);
4255 EXPECT_TRUE(offer->contents()[1].rejected);
4256}
4257
4258// Test that the media section will be rejected in answer if the corresponding
4259// MediaDescriptionOptions is stopped by the offerer.
4260TEST_F(MediaSessionDescriptionFactoryTest,
4261 CreateAnswerWithMediaSectionStoppedByOfferer) {
4262 // Create an offer with two audio sections and one of them is stopped.
4263 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004264 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4265 RtpTransceiverDirection::kSendRecv, kActive,
4266 &offer_opts);
4267 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4268 RtpTransceiverDirection::kInactive, kStopped,
4269 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004270 std::unique_ptr<SessionDescription> offer =
4271 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004272 ASSERT_TRUE(offer);
4273 ASSERT_EQ(2u, offer->contents().size());
4274 EXPECT_FALSE(offer->contents()[0].rejected);
4275 EXPECT_TRUE(offer->contents()[1].rejected);
4276
4277 // Create an answer based on the offer.
4278 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004279 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4280 RtpTransceiverDirection::kSendRecv, kActive,
4281 &answer_opts);
4282 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4283 RtpTransceiverDirection::kSendRecv, kActive,
4284 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004285 std::unique_ptr<SessionDescription> answer =
4286 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004287 ASSERT_EQ(2u, answer->contents().size());
4288 EXPECT_FALSE(answer->contents()[0].rejected);
4289 EXPECT_TRUE(answer->contents()[1].rejected);
4290}
4291
4292// Test that the media section will be rejected in answer if the corresponding
4293// MediaDescriptionOptions is stopped by the answerer.
4294TEST_F(MediaSessionDescriptionFactoryTest,
4295 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4296 // Create an offer with two audio sections.
4297 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004298 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4299 RtpTransceiverDirection::kSendRecv, kActive,
4300 &offer_opts);
4301 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4302 RtpTransceiverDirection::kSendRecv, kActive,
4303 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004304 std::unique_ptr<SessionDescription> offer =
4305 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004306 ASSERT_TRUE(offer);
4307 ASSERT_EQ(2u, offer->contents().size());
4308 ASSERT_FALSE(offer->contents()[0].rejected);
4309 ASSERT_FALSE(offer->contents()[1].rejected);
4310
4311 // The answerer rejects one of the audio sections.
4312 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004313 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4314 RtpTransceiverDirection::kSendRecv, kActive,
4315 &answer_opts);
4316 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4317 RtpTransceiverDirection::kInactive, kStopped,
4318 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004319 std::unique_ptr<SessionDescription> answer =
4320 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004321 ASSERT_EQ(2u, answer->contents().size());
4322 EXPECT_FALSE(answer->contents()[0].rejected);
4323 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004324
4325 // The TransportInfo of the rejected m= section is expected to be added in the
4326 // answer.
4327 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004328}
4329
4330// Test the generated media sections has the same order of the
4331// corresponding MediaDescriptionOptions.
4332TEST_F(MediaSessionDescriptionFactoryTest,
4333 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4334 MediaSessionOptions opts;
4335 // This tests put video section first because normally audio comes first by
4336 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004337 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4338 RtpTransceiverDirection::kSendRecv, kActive,
4339 &opts);
4340 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4341 RtpTransceiverDirection::kSendRecv, kActive,
4342 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004343 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004344
4345 ASSERT_TRUE(offer);
4346 ASSERT_EQ(2u, offer->contents().size());
4347 EXPECT_EQ("video", offer->contents()[0].name);
4348 EXPECT_EQ("audio", offer->contents()[1].name);
4349}
4350
4351// Test that different media sections using the same codec have same payload
4352// type.
4353TEST_F(MediaSessionDescriptionFactoryTest,
4354 PayloadTypesSharedByMediaSectionsOfSameType) {
4355 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004356 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4357 RtpTransceiverDirection::kSendRecv, kActive,
4358 &opts);
4359 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4360 RtpTransceiverDirection::kSendRecv, kActive,
4361 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004362 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004363 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004364 ASSERT_TRUE(offer);
4365 ASSERT_EQ(2u, offer->contents().size());
4366 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004367 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004368 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004369 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004370 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4371 ASSERT_EQ(2u, vcd1->codecs().size());
4372 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4373 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4374 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4375 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4376
4377 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004378 std::unique_ptr<SessionDescription> answer =
4379 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004380 ASSERT_TRUE(answer);
4381 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004382 vcd1 = answer->contents()[0].media_description()->as_video();
4383 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004384 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4385 ASSERT_EQ(1u, vcd1->codecs().size());
4386 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4387 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4388}
4389
4390// Test that the codec preference order per media section is respected in
4391// subsequent offer.
4392TEST_F(MediaSessionDescriptionFactoryTest,
4393 CreateOfferRespectsCodecPreferenceOrder) {
4394 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004395 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4396 RtpTransceiverDirection::kSendRecv, kActive,
4397 &opts);
4398 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4399 RtpTransceiverDirection::kSendRecv, kActive,
4400 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004401 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004402 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004403 ASSERT_TRUE(offer);
4404 ASSERT_EQ(2u, offer->contents().size());
4405 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004406 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004407 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004408 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004409 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4410 EXPECT_EQ(video_codecs, vcd1->codecs());
4411 EXPECT_EQ(video_codecs, vcd2->codecs());
4412
4413 // Change the codec preference of the first video section and create a
4414 // follow-up offer.
4415 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4416 vcd1->set_codecs(video_codecs_reverse);
4417 std::unique_ptr<SessionDescription> updated_offer(
4418 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004419 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4420 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004421 // The video codec preference order should be respected.
4422 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4423 EXPECT_EQ(video_codecs, vcd2->codecs());
4424}
4425
4426// Test that the codec preference order per media section is respected in
4427// the answer.
4428TEST_F(MediaSessionDescriptionFactoryTest,
4429 CreateAnswerRespectsCodecPreferenceOrder) {
4430 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004431 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4432 RtpTransceiverDirection::kSendRecv, kActive,
4433 &opts);
4434 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4435 RtpTransceiverDirection::kSendRecv, kActive,
4436 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004437 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004438 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004439 ASSERT_TRUE(offer);
4440 ASSERT_EQ(2u, offer->contents().size());
4441 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004442 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004443 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004444 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004445 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4446 EXPECT_EQ(video_codecs, vcd1->codecs());
4447 EXPECT_EQ(video_codecs, vcd2->codecs());
4448
4449 // Change the codec preference of the first video section and create an
4450 // answer.
4451 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4452 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004453 std::unique_ptr<SessionDescription> answer =
4454 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004455 vcd1 = answer->contents()[0].media_description()->as_video();
4456 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004457 // The video codec preference order should be respected.
4458 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4459 EXPECT_EQ(video_codecs, vcd2->codecs());
4460}
4461
Zhi Huang6f367472017-11-22 13:20:02 -08004462// Test that when creating an answer, the codecs use local parameters instead of
4463// the remote ones.
4464TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4465 const std::string audio_param_name = "audio_param";
4466 const std::string audio_value1 = "audio_v1";
4467 const std::string audio_value2 = "audio_v2";
4468 const std::string video_param_name = "video_param";
4469 const std::string video_value1 = "video_v1";
4470 const std::string video_value2 = "video_v2";
4471
4472 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4473 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4474 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4475 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4476
4477 // Set the parameters for codecs.
4478 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4479 video_codecs1[0].SetParam(video_param_name, video_value1);
4480 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4481 video_codecs2[0].SetParam(video_param_name, video_value2);
4482
4483 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004484 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004485 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004486 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004487
4488 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004489 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4490 RtpTransceiverDirection::kSendRecv, kActive,
4491 &opts);
4492 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4493 RtpTransceiverDirection::kSendRecv, kActive,
4494 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004495
Steve Anton6fe1fba2018-12-11 10:15:23 -08004496 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004497 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004498 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4499 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004500 std::string value;
4501 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4502 EXPECT_EQ(audio_value1, value);
4503 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4504 EXPECT_EQ(video_value1, value);
4505
Steve Anton6fe1fba2018-12-11 10:15:23 -08004506 std::unique_ptr<SessionDescription> answer =
4507 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004508 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004509 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4510 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004511 // Use the parameters from the local codecs.
4512 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4513 EXPECT_EQ(audio_value2, value);
4514 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4515 EXPECT_EQ(video_value2, value);
4516}
4517
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004518// Test that matching packetization-mode is part of the criteria for matching
4519// H264 codecs (in addition to profile-level-id). Previously, this was not the
4520// case, so the first H264 codec with the same profile-level-id would match and
4521// the payload type in the answer would be incorrect.
4522// This is a regression test for bugs.webrtc.org/8808
4523TEST_F(MediaSessionDescriptionFactoryTest,
4524 H264MatchCriteriaIncludesPacketizationMode) {
4525 // Create two H264 codecs with the same profile level ID and different
4526 // packetization modes.
4527 VideoCodec h264_pm0(96, "H264");
4528 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4529 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4530 VideoCodec h264_pm1(97, "H264");
4531 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4532 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4533
4534 // Offerer will send both codecs, answerer should choose the one with matching
4535 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004536 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4537 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004538
4539 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004540 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4541 RtpTransceiverDirection::kSendRecv, kActive,
4542 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004543
Steve Anton6fe1fba2018-12-11 10:15:23 -08004544 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004545 ASSERT_TRUE(offer);
4546
Steve Anton6fe1fba2018-12-11 10:15:23 -08004547 std::unique_ptr<SessionDescription> answer =
4548 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004549 ASSERT_TRUE(answer);
4550
4551 // Answer should have one negotiated codec with packetization-mode=1 using the
4552 // offered payload type.
4553 ASSERT_EQ(1u, answer->contents().size());
4554 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4555 ASSERT_EQ(1u, answer_vcd->codecs().size());
4556 auto answer_codec = answer_vcd->codecs()[0];
4557 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4558}
4559
zhihuangcf5b37c2016-05-05 11:44:35 -07004560class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4561 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004562 MediaProtocolTest()
4563 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004564 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4565 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004566 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4567 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004568 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004569 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4570 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004571 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4572 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004573 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004574 f1_.set_secure(SEC_ENABLED);
4575 f2_.set_secure(SEC_ENABLED);
4576 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004577 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004578 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004579 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004580 tdf1_.set_secure(SEC_ENABLED);
4581 tdf2_.set_secure(SEC_ENABLED);
4582 }
4583
4584 protected:
4585 MediaSessionDescriptionFactory f1_;
4586 MediaSessionDescriptionFactory f2_;
4587 TransportDescriptionFactory tdf1_;
4588 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004589 UniqueRandomIdGenerator ssrc_generator1;
4590 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004591};
4592
4593TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4594 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004595 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004596 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004597 ASSERT_TRUE(offer.get() != nullptr);
4598 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004599 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004600 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004601 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004602 std::unique_ptr<SessionDescription> answer =
4603 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004604 const ContentInfo* ac = answer->GetContentByName("audio");
4605 const ContentInfo* vc = answer->GetContentByName("video");
4606 ASSERT_TRUE(ac != nullptr);
4607 ASSERT_TRUE(vc != nullptr);
4608 EXPECT_FALSE(ac->rejected); // the offer is accepted
4609 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004610 const AudioContentDescription* acd = ac->media_description()->as_audio();
4611 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004612 EXPECT_EQ(GetParam(), acd->protocol());
4613 EXPECT_EQ(GetParam(), vcd->protocol());
4614}
4615
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004616INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4617 MediaProtocolTest,
4618 ::testing::ValuesIn(kMediaProtocols));
4619INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4620 MediaProtocolTest,
4621 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004622
4623TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4624 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004625 UniqueRandomIdGenerator ssrc_generator;
4626 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004627 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4628 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4629
4630 // The merged list of codecs should contain any send codecs that are also
4631 // nominally in the recieve codecs list. Payload types should be picked from
4632 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4633 // (set to 1). This equals what happens when the send codecs are used in an
4634 // offer and the receive codecs are used in the following answer.
4635 const std::vector<AudioCodec> sendrecv_codecs =
4636 MAKE_VECTOR(kAudioCodecsAnswer);
4637 const std::vector<AudioCodec> no_codecs;
4638
4639 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4640 << "Please don't change shared test data!";
4641 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4642 << "Please don't change shared test data!";
4643 // Alter iLBC send codec to have zero channels, to test that that is handled
4644 // properly.
4645 send_codecs[1].channels = 0;
4646
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004647 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004648 // are handled properly.
4649 recv_codecs[2].name = "ilbc";
4650
4651 // Test proper merge
4652 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004653 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4654 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4655 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004656
4657 // Test empty send codecs list
4658 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004659 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4660 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4661 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004662
4663 // Test empty recv codecs list
4664 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004665 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4666 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4667 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004668
4669 // Test all empty codec lists
4670 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004671 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4672 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4673 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004674}
4675
4676namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004677// Compare the two vectors of codecs ignoring the payload type.
4678template <class Codec>
4679bool CodecsMatch(const std::vector<Codec>& codecs1,
4680 const std::vector<Codec>& codecs2) {
4681 if (codecs1.size() != codecs2.size()) {
4682 return false;
4683 }
4684
4685 for (size_t i = 0; i < codecs1.size(); ++i) {
4686 if (!codecs1[i].Matches(codecs2[i])) {
4687 return false;
4688 }
4689 }
4690 return true;
4691}
4692
Steve Anton4e70a722017-11-28 14:57:10 -08004693void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004694 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004695 UniqueRandomIdGenerator ssrc_generator;
4696 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004697 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4698 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4699 const std::vector<AudioCodec> sendrecv_codecs =
4700 MAKE_VECTOR(kAudioCodecsAnswer);
4701 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004702
4703 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004704 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4705 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004706
Steve Anton4e70a722017-11-28 14:57:10 -08004707 if (direction == RtpTransceiverDirection::kSendRecv ||
4708 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004709 AttachSenderToMediaDescriptionOptions(
4710 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004711 }
ossu075af922016-06-14 03:29:38 -07004712
Steve Anton6fe1fba2018-12-11 10:15:23 -08004713 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004714 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004715 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004716
4717 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004718 // that the codecs put in are right. This happens when we neither want to
4719 // send nor receive audio. The checks are still in place if at some point
4720 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004721 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004722 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004723 // sendrecv and inactive should both present lists as if the channel was
4724 // to be used for sending and receiving. Inactive essentially means it
4725 // might eventually be used anything, but we don't know more at this
4726 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004727 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004728 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004729 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004730 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004731 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004732 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004733 }
4734 }
4735}
4736
4737static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004738 AudioCodec(0, "codec0", 16000, -1, 1),
4739 AudioCodec(1, "codec1", 8000, 13300, 1),
4740 AudioCodec(2, "codec2", 8000, 64000, 1),
4741 AudioCodec(3, "codec3", 8000, 64000, 1),
4742 AudioCodec(4, "codec4", 8000, 0, 2),
4743 AudioCodec(5, "codec5", 32000, 0, 1),
4744 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004745
zhihuang1c378ed2017-08-17 14:10:50 -07004746/* The codecs groups below are chosen as per the matrix below. The objective
4747 * is to have different sets of codecs in the inputs, to get unique sets of
4748 * codecs after negotiation, depending on offer and answer communication
4749 * directions. One-way directions in the offer should either result in the
4750 * opposite direction in the answer, or an inactive answer. Regardless, the
4751 * choice of codecs should be as if the answer contained the opposite
4752 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004753 *
4754 * | Offer | Answer | Result
4755 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4756 * 0 | x - - | - x - | x - - - -
4757 * 1 | x x x | - x - | x - - x -
4758 * 2 | - x - | x - - | - x - - -
4759 * 3 | x x x | x - - | - x x - -
4760 * 4 | - x - | x x x | - x - - -
4761 * 5 | x - - | x x x | x - - - -
4762 * 6 | x x x | x x x | x x x x x
4763 */
4764// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004765static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4766static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004767// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4768// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004769static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4770static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004771// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004772static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4773static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4774static const int kResultSendrecv_SendCodecs[] = {3, 6};
4775static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4776static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004777
4778template <typename T, int IDXS>
4779std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4780 std::vector<T> out;
4781 out.reserve(IDXS);
4782 for (int idx : indices)
4783 out.push_back(array[idx]);
4784
4785 return out;
4786}
4787
Steve Anton4e70a722017-11-28 14:57:10 -08004788void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4789 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004790 bool add_legacy_stream) {
4791 TransportDescriptionFactory offer_tdf;
4792 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004793 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4794 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4795 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004796 offer_factory.set_audio_codecs(
4797 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4798 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4799 answer_factory.set_audio_codecs(
4800 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4801 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4802
ossu075af922016-06-14 03:29:38 -07004803 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004804 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4805 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004806
Steve Anton4e70a722017-11-28 14:57:10 -08004807 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004808 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4809 kAudioTrack1, {kMediaStream1}, 1,
4810 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004811 }
4812
Steve Anton6fe1fba2018-12-11 10:15:23 -08004813 std::unique_ptr<SessionDescription> offer =
4814 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004815 ASSERT_TRUE(offer.get() != NULL);
4816
4817 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004818 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4819 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004820
Steve Anton4e70a722017-11-28 14:57:10 -08004821 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004822 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4823 kAudioTrack1, {kMediaStream1}, 1,
4824 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004825 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004826 std::unique_ptr<SessionDescription> answer =
4827 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004828 const ContentInfo* ac = answer->GetContentByName("audio");
4829
zhihuang1c378ed2017-08-17 14:10:50 -07004830 // If the factory didn't add any audio content to the answer, we cannot
4831 // check that the codecs put in are right. This happens when we neither want
4832 // to send nor receive audio. The checks are still in place if at some point
4833 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004834 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004835 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4836 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004837
ossu075af922016-06-14 03:29:38 -07004838 std::vector<AudioCodec> target_codecs;
4839 // For offers with sendrecv or inactive, we should never reply with more
4840 // codecs than offered, with these codec sets.
4841 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004842 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004843 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4844 kResultSendrecv_SendrecvCodecs);
4845 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004846 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004847 target_codecs =
4848 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004849 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004850 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004851 target_codecs =
4852 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004853 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004854 case RtpTransceiverDirection::kSendRecv:
4855 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004856 target_codecs =
4857 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004858 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004859 target_codecs =
4860 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004861 } else {
4862 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4863 kResultSendrecv_SendrecvCodecs);
4864 }
4865 break;
Harald Alvestrand6060df52020-08-11 09:54:02 +02004866 case RtpTransceiverDirection::kStopped:
4867 // This does not happen in any current test.
Markus Handell45c104b2020-03-11 10:51:13 +01004868 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004869 }
4870
zhihuang1c378ed2017-08-17 14:10:50 -07004871 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004872 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004873 bool first = true;
4874 os << "{";
4875 for (const auto& c : codecs) {
4876 os << (first ? " " : ", ") << c.id;
4877 first = false;
4878 }
4879 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004880 return os.Release();
ossu075af922016-06-14 03:29:38 -07004881 };
4882
4883 EXPECT_TRUE(acd->codecs() == target_codecs)
4884 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004885 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4886 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004887 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004888 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4889 << "; got: "
4890 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004891 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004892 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004893 << "Only inactive offers are allowed to not generate any audio "
4894 "content";
ossu075af922016-06-14 03:29:38 -07004895 }
4896}
brandtr03d5fb12016-11-22 03:37:59 -08004897
4898} // namespace
ossu075af922016-06-14 03:29:38 -07004899
4900class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004901 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004902
4903TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004904 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004905}
4906
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004907INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4908 AudioCodecsOfferTest,
4909 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4910 RtpTransceiverDirection::kRecvOnly,
4911 RtpTransceiverDirection::kSendRecv,
4912 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004913
4914class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004915 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4916 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004917 bool>> {};
ossu075af922016-06-14 03:29:38 -07004918
4919TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004920 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4921 ::testing::get<1>(GetParam()),
4922 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004923}
4924
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004925INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004926 MediaSessionDescriptionFactoryTest,
4927 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004928 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4929 RtpTransceiverDirection::kRecvOnly,
4930 RtpTransceiverDirection::kSendRecv,
4931 RtpTransceiverDirection::kInactive),
4932 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4933 RtpTransceiverDirection::kRecvOnly,
4934 RtpTransceiverDirection::kSendRecv,
4935 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004936 ::testing::Bool()));