blob: 654284ac509b12c12da2e7958e48a215241c7ac7 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/media_session.h"
12
Amit Hilbuch77938e62018-12-21 09:23:38 -080013#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080014#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <string>
Harald Alvestrand1716d392019-06-03 20:35:45 +020016#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <vector>
18
Steve Anton64b626b2019-01-28 17:25:26 -080019#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080020#include "absl/memory/memory.h"
Mirko Bonadei57cabed2020-04-01 12:03:11 +020021#include "absl/strings/match.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020024#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "p2p/base/p2p_constants.h"
26#include "p2p/base/transport_description.h"
27#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "pc/rtp_media_utils.h"
29#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080033#include "rtc_base/message_digest.h"
34#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020035#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080036#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080037#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038
Yves Gerey665174f2018-06-19 15:03:05 +020039#define ASSERT_CRYPTO(cd, s, cs) \
40 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080041 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042
43typedef std::vector<cricket::Candidate> Candidates;
44
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080045using cricket::AudioCodec;
46using cricket::AudioContentDescription;
47using cricket::ContentInfo;
48using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080049using cricket::GetFirstAudioContent;
50using cricket::GetFirstAudioContentDescription;
51using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020052using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080053using cricket::GetFirstVideoContent;
54using cricket::GetFirstVideoContentDescription;
55using cricket::kAutoBandwidth;
56using cricket::MEDIA_TYPE_AUDIO;
57using cricket::MEDIA_TYPE_DATA;
58using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070060using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080061using cricket::MediaProtocolType;
62using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000063using cricket::MediaSessionOptions;
64using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080065using cricket::RidDescription;
66using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020067using cricket::RtpDataCodec;
68using cricket::RtpDataContentDescription;
69using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080070using cricket::SEC_DISABLED;
71using cricket::SEC_ENABLED;
72using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080074using cricket::SimulcastDescription;
75using cricket::SimulcastLayer;
76using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077using cricket::SsrcGroup;
78using cricket::StreamParams;
79using cricket::StreamParamsVec;
80using cricket::TransportDescription;
81using cricket::TransportDescriptionFactory;
82using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080084using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070085using rtc::CS_AEAD_AES_128_GCM;
86using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080087using rtc::CS_AES_CM_128_HMAC_SHA1_32;
88using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080089using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020090using ::testing::Contains;
91using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +010092using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020093using ::testing::ElementsAreArray;
94using ::testing::Eq;
95using ::testing::Field;
96using ::testing::IsEmpty;
97using ::testing::IsFalse;
98using ::testing::Ne;
99using ::testing::Not;
100using ::testing::Pointwise;
101using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700102using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800103using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104
105static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700106 AudioCodec(103, "ISAC", 16000, -1, 1),
107 AudioCodec(102, "iLBC", 8000, 13300, 1),
108 AudioCodec(0, "PCMU", 8000, 64000, 1),
109 AudioCodec(8, "PCMA", 8000, 64000, 1),
110 AudioCodec(117, "red", 8000, 0, 1),
111 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112
113static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200114 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700115 AudioCodec(0, "PCMU", 8000, 64000, 1),
116 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117};
118
119static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700120 AudioCodec(102, "iLBC", 8000, 13300, 1),
121 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122};
123
perkj26752742016-10-24 01:21:16 -0700124static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
125 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126
zhihuang1c378ed2017-08-17 14:10:50 -0700127static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
128 VideoCodec(96, "H264-SVC")};
129
perkj26752742016-10-24 01:21:16 -0700130static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
131 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132
perkj26752742016-10-24 01:21:16 -0700133static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200135static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
136 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200138static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
139 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200141static const RtpDataCodec kDataCodecsAnswer[] = {
142 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143
isheriff6f8d6862016-05-26 11:24:55 -0700144static const RtpExtension kAudioRtpExtension1[] = {
145 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
146 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147};
148
jbauch5869f502017-06-29 12:31:36 -0700149static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
151 RtpExtension("http://google.com/testing/audio_something", 10),
152 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
153};
154
isheriff6f8d6862016-05-26 11:24:55 -0700155static const RtpExtension kAudioRtpExtension2[] = {
156 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
157 RtpExtension("http://google.com/testing/audio_something_else", 8),
158 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159};
160
isheriff6f8d6862016-05-26 11:24:55 -0700161static const RtpExtension kAudioRtpExtension3[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700164};
165
jbauch5869f502017-06-29 12:31:36 -0700166static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
167 RtpExtension("http://google.com/testing/audio_something", 2),
168 // Use RTP extension that supports encryption.
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
170};
171
172static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
173 RtpExtension("http://google.com/testing/audio_something", 2),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
175 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
176};
177
isheriff6f8d6862016-05-26 11:24:55 -0700178static const RtpExtension kAudioRtpExtensionAnswer[] = {
179 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000180};
181
jbauch5869f502017-06-29 12:31:36 -0700182static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
183 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
184};
185
isheriff6f8d6862016-05-26 11:24:55 -0700186static const RtpExtension kVideoRtpExtension1[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
188 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000189};
190
jbauch5869f502017-06-29 12:31:36 -0700191static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
192 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
193 RtpExtension("http://google.com/testing/video_something", 13),
194 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
195};
196
isheriff6f8d6862016-05-26 11:24:55 -0700197static const RtpExtension kVideoRtpExtension2[] = {
198 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
199 RtpExtension("http://google.com/testing/video_something_else", 14),
200 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000201};
202
isheriff6f8d6862016-05-26 11:24:55 -0700203static const RtpExtension kVideoRtpExtension3[] = {
204 RtpExtension("http://google.com/testing/video_something", 4),
205 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700206};
207
jbauch5869f502017-06-29 12:31:36 -0700208static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
209 RtpExtension("http://google.com/testing/video_something", 4),
210 // Use RTP extension that supports encryption.
211 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
212};
213
isheriff6f8d6862016-05-26 11:24:55 -0700214static const RtpExtension kVideoRtpExtensionAnswer[] = {
215 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216};
217
jbauch5869f502017-06-29 12:31:36 -0700218static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
219 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
220};
221
Johannes Kronce8e8672019-02-22 13:06:44 +0100222static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
223 RtpExtension("http://www.ietf.org/id/"
224 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
225 1),
226};
227
228static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
229 RtpExtension("http://www.ietf.org/id/"
230 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
231 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100232 RtpExtension(
233 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
234 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100235};
236
237static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100238 RtpExtension(
239 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
240 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100241};
242
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100243static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
244 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
245 "generic-frame-descriptor-00",
246 3),
247};
248
Peter Boström0c4e06b2015-10-07 12:23:21 +0200249static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
250static const uint32_t kSimSsrc[] = {10, 20, 30};
251static const uint32_t kFec1Ssrc[] = {10, 11};
252static const uint32_t kFec2Ssrc[] = {20, 21};
253static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254
255static const char kMediaStream1[] = "stream_1";
256static const char kMediaStream2[] = "stream_2";
257static const char kVideoTrack1[] = "video_1";
258static const char kVideoTrack2[] = "video_2";
259static const char kAudioTrack1[] = "audio_1";
260static const char kAudioTrack2[] = "audio_2";
261static const char kAudioTrack3[] = "audio_3";
262static const char kDataTrack1[] = "data_1";
263static const char kDataTrack2[] = "data_2";
264static const char kDataTrack3[] = "data_3";
265
zhihuangcf5b37c2016-05-05 11:44:35 -0700266static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
267 "RTP/SAVPF"};
268static const char* kMediaProtocolsDtls[] = {
269 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
270 "UDP/TLS/RTP/SAVP"};
271
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700272// SRTP cipher name negotiated by the tests. This must be updated if the
273// default changes.
274static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
275static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
276
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800277// These constants are used to make the code using "AddMediaDescriptionOptions"
278// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700279static constexpr bool kStopped = true;
280static constexpr bool kActive = false;
281
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000282static bool IsMediaContentOfType(const ContentInfo* content,
283 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800284 RTC_DCHECK(content);
285 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000286}
287
Steve Anton4e70a722017-11-28 14:57:10 -0800288static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800289 RTC_DCHECK(content);
290 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000291}
292
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000293static void AddRtxCodec(const VideoCodec& rtx_codec,
294 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800295 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000296 codecs->push_back(rtx_codec);
297}
298
299template <class T>
300static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
301 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100302 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000303 for (const auto& codec : codecs) {
304 codec_names.push_back(codec.name);
305 }
306 return codec_names;
307}
308
zhihuang1c378ed2017-08-17 14:10:50 -0700309// This is used for test only. MIDs are not the identification of the
310// MediaDescriptionOptions since some end points may not support MID and the SDP
311// may not contain 'mid'.
312std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
313 const std::string& mid,
314 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800315 return absl::c_find_if(
316 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700317 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
318}
319
320std::vector<MediaDescriptionOptions>::const_iterator
321FindFirstMediaDescriptionByMid(const std::string& mid,
322 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800323 return absl::c_find_if(
324 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700325 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700326}
327
328// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800329static void AddMediaDescriptionOptions(MediaType type,
330 const std::string& mid,
331 RtpTransceiverDirection direction,
332 bool stopped,
333 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800334 opts->media_description_options.push_back(
335 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700336}
337
Steve Anton4e70a722017-11-28 14:57:10 -0800338static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700339 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800340 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
341 opts);
342 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
343 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700344}
345
346static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800347 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700348 MediaSessionOptions* opts) {
349 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800350 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700351}
352
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800353static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700354 const std::string& mid,
355 MediaType type,
356 const std::string& track_id,
357 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800358 const std::vector<RidDescription>& rids,
359 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700360 int num_sim_layer,
361 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700362 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
363 switch (type) {
364 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700365 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700366 break;
367 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800368 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
369 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700370 break;
371 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700372 RTC_CHECK(stream_ids.size() == 1U);
373 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700374 break;
375 default:
376 RTC_NOTREACHED();
377 }
378}
379
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800380static void AttachSenderToMediaDescriptionOptions(
381 const std::string& mid,
382 MediaType type,
383 const std::string& track_id,
384 const std::vector<std::string>& stream_ids,
385 int num_sim_layer,
386 MediaSessionOptions* session_options) {
387 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
388 SimulcastLayerList(), num_sim_layer,
389 session_options);
390}
391
zhihuang1c378ed2017-08-17 14:10:50 -0700392static void DetachSenderFromMediaSection(const std::string& mid,
393 const std::string& track_id,
394 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700395 std::vector<cricket::SenderOptions>& sender_options_list =
396 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
397 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800398 absl::c_find_if(sender_options_list,
399 [track_id](const cricket::SenderOptions& sender_options) {
400 return sender_options.track_id == track_id;
401 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700402 RTC_DCHECK(sender_it != sender_options_list.end());
403 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700404}
405
406// Helper function used to create a default MediaSessionOptions for Plan B SDP.
407// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
408static MediaSessionOptions CreatePlanBMediaSessionOptions() {
409 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800410 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
411 RtpTransceiverDirection::kRecvOnly, kActive,
412 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700413 return session_options;
414}
415
Philipp Hancke1aec2bf2020-05-12 10:11:27 +0200416// prefers GCM SDES crypto suites by removing non-GCM defaults.
417void PreferGcmCryptoParameters(CryptoParamsVec* cryptos) {
418 cryptos->erase(
419 std::remove_if(cryptos->begin(), cryptos->end(),
420 [](const cricket::CryptoParams& crypto) {
421 return crypto.cipher_suite != CS_AEAD_AES_256_GCM &&
422 crypto.cipher_suite != CS_AEAD_AES_128_GCM;
423 }),
424 cryptos->end());
425}
426
zhihuang1c378ed2017-08-17 14:10:50 -0700427// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
428// was designed for Plan B SDP, where only one audio "m=" section and one video
429// "m=" section could be generated, and ordering couldn't be controlled. Many of
430// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200431class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800433 MediaSessionDescriptionFactoryTest()
434 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700435 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
436 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200437 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
438 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200439 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700440 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
441 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200442 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
443 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200444 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200445 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700446 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200447 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700448 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 }
450
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000451 // Create a video StreamParamsVec object with:
452 // - one video stream with 3 simulcast streams and FEC,
453 StreamParamsVec CreateComplexVideoStreamParamsVec() {
454 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
455 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
456 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
457 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
458
459 std::vector<SsrcGroup> ssrc_groups;
460 ssrc_groups.push_back(sim_group);
461 ssrc_groups.push_back(fec_group1);
462 ssrc_groups.push_back(fec_group2);
463 ssrc_groups.push_back(fec_group3);
464
465 StreamParams simulcast_params;
466 simulcast_params.id = kVideoTrack1;
467 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
468 simulcast_params.ssrc_groups = ssrc_groups;
469 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800470 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000471
472 StreamParamsVec video_streams;
473 video_streams.push_back(simulcast_params);
474
475 return video_streams;
476 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000477
478 bool CompareCryptoParams(const CryptoParamsVec& c1,
479 const CryptoParamsVec& c2) {
480 if (c1.size() != c2.size())
481 return false;
482 for (size_t i = 0; i < c1.size(); ++i)
483 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
484 c1[i].key_params != c2[i].key_params ||
485 c1[i].session_params != c2[i].session_params)
486 return false;
487 return true;
488 }
489
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700490 // Returns true if the transport info contains "renomination" as an
491 // ICE option.
492 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800493 return absl::c_linear_search(transport_info->description.transport_options,
494 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700495 }
496
zhihuang1c378ed2017-08-17 14:10:50 -0700497 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700498 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499 bool has_current_desc) {
500 const std::string current_audio_ufrag = "current_audio_ufrag";
501 const std::string current_audio_pwd = "current_audio_pwd";
502 const std::string current_video_ufrag = "current_video_ufrag";
503 const std::string current_video_pwd = "current_video_pwd";
504 const std::string current_data_ufrag = "current_data_ufrag";
505 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800506 std::unique_ptr<SessionDescription> current_desc;
507 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200509 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800510 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200511 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800512 TransportDescription(current_audio_ufrag, current_audio_pwd)));
513 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200514 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800515 TransportDescription(current_video_ufrag, current_video_pwd)));
516 current_desc->AddTransportInfo(TransportInfo(
517 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 }
519 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800520 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521 } else {
kwiberg31022942016-03-11 14:18:21 -0800522 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800523 offer = f1_.CreateOffer(options, NULL);
524 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525 }
526 ASSERT_TRUE(desc.get() != NULL);
527 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000528 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000529 EXPECT_TRUE(ti_audio != NULL);
530 if (has_current_desc) {
531 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
532 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
533 } else {
534 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
535 ti_audio->description.ice_ufrag.size());
536 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
537 ti_audio->description.ice_pwd.size());
538 }
zhihuang1c378ed2017-08-17 14:10:50 -0700539 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700540 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700541 EXPECT_EQ(
542 media_desc_options_it->transport_options.enable_ice_renomination,
543 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700544 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
545 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546
547 } else {
548 EXPECT_TRUE(ti_audio == NULL);
549 }
550 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000551 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700553 auto media_desc_options_it =
554 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 if (options.bundle_enabled) {
556 EXPECT_EQ(ti_audio->description.ice_ufrag,
557 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200558 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700559 EXPECT_EQ(ti_audio->description.opaque_parameters,
560 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 } else {
562 if (has_current_desc) {
563 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
564 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
565 } else {
566 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
567 ti_video->description.ice_ufrag.size());
568 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
569 ti_video->description.ice_pwd.size());
570 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700571 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
572 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 }
zhihuang1c378ed2017-08-17 14:10:50 -0700574 EXPECT_EQ(
575 media_desc_options_it->transport_options.enable_ice_renomination,
576 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 } else {
578 EXPECT_TRUE(ti_video == NULL);
579 }
580 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
581 if (options.has_data()) {
582 EXPECT_TRUE(ti_data != NULL);
583 if (options.bundle_enabled) {
584 EXPECT_EQ(ti_audio->description.ice_ufrag,
585 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200586 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 } else {
588 if (has_current_desc) {
589 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
590 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
591 } else {
592 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
593 ti_data->description.ice_ufrag.size());
594 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
595 ti_data->description.ice_pwd.size());
596 }
597 }
zhihuang1c378ed2017-08-17 14:10:50 -0700598 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700599 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700600 EXPECT_EQ(
601 media_desc_options_it->transport_options.enable_ice_renomination,
602 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700603
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700605 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 }
607 }
608
609 void TestCryptoWithBundle(bool offer) {
610 f1_.set_secure(SEC_ENABLED);
611 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800612 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
613 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
614 &options);
kwiberg31022942016-03-11 14:18:21 -0800615 std::unique_ptr<SessionDescription> ref_desc;
616 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 if (offer) {
618 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800619 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800621 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 } else {
623 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800624 ref_desc = f1_.CreateOffer(options, NULL);
625 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800627 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800629 desc->GetContentDescriptionByName("audio");
630 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800632 desc->GetContentDescriptionByName("video");
633 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
635 video_media_desc->cryptos()));
636 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800637 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 audio_media_desc->cryptos()[0].cipher_suite);
639
640 // Verify the selected crypto is one from the reference audio
641 // media content.
642 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800643 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 bool found = false;
645 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
646 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200647 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000648 found = true;
649 break;
650 }
651 }
652 EXPECT_TRUE(found);
653 }
654
655 // This test that the audio and video media direction is set to
656 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700657 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800659 RtpTransceiverDirection direction_in_offer,
660 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700661 MediaSessionOptions offer_opts;
662 AddAudioVideoSections(direction_in_offer, &offer_opts);
663
Steve Anton6fe1fba2018-12-11 10:15:23 -0800664 std::unique_ptr<SessionDescription> offer =
665 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700667 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700669 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671
zhihuang1c378ed2017-08-17 14:10:50 -0700672 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800673 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800674 std::unique_ptr<SessionDescription> answer =
675 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000676 const AudioContentDescription* acd_answer =
677 GetFirstAudioContentDescription(answer.get());
678 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
679 const VideoContentDescription* vcd_answer =
680 GetFirstVideoContentDescription(answer.get());
681 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
682 }
683
684 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800685 RTC_DCHECK(content);
686 RTC_CHECK(content->media_description());
687 const cricket::AudioContentDescription* audio_desc =
688 content->media_description()->as_audio();
689 RTC_CHECK(audio_desc);
690 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
691 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800693 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 }
695 return true;
696 }
697
jbauchcb560652016-08-04 05:20:32 -0700698 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
699 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800700 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700701 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700702
jbauchcb560652016-08-04 05:20:32 -0700703 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800704 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700705 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700706
jbauchcb560652016-08-04 05:20:32 -0700707 f1_.set_secure(SEC_ENABLED);
708 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800709 std::unique_ptr<SessionDescription> offer =
710 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700711 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +0200712 if (gcm_offer && gcm_answer) {
713 for (cricket::ContentInfo& content : offer->contents()) {
714 auto cryptos = content.media_description()->cryptos();
715 PreferGcmCryptoParameters(&cryptos);
716 content.media_description()->set_cryptos(cryptos);
717 }
718 }
Steve Anton6fe1fba2018-12-11 10:15:23 -0800719 std::unique_ptr<SessionDescription> answer =
720 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700721 const ContentInfo* ac = answer->GetContentByName("audio");
722 const ContentInfo* vc = answer->GetContentByName("video");
723 ASSERT_TRUE(ac != NULL);
724 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800725 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
726 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800727 const AudioContentDescription* acd = ac->media_description()->as_audio();
728 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700729 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800730 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700731 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700732 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700733 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
734 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700735 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700736 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700737 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700738 }
739 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800740 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200741 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
742 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700743 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700744 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700745 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700746 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700747 }
Steve Antone38a5a12018-11-21 16:05:15 -0800748 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700749 }
750
Johannes Kronce8e8672019-02-22 13:06:44 +0100751 void TestTransportSequenceNumberNegotiation(
752 const cricket::RtpHeaderExtensions& local,
753 const cricket::RtpHeaderExtensions& offered,
754 const cricket::RtpHeaderExtensions& expectedAnswer) {
755 MediaSessionOptions opts;
756 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell71db9ac2020-06-08 19:48:49 +0200757 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100758 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
759 ASSERT_TRUE(offer.get() != NULL);
Markus Handell71db9ac2020-06-08 19:48:49 +0200760 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
Johannes Kronce8e8672019-02-22 13:06:44 +0100761 std::unique_ptr<SessionDescription> answer =
762 f2_.CreateAnswer(offer.get(), opts, NULL);
763
764 EXPECT_EQ(
765 expectedAnswer,
766 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
767 EXPECT_EQ(
768 expectedAnswer,
769 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
770 }
771
Markus Handell71db9ac2020-06-08 19:48:49 +0200772 std::vector<webrtc::RtpHeaderExtensionCapability>
773 HeaderExtensionCapabilitiesFromRtpExtensions(
774 cricket::RtpHeaderExtensions extensions) {
775 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
776 for (const auto& extension : extensions) {
777 webrtc::RtpHeaderExtensionCapability capability(
778 extension.uri, extension.id,
779 webrtc::RtpTransceiverDirection::kSendRecv);
780 capabilities.push_back(capability);
781 }
782 return capabilities;
783 }
784
785 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
786 cricket::RtpHeaderExtensions video_exts,
787 MediaSessionOptions* opts) {
788 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
789 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
790 for (auto& entry : opts->media_description_options) {
791 switch (entry.type) {
792 case MEDIA_TYPE_AUDIO:
793 entry.header_extensions = audio_caps;
794 break;
795 case MEDIA_TYPE_VIDEO:
796 entry.header_extensions = video_caps;
797 break;
798 default:
799 break;
800 }
801 }
802 }
803
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800805 UniqueRandomIdGenerator ssrc_generator1;
806 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 MediaSessionDescriptionFactory f1_;
808 MediaSessionDescriptionFactory f2_;
809 TransportDescriptionFactory tdf1_;
810 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811};
812
813// Create a typical audio offer, and ensure it matches what we expect.
814TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
815 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800816 std::unique_ptr<SessionDescription> offer =
817 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 ASSERT_TRUE(offer.get() != NULL);
819 const ContentInfo* ac = offer->GetContentByName("audio");
820 const ContentInfo* vc = offer->GetContentByName("video");
821 ASSERT_TRUE(ac != NULL);
822 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800823 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800824 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700826 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700827 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
829 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700830 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800831 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832}
833
834// Create a typical video offer, and ensure it matches what we expect.
835TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
836 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800837 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800839 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 ASSERT_TRUE(offer.get() != NULL);
841 const ContentInfo* ac = offer->GetContentByName("audio");
842 const ContentInfo* vc = offer->GetContentByName("video");
843 ASSERT_TRUE(ac != NULL);
844 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800845 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
846 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800847 const AudioContentDescription* acd = ac->media_description()->as_audio();
848 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700850 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700851 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
853 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700854 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800855 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200857 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700858 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
860 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700861 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800862 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863}
864
865// Test creating an offer with bundle where the Codecs have the same dynamic
866// RTP playlod type. The test verifies that the offer don't contain the
867// duplicate RTP payload types.
868TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200869 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700870 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200871 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
873 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
874
875 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800876 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
877 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000878 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800879 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 const VideoContentDescription* vcd =
881 GetFirstVideoContentDescription(offer.get());
882 const AudioContentDescription* acd =
883 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200884 const RtpDataContentDescription* dcd =
885 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000886 ASSERT_TRUE(NULL != vcd);
887 ASSERT_TRUE(NULL != acd);
888 ASSERT_TRUE(NULL != dcd);
889 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
890 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
891 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
892 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
893 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
894 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
895}
896
zhihuang1c378ed2017-08-17 14:10:50 -0700897// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000898// after an audio only session has been negotiated.
899TEST_F(MediaSessionDescriptionFactoryTest,
900 TestCreateUpdatedVideoOfferWithBundle) {
901 f1_.set_secure(SEC_ENABLED);
902 f2_.set_secure(SEC_ENABLED);
903 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800904 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
905 RtpTransceiverDirection::kRecvOnly, kActive,
906 &opts);
907 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
908 RtpTransceiverDirection::kInactive, kStopped,
909 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000910 opts.data_channel_type = cricket::DCT_NONE;
911 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800912 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
913 std::unique_ptr<SessionDescription> answer =
914 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915
916 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800917 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
918 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
919 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000920 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800921 std::unique_ptr<SessionDescription> updated_offer(
922 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000923
924 const AudioContentDescription* acd =
925 GetFirstAudioContentDescription(updated_offer.get());
926 const VideoContentDescription* vcd =
927 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200928 const RtpDataContentDescription* dcd =
929 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000930 EXPECT_TRUE(NULL != vcd);
931 EXPECT_TRUE(NULL != acd);
932 EXPECT_TRUE(NULL != dcd);
933
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700934 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800935 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700936 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800937 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700938 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800939 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940}
deadbeef44f08192015-12-15 16:20:09 -0800941
wu@webrtc.org78187522013-10-07 23:32:02 +0000942// Create a RTP data offer, and ensure it matches what we expect.
943TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800945 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
946 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800948 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000949 ASSERT_TRUE(offer.get() != NULL);
950 const ContentInfo* ac = offer->GetContentByName("audio");
951 const ContentInfo* dc = offer->GetContentByName("data");
952 ASSERT_TRUE(ac != NULL);
953 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800954 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
955 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800956 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200957 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000958 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700959 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700960 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000961 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
962 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700963 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800964 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200966 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700967 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000968 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200969 dcd->bandwidth()); // default bandwidth (auto)
970 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700971 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800972 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000973}
974
wu@webrtc.org78187522013-10-07 23:32:02 +0000975// Create an SCTP data offer with bundle without error.
976TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
977 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000978 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800979 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000980 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800981 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000982 EXPECT_TRUE(offer.get() != NULL);
983 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000984 auto dcd = GetFirstSctpDataContentDescription(offer.get());
985 ASSERT_TRUE(dcd);
986 // Since this transport is insecure, the protocol should be "SCTP".
987 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
988}
989
990// Create an SCTP data offer with bundle without error.
991TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
992 MediaSessionOptions opts;
993 opts.bundle_enabled = true;
994 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
995 f1_.set_secure(SEC_ENABLED);
996 tdf1_.set_secure(SEC_ENABLED);
997 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
998 EXPECT_TRUE(offer.get() != NULL);
999 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
1000 auto dcd = GetFirstSctpDataContentDescription(offer.get());
1001 ASSERT_TRUE(dcd);
1002 // The protocol should now be "UDP/DTLS/SCTP"
1003 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +00001004}
1005
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001006// Test creating an sctp data channel from an already generated offer.
1007TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
1008 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001009 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -08001010 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001011 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001012 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001013 ASSERT_TRUE(offer1.get() != NULL);
1014 const ContentInfo* data = offer1->GetContentByName("data");
1015 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001016 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001017
1018 // Now set data_channel_type to 'none' (default) and make sure that the
1019 // datachannel type that gets generated from the previous offer, is of the
1020 // same type.
1021 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -08001022 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001023 f1_.CreateOffer(opts, offer1.get()));
1024 data = offer2->GetContentByName("data");
1025 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001026 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +00001027}
1028
Steve Anton2bed3972019-01-04 17:04:30 -08001029// Test that if BUNDLE is enabled and all media sections are rejected then the
1030// BUNDLE group is not present in the re-offer.
1031TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
1032 MediaSessionOptions opts;
1033 opts.bundle_enabled = true;
1034 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1035 RtpTransceiverDirection::kSendRecv, kActive,
1036 &opts);
1037 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1038
1039 opts.media_description_options[0].stopped = true;
1040 std::unique_ptr<SessionDescription> reoffer =
1041 f1_.CreateOffer(opts, offer.get());
1042
1043 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1044}
1045
1046// Test that if BUNDLE is enabled and the remote re-offer does not include a
1047// BUNDLE group since all media sections are rejected, then the re-answer also
1048// does not include a BUNDLE group.
1049TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
1050 MediaSessionOptions opts;
1051 opts.bundle_enabled = true;
1052 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1053 RtpTransceiverDirection::kSendRecv, kActive,
1054 &opts);
1055 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1056 std::unique_ptr<SessionDescription> answer =
1057 f2_.CreateAnswer(offer.get(), opts, nullptr);
1058
1059 opts.media_description_options[0].stopped = true;
1060 std::unique_ptr<SessionDescription> reoffer =
1061 f1_.CreateOffer(opts, offer.get());
1062 std::unique_ptr<SessionDescription> reanswer =
1063 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1064
1065 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1066}
1067
1068// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1069// was rejected then the new offerer-tagged media section is the non-rejected
1070// media section.
1071TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1072 MediaSessionOptions opts;
1073 opts.bundle_enabled = true;
1074 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1075 RtpTransceiverDirection::kSendRecv, kActive,
1076 &opts);
1077 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1078
1079 // Reject the audio m= section and add a video m= section.
1080 opts.media_description_options[0].stopped = true;
1081 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1082 RtpTransceiverDirection::kSendRecv, kActive,
1083 &opts);
1084 std::unique_ptr<SessionDescription> reoffer =
1085 f1_.CreateOffer(opts, offer.get());
1086
1087 const cricket::ContentGroup* bundle_group =
1088 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1089 ASSERT_TRUE(bundle_group);
1090 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1091 EXPECT_TRUE(bundle_group->HasContentName("video"));
1092}
1093
1094// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1095// was rejected and a new media section is added, then the re-answer BUNDLE
1096// group will contain only the non-rejected media section.
1097TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1098 MediaSessionOptions opts;
1099 opts.bundle_enabled = true;
1100 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1101 RtpTransceiverDirection::kSendRecv, kActive,
1102 &opts);
1103 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1104 std::unique_ptr<SessionDescription> answer =
1105 f2_.CreateAnswer(offer.get(), opts, nullptr);
1106
1107 // Reject the audio m= section and add a video m= section.
1108 opts.media_description_options[0].stopped = true;
1109 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1110 RtpTransceiverDirection::kSendRecv, kActive,
1111 &opts);
1112 std::unique_ptr<SessionDescription> reoffer =
1113 f1_.CreateOffer(opts, offer.get());
1114 std::unique_ptr<SessionDescription> reanswer =
1115 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1116
1117 const cricket::ContentGroup* bundle_group =
1118 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1119 ASSERT_TRUE(bundle_group);
1120 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1121 EXPECT_TRUE(bundle_group->HasContentName("video"));
1122}
1123
1124// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1125// and there is still a non-rejected media section that was in the initial
1126// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1127// media section.
1128TEST_F(MediaSessionDescriptionFactoryTest,
1129 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1130 MediaSessionOptions opts;
1131 opts.bundle_enabled = true;
1132 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1133 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1134 std::unique_ptr<SessionDescription> answer =
1135 f2_.CreateAnswer(offer.get(), opts, nullptr);
1136
1137 // Reject the audio m= section.
1138 opts.media_description_options[0].stopped = true;
1139 std::unique_ptr<SessionDescription> reoffer =
1140 f1_.CreateOffer(opts, offer.get());
1141
1142 const TransportDescription* offer_tagged =
1143 offer->GetTransportDescriptionByName("audio");
1144 ASSERT_TRUE(offer_tagged);
1145 const TransportDescription* reoffer_tagged =
1146 reoffer->GetTransportDescriptionByName("video");
1147 ASSERT_TRUE(reoffer_tagged);
1148 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1149 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1150}
1151
1152// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1153// and there is still a non-rejected media section that was in the initial
1154// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1155// media section.
1156TEST_F(MediaSessionDescriptionFactoryTest,
1157 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1158 MediaSessionOptions opts;
1159 opts.bundle_enabled = true;
1160 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1161 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1162 std::unique_ptr<SessionDescription> answer =
1163 f2_.CreateAnswer(offer.get(), opts, nullptr);
1164
1165 // Reject the audio m= section.
1166 opts.media_description_options[0].stopped = true;
1167 std::unique_ptr<SessionDescription> reoffer =
1168 f1_.CreateOffer(opts, offer.get());
1169 std::unique_ptr<SessionDescription> reanswer =
1170 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1171
1172 const TransportDescription* answer_tagged =
1173 answer->GetTransportDescriptionByName("audio");
1174 ASSERT_TRUE(answer_tagged);
1175 const TransportDescription* reanswer_tagged =
1176 reanswer->GetTransportDescriptionByName("video");
1177 ASSERT_TRUE(reanswer_tagged);
1178 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1179 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1180}
1181
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001182// Create an audio, video offer without legacy StreamParams.
1183TEST_F(MediaSessionDescriptionFactoryTest,
1184 TestCreateOfferWithoutLegacyStreams) {
1185 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001186 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001187 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001188 ASSERT_TRUE(offer.get() != NULL);
1189 const ContentInfo* ac = offer->GetContentByName("audio");
1190 const ContentInfo* vc = offer->GetContentByName("video");
1191 ASSERT_TRUE(ac != NULL);
1192 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001193 const AudioContentDescription* acd = ac->media_description()->as_audio();
1194 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195
Yves Gerey665174f2018-06-19 15:03:05 +02001196 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1197 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001198}
1199
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001200// Creates an audio+video sendonly offer.
1201TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001202 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001203 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001204 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1205 {kMediaStream1}, 1, &opts);
1206 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1207 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001208
Steve Anton6fe1fba2018-12-11 10:15:23 -08001209 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001210 ASSERT_TRUE(offer.get() != NULL);
1211 EXPECT_EQ(2u, offer->contents().size());
1212 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1213 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1214
Steve Anton4e70a722017-11-28 14:57:10 -08001215 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1216 GetMediaDirection(&offer->contents()[0]));
1217 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1218 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001219}
1220
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001221// Verifies that the order of the media contents in the current
1222// SessionDescription is preserved in the new SessionDescription.
1223TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1224 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001225 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001226
kwiberg31022942016-03-11 14:18:21 -08001227 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001228 ASSERT_TRUE(offer1.get() != NULL);
1229 EXPECT_EQ(1u, offer1->contents().size());
1230 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1231
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001232 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1233 RtpTransceiverDirection::kRecvOnly, kActive,
1234 &opts);
kwiberg31022942016-03-11 14:18:21 -08001235 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001236 f1_.CreateOffer(opts, offer1.get()));
1237 ASSERT_TRUE(offer2.get() != NULL);
1238 EXPECT_EQ(2u, offer2->contents().size());
1239 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1240 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1241
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001242 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1243 RtpTransceiverDirection::kRecvOnly, kActive,
1244 &opts);
kwiberg31022942016-03-11 14:18:21 -08001245 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001246 f1_.CreateOffer(opts, offer2.get()));
1247 ASSERT_TRUE(offer3.get() != NULL);
1248 EXPECT_EQ(3u, offer3->contents().size());
1249 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1250 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1251 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001252}
1253
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254// Create a typical audio answer, and ensure it matches what we expect.
1255TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1256 f1_.set_secure(SEC_ENABLED);
1257 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001258 std::unique_ptr<SessionDescription> offer =
1259 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001261 std::unique_ptr<SessionDescription> answer =
1262 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263 const ContentInfo* ac = answer->GetContentByName("audio");
1264 const ContentInfo* vc = answer->GetContentByName("video");
1265 ASSERT_TRUE(ac != NULL);
1266 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001267 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001268 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001270 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001271 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1273 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001274 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001275 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276}
1277
jbauchcb560652016-08-04 05:20:32 -07001278// Create a typical audio answer with GCM ciphers enabled, and ensure it
1279// matches what we expect.
1280TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1281 f1_.set_secure(SEC_ENABLED);
1282 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001283 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001284 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001285 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001286 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +02001287 for (cricket::ContentInfo& content : offer->contents()) {
1288 auto cryptos = content.media_description()->cryptos();
1289 PreferGcmCryptoParameters(&cryptos);
1290 content.media_description()->set_cryptos(cryptos);
1291 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08001292 std::unique_ptr<SessionDescription> answer =
1293 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001294 const ContentInfo* ac = answer->GetContentByName("audio");
1295 const ContentInfo* vc = answer->GetContentByName("video");
1296 ASSERT_TRUE(ac != NULL);
1297 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001298 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001299 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001300 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001301 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001302 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001303 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1304 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001305 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001306 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001307}
1308
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309// Create a typical video answer, and ensure it matches what we expect.
1310TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1311 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001312 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001313 f1_.set_secure(SEC_ENABLED);
1314 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001315 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001317 std::unique_ptr<SessionDescription> answer =
1318 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001319 const ContentInfo* ac = answer->GetContentByName("audio");
1320 const ContentInfo* vc = answer->GetContentByName("video");
1321 ASSERT_TRUE(ac != NULL);
1322 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001323 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1324 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001325 const AudioContentDescription* acd = ac->media_description()->as_audio();
1326 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001327 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001328 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001329 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001330 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001331 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001332 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001334 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001335 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1336 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001337 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001338 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339}
1340
jbauchcb560652016-08-04 05:20:32 -07001341// Create a typical video answer with GCM ciphers enabled, and ensure it
1342// matches what we expect.
1343TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1344 TestVideoGcmCipher(true, true);
1345}
1346
1347// Create a typical video answer with GCM ciphers enabled for the offer only,
1348// and ensure it matches what we expect.
1349TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1350 TestVideoGcmCipher(true, false);
1351}
1352
1353// Create a typical video answer with GCM ciphers enabled for the answer only,
1354// and ensure it matches what we expect.
1355TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1356 TestVideoGcmCipher(false, true);
1357}
1358
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001359TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001360 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001361 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001362 f1_.set_secure(SEC_ENABLED);
1363 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001364 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001365 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001366 std::unique_ptr<SessionDescription> answer =
1367 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001368 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001369 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001370 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001371 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001372 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1373 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001374 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001375 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001376 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001377 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001378 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001379 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001380 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001381 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001382 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001383 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001384 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001385 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001386 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001387 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001388}
1389
jbauchcb560652016-08-04 05:20:32 -07001390TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001391 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001392 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001393 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001394 f1_.set_secure(SEC_ENABLED);
1395 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001396 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001397 ASSERT_TRUE(offer.get() != NULL);
Philipp Hancke1aec2bf2020-05-12 10:11:27 +02001398 for (cricket::ContentInfo& content : offer->contents()) {
1399 auto cryptos = content.media_description()->cryptos();
1400 PreferGcmCryptoParameters(&cryptos);
1401 content.media_description()->set_cryptos(cryptos);
1402 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08001403 std::unique_ptr<SessionDescription> answer =
1404 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001405 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001406 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001407 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001408 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001409 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1410 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001411 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001412 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001413 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001414 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001415 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001416 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001417 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001418 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001419 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001420 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001421 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001422 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001423 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001424 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001425}
1426
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001427// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1428// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001429TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1430 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001431 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001432 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001433 ASSERT_TRUE(offer.get() != NULL);
1434 ContentInfo* dc_offer = offer->GetContentByName("data");
1435 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001436 SctpDataContentDescription* dcd_offer =
1437 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001438 EXPECT_TRUE(dcd_offer->use_sctpmap());
1439
Steve Anton6fe1fba2018-12-11 10:15:23 -08001440 std::unique_ptr<SessionDescription> answer =
1441 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001442 const ContentInfo* dc_answer = answer->GetContentByName("data");
1443 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001444 const SctpDataContentDescription* dcd_answer =
1445 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001446 EXPECT_TRUE(dcd_answer->use_sctpmap());
1447}
1448
1449// The answer's use_sctpmap flag should match the offer's.
1450TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1451 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001452 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001453 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001454 ASSERT_TRUE(offer.get() != NULL);
1455 ContentInfo* dc_offer = offer->GetContentByName("data");
1456 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001457 SctpDataContentDescription* dcd_offer =
1458 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001459 dcd_offer->set_use_sctpmap(false);
1460
Steve Anton6fe1fba2018-12-11 10:15:23 -08001461 std::unique_ptr<SessionDescription> answer =
1462 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001463 const ContentInfo* dc_answer = answer->GetContentByName("data");
1464 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001465 const SctpDataContentDescription* dcd_answer =
1466 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001467 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001468}
1469
deadbeef8b7e9ad2017-05-25 09:38:55 -07001470// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1471// and "TCP/DTLS/SCTP" offers.
1472TEST_F(MediaSessionDescriptionFactoryTest,
1473 TestCreateDataAnswerToDifferentOfferedProtos) {
1474 // Need to enable DTLS offer/answer generation (disabled by default in this
1475 // test).
1476 f1_.set_secure(SEC_ENABLED);
1477 f2_.set_secure(SEC_ENABLED);
1478 tdf1_.set_secure(SEC_ENABLED);
1479 tdf2_.set_secure(SEC_ENABLED);
1480
1481 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001482 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001483 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001484 ASSERT_TRUE(offer.get() != nullptr);
1485 ContentInfo* dc_offer = offer->GetContentByName("data");
1486 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001487 SctpDataContentDescription* dcd_offer =
1488 dc_offer->media_description()->as_sctp();
1489 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001490
1491 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1492 "TCP/DTLS/SCTP"};
1493 for (const std::string& proto : protos) {
1494 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001495 std::unique_ptr<SessionDescription> answer =
1496 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001497 const ContentInfo* dc_answer = answer->GetContentByName("data");
1498 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001499 const SctpDataContentDescription* dcd_answer =
1500 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001501 EXPECT_FALSE(dc_answer->rejected);
1502 EXPECT_EQ(proto, dcd_answer->protocol());
1503 }
1504}
1505
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001506TEST_F(MediaSessionDescriptionFactoryTest,
1507 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1508 // Need to enable DTLS offer/answer generation (disabled by default in this
1509 // test).
1510 f1_.set_secure(SEC_ENABLED);
1511 f2_.set_secure(SEC_ENABLED);
1512 tdf1_.set_secure(SEC_ENABLED);
1513 tdf2_.set_secure(SEC_ENABLED);
1514
1515 MediaSessionOptions opts;
1516 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1517 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1518 ASSERT_TRUE(offer.get() != nullptr);
1519 ContentInfo* dc_offer = offer->GetContentByName("data");
1520 ASSERT_TRUE(dc_offer != nullptr);
1521 SctpDataContentDescription* dcd_offer =
1522 dc_offer->media_description()->as_sctp();
1523 ASSERT_TRUE(dcd_offer);
1524 dcd_offer->set_max_message_size(1234);
1525 std::unique_ptr<SessionDescription> answer =
1526 f2_.CreateAnswer(offer.get(), opts, nullptr);
1527 const ContentInfo* dc_answer = answer->GetContentByName("data");
1528 ASSERT_TRUE(dc_answer != nullptr);
1529 const SctpDataContentDescription* dcd_answer =
1530 dc_answer->media_description()->as_sctp();
1531 EXPECT_FALSE(dc_answer->rejected);
1532 EXPECT_EQ(1234, dcd_answer->max_message_size());
1533}
1534
1535TEST_F(MediaSessionDescriptionFactoryTest,
1536 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1537 // Need to enable DTLS offer/answer generation (disabled by default in this
1538 // test).
1539 f1_.set_secure(SEC_ENABLED);
1540 f2_.set_secure(SEC_ENABLED);
1541 tdf1_.set_secure(SEC_ENABLED);
1542 tdf2_.set_secure(SEC_ENABLED);
1543
1544 MediaSessionOptions opts;
1545 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1546 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1547 ASSERT_TRUE(offer.get() != nullptr);
1548 ContentInfo* dc_offer = offer->GetContentByName("data");
1549 ASSERT_TRUE(dc_offer != nullptr);
1550 SctpDataContentDescription* dcd_offer =
1551 dc_offer->media_description()->as_sctp();
1552 ASSERT_TRUE(dcd_offer);
1553 dcd_offer->set_max_message_size(0);
1554 std::unique_ptr<SessionDescription> answer =
1555 f2_.CreateAnswer(offer.get(), opts, nullptr);
1556 const ContentInfo* dc_answer = answer->GetContentByName("data");
1557 ASSERT_TRUE(dc_answer != nullptr);
1558 const SctpDataContentDescription* dcd_answer =
1559 dc_answer->media_description()->as_sctp();
1560 EXPECT_FALSE(dc_answer->rejected);
1561 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1562}
1563
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001564// Verifies that the order of the media contents in the offer is preserved in
1565// the answer.
1566TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1567 MediaSessionOptions opts;
1568
1569 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001570 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001571 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001572 ASSERT_TRUE(offer1.get() != NULL);
1573
1574 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001575 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1576 RtpTransceiverDirection::kRecvOnly, kActive,
1577 &opts);
kwiberg31022942016-03-11 14:18:21 -08001578 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001579 f1_.CreateOffer(opts, offer1.get()));
1580 ASSERT_TRUE(offer2.get() != NULL);
1581
1582 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001583 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1584 RtpTransceiverDirection::kRecvOnly, kActive,
1585 &opts);
kwiberg31022942016-03-11 14:18:21 -08001586 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001587 f1_.CreateOffer(opts, offer2.get()));
1588 ASSERT_TRUE(offer3.get() != NULL);
1589
Steve Anton6fe1fba2018-12-11 10:15:23 -08001590 std::unique_ptr<SessionDescription> answer =
1591 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001592 ASSERT_TRUE(answer.get() != NULL);
1593 EXPECT_EQ(3u, answer->contents().size());
1594 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1595 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1596 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1597}
1598
ossu075af922016-06-14 03:29:38 -07001599// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1600// answerer settings.
1601
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001602// This test that the media direction is set to send/receive in an answer if
1603// the offer is send receive.
1604TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001605 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1606 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001607}
1608
1609// This test that the media direction is set to receive only in an answer if
1610// the offer is send only.
1611TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001612 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1613 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001614}
1615
1616// This test that the media direction is set to send only in an answer if
1617// the offer is recv only.
1618TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001619 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1620 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001621}
1622
1623// This test that the media direction is set to inactive in an answer if
1624// the offer is inactive.
1625TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001626 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1627 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001628}
1629
1630// Test that a data content with an unknown protocol is rejected in an answer.
1631TEST_F(MediaSessionDescriptionFactoryTest,
1632 CreateDataAnswerToOfferWithUnknownProtocol) {
1633 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001634 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635 f1_.set_secure(SEC_ENABLED);
1636 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001637 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001638 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001640 RtpDataContentDescription* dcd_offer =
1641 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001642 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001643 // Offer must be acceptable as an RTP protocol in order to be set.
1644 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001645 dcd_offer->set_protocol(protocol);
1646
Steve Anton6fe1fba2018-12-11 10:15:23 -08001647 std::unique_ptr<SessionDescription> answer =
1648 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001649
1650 const ContentInfo* dc_answer = answer->GetContentByName("data");
1651 ASSERT_TRUE(dc_answer != NULL);
1652 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001653 const RtpDataContentDescription* dcd_answer =
1654 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001655 ASSERT_TRUE(dcd_answer != NULL);
1656 EXPECT_EQ(protocol, dcd_answer->protocol());
1657}
1658
1659// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1660TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001661 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001662 f1_.set_secure(SEC_DISABLED);
1663 f2_.set_secure(SEC_DISABLED);
1664 tdf1_.set_secure(SEC_DISABLED);
1665 tdf2_.set_secure(SEC_DISABLED);
1666
Steve Anton6fe1fba2018-12-11 10:15:23 -08001667 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668 const AudioContentDescription* offer_acd =
1669 GetFirstAudioContentDescription(offer.get());
1670 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001671 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001672
Steve Anton6fe1fba2018-12-11 10:15:23 -08001673 std::unique_ptr<SessionDescription> answer =
1674 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001675
1676 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1677 ASSERT_TRUE(ac_answer != NULL);
1678 EXPECT_FALSE(ac_answer->rejected);
1679
1680 const AudioContentDescription* answer_acd =
1681 GetFirstAudioContentDescription(answer.get());
1682 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001683 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001684}
1685
1686// Create a video offer and answer and ensure the RTP header extensions
1687// matches what we expect.
1688TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1689 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001690 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Markus Handell71db9ac2020-06-08 19:48:49 +02001691 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1692 MAKE_VECTOR(kVideoRtpExtension1), &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001693
Steve Anton6fe1fba2018-12-11 10:15:23 -08001694 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001695 ASSERT_TRUE(offer.get() != NULL);
Markus Handell71db9ac2020-06-08 19:48:49 +02001696 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1697 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001698 std::unique_ptr<SessionDescription> answer =
1699 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001700
Yves Gerey665174f2018-06-19 15:03:05 +02001701 EXPECT_EQ(
1702 MAKE_VECTOR(kAudioRtpExtension1),
1703 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1704 EXPECT_EQ(
1705 MAKE_VECTOR(kVideoRtpExtension1),
1706 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1707 EXPECT_EQ(
1708 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1709 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1710 EXPECT_EQ(
1711 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1712 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001713}
1714
Johannes Kronce8e8672019-02-22 13:06:44 +01001715// Create a audio/video offer and answer and ensure that the
1716// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1717// supported and should take precedence even though not listed among locally
1718// supported extensions.
1719TEST_F(MediaSessionDescriptionFactoryTest,
1720 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1721 TestTransportSequenceNumberNegotiation(
1722 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1723 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1724 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1725}
1726TEST_F(MediaSessionDescriptionFactoryTest,
1727 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1728 TestTransportSequenceNumberNegotiation(
1729 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1730 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1731 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1732}
1733TEST_F(MediaSessionDescriptionFactoryTest,
1734 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1735 TestTransportSequenceNumberNegotiation(
1736 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1737 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1738 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1739}
1740
jbauch5869f502017-06-29 12:31:36 -07001741TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001742 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1743 MediaSessionOptions opts;
1744 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1745
Markus Handell71db9ac2020-06-08 19:48:49 +02001746 SetAudioVideoRtpHeaderExtensions(
1747 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1748 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001749 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell71db9ac2020-06-08 19:48:49 +02001750 SetAudioVideoRtpHeaderExtensions(
1751 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1752 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001753 std::unique_ptr<SessionDescription> answer =
1754 f2_.CreateAnswer(offer.get(), opts, nullptr);
1755 EXPECT_THAT(
1756 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell71db9ac2020-06-08 19:48:49 +02001757 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001758 EXPECT_THAT(
1759 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell71db9ac2020-06-08 19:48:49 +02001760 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001761}
1762
1763TEST_F(MediaSessionDescriptionFactoryTest,
1764 TestNegotiateFrameDescriptorWhenExposedLocally) {
1765 MediaSessionOptions opts;
1766 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1767
Markus Handell71db9ac2020-06-08 19:48:49 +02001768 SetAudioVideoRtpHeaderExtensions(
1769 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1770 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001771 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1772 std::unique_ptr<SessionDescription> answer =
1773 f2_.CreateAnswer(offer.get(), opts, nullptr);
1774 EXPECT_THAT(
1775 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell71db9ac2020-06-08 19:48:49 +02001776 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001777 EXPECT_THAT(
1778 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
Markus Handell71db9ac2020-06-08 19:48:49 +02001779 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001780}
1781
1782TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001783 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1784 MediaSessionOptions opts;
1785 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1786
1787 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
Markus Handell71db9ac2020-06-08 19:48:49 +02001788 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001789 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell71db9ac2020-06-08 19:48:49 +02001790 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1791 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001792 std::unique_ptr<SessionDescription> answer =
1793 f2_.CreateAnswer(offer.get(), opts, nullptr);
1794 EXPECT_THAT(
1795 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1796 ElementsAre(offer_dd));
1797}
1798
1799TEST_F(MediaSessionDescriptionFactoryTest,
1800 NegotiateDependencyDescriptorWhenExposedLocally) {
1801 MediaSessionOptions opts;
1802 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1803
1804 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1805 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
Markus Handell71db9ac2020-06-08 19:48:49 +02001806 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001807 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell71db9ac2020-06-08 19:48:49 +02001808 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001809 std::unique_ptr<SessionDescription> answer =
1810 f2_.CreateAnswer(offer.get(), opts, nullptr);
1811 EXPECT_THAT(
1812 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1813 ElementsAre(offer_dd));
1814}
1815
1816TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001817 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1818 MediaSessionOptions opts;
1819 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1820
1821 const cricket::RtpHeaderExtensions offered_extensions = {
1822 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1823 const cricket::RtpHeaderExtensions local_extensions = {
1824 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
Markus Handell71db9ac2020-06-08 19:48:49 +02001825 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1826 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001827 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell71db9ac2020-06-08 19:48:49 +02001828 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001829 std::unique_ptr<SessionDescription> answer =
1830 f2_.CreateAnswer(offer.get(), opts, nullptr);
1831 EXPECT_THAT(
1832 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1833 ElementsAreArray(offered_extensions));
1834 EXPECT_THAT(
1835 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1836 ElementsAreArray(offered_extensions));
1837}
1838
1839TEST_F(MediaSessionDescriptionFactoryTest,
1840 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1841 MediaSessionOptions opts;
1842 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1843
1844 const cricket::RtpHeaderExtensions offered_extensions = {
1845 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1846 const cricket::RtpHeaderExtensions local_extensions = {
1847 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell71db9ac2020-06-08 19:48:49 +02001848 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1849 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001850 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell71db9ac2020-06-08 19:48:49 +02001851 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001852 std::unique_ptr<SessionDescription> answer =
1853 f2_.CreateAnswer(offer.get(), opts, nullptr);
1854 EXPECT_THAT(
1855 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1856 ElementsAreArray(offered_extensions));
1857 EXPECT_THAT(
1858 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1859 ElementsAreArray(offered_extensions));
1860}
1861
1862TEST_F(MediaSessionDescriptionFactoryTest,
1863 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1864 MediaSessionOptions opts;
1865 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1866
1867 const cricket::RtpHeaderExtensions offered_extensions = {
1868 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1869 const cricket::RtpHeaderExtensions local_extensions = {
1870 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
Markus Handell71db9ac2020-06-08 19:48:49 +02001871 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1872 &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001873 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Markus Handell71db9ac2020-06-08 19:48:49 +02001874 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
Minyue Li430e4a02020-03-10 10:59:37 +01001875 std::unique_ptr<SessionDescription> answer =
1876 f2_.CreateAnswer(offer.get(), opts, nullptr);
1877 EXPECT_THAT(
1878 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1879 IsEmpty());
1880 EXPECT_THAT(
1881 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1882 IsEmpty());
1883}
1884
Markus Handell71db9ac2020-06-08 19:48:49 +02001885TEST_F(MediaSessionDescriptionFactoryTest, OffersUnstoppedExtensions) {
1886 MediaSessionOptions opts;
1887 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1888 RtpTransceiverDirection::kSendRecv, kActive,
1889 &opts);
1890 opts.media_description_options.back().header_extensions = {
1891 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1892 RtpTransceiverDirection::kStopped),
1893 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1894 RtpTransceiverDirection::kSendOnly),
1895 webrtc::RtpHeaderExtensionCapability("uri3", 5,
1896 RtpTransceiverDirection::kRecvOnly)};
1897 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1898 RtpTransceiverDirection::kSendRecv, kActive,
1899 &opts);
1900 opts.media_description_options.back().header_extensions = {
1901 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1902 RtpTransceiverDirection::kSendRecv),
1903 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1904 RtpTransceiverDirection::kStopped),
1905 webrtc::RtpHeaderExtensionCapability("uri3", 5,
1906 RtpTransceiverDirection::kRecvOnly)};
1907 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
1908 RtpTransceiverDirection::kSendRecv, kActive,
1909 &opts);
1910 opts.media_description_options.back().header_extensions = {
1911 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1912 RtpTransceiverDirection::kSendRecv),
1913 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1914 RtpTransceiverDirection::kRecvOnly),
1915 webrtc::RtpHeaderExtensionCapability("uri3", 5,
1916 RtpTransceiverDirection::kStopped)};
1917 auto offer = f1_.CreateOffer(opts, nullptr);
1918 EXPECT_THAT(
1919 offer->contents(),
1920 ElementsAre(
1921 Property(&ContentInfo::media_description,
1922 Pointee(Property(
1923 &MediaContentDescription::rtp_header_extensions,
1924 ElementsAre(Field(&RtpExtension::uri, "uri2"),
1925 Field(&RtpExtension::uri, "uri3"))))),
1926 Property(&ContentInfo::media_description,
1927 Pointee(Property(
1928 &MediaContentDescription::rtp_header_extensions,
1929 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1930 Field(&RtpExtension::uri, "uri3"))))),
1931 Property(&ContentInfo::media_description,
1932 Pointee(Property(
1933 &MediaContentDescription::rtp_header_extensions,
1934 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1935 Field(&RtpExtension::uri, "uri2")))))));
1936}
1937
1938TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1939 MediaSessionOptions opts;
1940 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1941 RtpTransceiverDirection::kSendRecv, kActive,
1942 &opts);
1943 opts.media_description_options.back().header_extensions = {
1944 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1945 RtpTransceiverDirection::kStopped),
1946 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1947 RtpTransceiverDirection::kSendOnly),
1948 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1949 RtpTransceiverDirection::kRecvOnly),
1950 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1951 RtpTransceiverDirection::kSendRecv)};
1952 auto offer = f1_.CreateOffer(opts, nullptr);
1953 opts.media_description_options.back().header_extensions = {
1954 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1955 RtpTransceiverDirection::kSendOnly),
1956 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1957 RtpTransceiverDirection::kRecvOnly),
1958 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1959 RtpTransceiverDirection::kStopped),
1960 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1961 RtpTransceiverDirection::kSendRecv)};
1962 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1963 EXPECT_THAT(
1964 answer->contents(),
1965 ElementsAre(Property(
1966 &ContentInfo::media_description,
1967 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1968 ElementsAre(Field(&RtpExtension::uri, "uri2"),
1969 Field(&RtpExtension::uri, "uri4")))))));
1970}
1971
1972TEST_F(MediaSessionDescriptionFactoryTest,
1973 AppendsUnstoppedExtensionsToCurrentDescription) {
1974 MediaSessionOptions opts;
1975 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1976 RtpTransceiverDirection::kSendRecv, kActive,
1977 &opts);
1978 opts.media_description_options.back().header_extensions = {
1979 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1980 RtpTransceiverDirection::kSendRecv)};
1981 auto offer = f1_.CreateOffer(opts, nullptr);
1982 opts.media_description_options.back().header_extensions = {
1983 webrtc::RtpHeaderExtensionCapability("uri1", 2,
1984 RtpTransceiverDirection::kSendRecv),
1985 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1986 RtpTransceiverDirection::kRecvOnly),
1987 webrtc::RtpHeaderExtensionCapability("uri3", 5,
1988 RtpTransceiverDirection::kStopped),
1989 webrtc::RtpHeaderExtensionCapability("uri4", 6,
1990 RtpTransceiverDirection::kSendRecv)};
1991 auto offer2 = f1_.CreateOffer(opts, offer.get());
1992 EXPECT_THAT(
1993 offer2->contents(),
1994 ElementsAre(Property(
1995 &ContentInfo::media_description,
1996 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1997 ElementsAre(Field(&RtpExtension::uri, "uri1"),
1998 Field(&RtpExtension::uri, "uri2"),
1999 Field(&RtpExtension::uri, "uri4")))))));
2000}
2001
Minyue Li430e4a02020-03-10 10:59:37 +01002002TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002003 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07002004 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002005 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002006
2007 f1_.set_enable_encrypted_rtp_header_extensions(true);
2008 f2_.set_enable_encrypted_rtp_header_extensions(true);
2009
Markus Handell71db9ac2020-06-08 19:48:49 +02002010 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2011 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002012 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002013 ASSERT_TRUE(offer.get() != NULL);
Markus Handell71db9ac2020-06-08 19:48:49 +02002014 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2015 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002016 std::unique_ptr<SessionDescription> answer =
2017 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002018
Yves Gerey665174f2018-06-19 15:03:05 +02002019 EXPECT_EQ(
2020 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2021 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2022 EXPECT_EQ(
2023 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2024 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2025 EXPECT_EQ(
2026 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
2027 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2028 EXPECT_EQ(
2029 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
2030 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002031}
2032
2033TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002034 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07002035 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002036 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002037
2038 f1_.set_enable_encrypted_rtp_header_extensions(true);
2039
Markus Handell71db9ac2020-06-08 19:48:49 +02002040 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2041 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002042 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002043 ASSERT_TRUE(offer.get() != NULL);
Markus Handell71db9ac2020-06-08 19:48:49 +02002044 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2045 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002046 std::unique_ptr<SessionDescription> answer =
2047 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002048
Yves Gerey665174f2018-06-19 15:03:05 +02002049 EXPECT_EQ(
2050 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2051 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2052 EXPECT_EQ(
2053 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2054 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2055 EXPECT_EQ(
2056 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2057 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2058 EXPECT_EQ(
2059 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2060 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002061}
2062
2063TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002064 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07002065 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002066 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002067
2068 f2_.set_enable_encrypted_rtp_header_extensions(true);
2069
Markus Handell71db9ac2020-06-08 19:48:49 +02002070 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2071 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002072 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002073 ASSERT_TRUE(offer.get() != NULL);
Markus Handell71db9ac2020-06-08 19:48:49 +02002074 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2075 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002076 std::unique_ptr<SessionDescription> answer =
2077 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002078
Yves Gerey665174f2018-06-19 15:03:05 +02002079 EXPECT_EQ(
2080 MAKE_VECTOR(kAudioRtpExtension1),
2081 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2082 EXPECT_EQ(
2083 MAKE_VECTOR(kVideoRtpExtension1),
2084 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2085 EXPECT_EQ(
2086 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2087 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2088 EXPECT_EQ(
2089 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2090 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002091}
2092
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002093// Create an audio, video, data answer without legacy StreamParams.
2094TEST_F(MediaSessionDescriptionFactoryTest,
2095 TestCreateAnswerWithoutLegacyStreams) {
2096 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002097 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2098 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002099 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002100 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002101 std::unique_ptr<SessionDescription> answer =
2102 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002103 const ContentInfo* ac = answer->GetContentByName("audio");
2104 const ContentInfo* vc = answer->GetContentByName("video");
2105 const ContentInfo* dc = answer->GetContentByName("data");
2106 ASSERT_TRUE(ac != NULL);
2107 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002108 const AudioContentDescription* acd = ac->media_description()->as_audio();
2109 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002110 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002111
2112 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2113 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
2114 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
2115}
2116
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002117// Create a typical video answer, and ensure it matches what we expect.
2118TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2119 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002120 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
2121 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
2122 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002123
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002124 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002125 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
2126 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
2127 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002128
kwiberg31022942016-03-11 14:18:21 -08002129 std::unique_ptr<SessionDescription> offer;
2130 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131
2132 offer_opts.rtcp_mux_enabled = true;
2133 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002134 offer = f1_.CreateOffer(offer_opts, NULL);
2135 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002136 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2137 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002138 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002139 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2140 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002141 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002142 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2143 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002144 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002145 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2146 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002147 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002148
2149 offer_opts.rtcp_mux_enabled = true;
2150 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002151 offer = f1_.CreateOffer(offer_opts, NULL);
2152 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002153 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2154 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002155 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002156 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2157 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002158 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002159 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2160 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002161 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002162 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2163 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002164 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002165
2166 offer_opts.rtcp_mux_enabled = false;
2167 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002168 offer = f1_.CreateOffer(offer_opts, NULL);
2169 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002170 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2171 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002172 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002173 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2174 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002175 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002176 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2177 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002178 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2180 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002181 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002182
2183 offer_opts.rtcp_mux_enabled = false;
2184 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002185 offer = f1_.CreateOffer(offer_opts, NULL);
2186 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002187 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2188 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002189 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002190 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2191 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002192 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002193 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2194 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002195 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002196 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2197 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002198 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002199}
2200
2201// Create an audio-only answer to a video offer.
2202TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2203 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002204 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2205 RtpTransceiverDirection::kRecvOnly, kActive,
2206 &opts);
2207 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2208 RtpTransceiverDirection::kRecvOnly, kActive,
2209 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002210 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002211 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002212
2213 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002214 std::unique_ptr<SessionDescription> answer =
2215 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002216 const ContentInfo* ac = answer->GetContentByName("audio");
2217 const ContentInfo* vc = answer->GetContentByName("video");
2218 ASSERT_TRUE(ac != NULL);
2219 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002220 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002221 EXPECT_TRUE(vc->rejected);
2222}
2223
2224// Create an audio-only answer to an offer with data.
2225TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002226 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002227 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002228 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2229 RtpTransceiverDirection::kRecvOnly, kActive,
2230 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002231 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002232 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002233
2234 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002235 std::unique_ptr<SessionDescription> answer =
2236 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002237 const ContentInfo* ac = answer->GetContentByName("audio");
2238 const ContentInfo* dc = answer->GetContentByName("data");
2239 ASSERT_TRUE(ac != NULL);
2240 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002241 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002242 EXPECT_TRUE(dc->rejected);
2243}
2244
2245// Create an answer that rejects the contents which are rejected in the offer.
2246TEST_F(MediaSessionDescriptionFactoryTest,
2247 CreateAnswerToOfferWithRejectedMedia) {
2248 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002249 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2250 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002251 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002252 ASSERT_TRUE(offer.get() != NULL);
2253 ContentInfo* ac = offer->GetContentByName("audio");
2254 ContentInfo* vc = offer->GetContentByName("video");
2255 ContentInfo* dc = offer->GetContentByName("data");
2256 ASSERT_TRUE(ac != NULL);
2257 ASSERT_TRUE(vc != NULL);
2258 ASSERT_TRUE(dc != NULL);
2259 ac->rejected = true;
2260 vc->rejected = true;
2261 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002262 std::unique_ptr<SessionDescription> answer =
2263 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002264 ac = answer->GetContentByName("audio");
2265 vc = answer->GetContentByName("video");
2266 dc = answer->GetContentByName("data");
2267 ASSERT_TRUE(ac != NULL);
2268 ASSERT_TRUE(vc != NULL);
2269 ASSERT_TRUE(dc != NULL);
2270 EXPECT_TRUE(ac->rejected);
2271 EXPECT_TRUE(vc->rejected);
2272 EXPECT_TRUE(dc->rejected);
2273}
2274
Johannes Kron0854eb62018-10-10 22:33:20 +02002275TEST_F(MediaSessionDescriptionFactoryTest,
2276 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2277 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002278 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002279 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002280 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002281 ASSERT_TRUE(offer.get() != NULL);
2282 std::unique_ptr<SessionDescription> answer_no_support(
2283 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002284 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002285
2286 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002287 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002288 ASSERT_TRUE(offer.get() != NULL);
2289 std::unique_ptr<SessionDescription> answer_support(
2290 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002291 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002292}
2293
2294TEST_F(MediaSessionDescriptionFactoryTest,
2295 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2296 MediaSessionOptions opts;
2297 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002298 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002299 MediaContentDescription* video_offer =
2300 offer->GetContentDescriptionByName("video");
2301 ASSERT_TRUE(video_offer);
2302 MediaContentDescription* audio_offer =
2303 offer->GetContentDescriptionByName("audio");
2304 ASSERT_TRUE(audio_offer);
2305
2306 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002307 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2308 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002309
2310 ASSERT_TRUE(offer.get() != NULL);
2311 std::unique_ptr<SessionDescription> answer_no_support(
2312 f2_.CreateAnswer(offer.get(), opts, NULL));
2313 MediaContentDescription* video_answer =
2314 answer_no_support->GetContentDescriptionByName("video");
2315 MediaContentDescription* audio_answer =
2316 answer_no_support->GetContentDescriptionByName("audio");
2317 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002318 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002319 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002320 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002321
2322 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002323 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2324 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002325 ASSERT_TRUE(offer.get() != NULL);
2326 std::unique_ptr<SessionDescription> answer_support(
2327 f2_.CreateAnswer(offer.get(), opts, NULL));
2328 video_answer = answer_support->GetContentDescriptionByName("video");
2329 audio_answer = answer_support->GetContentDescriptionByName("audio");
2330 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002331 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002332 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002333 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002334}
2335
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002336// Create an audio and video offer with:
2337// - one video track
2338// - two audio tracks
2339// - two data tracks
2340// and ensure it matches what we expect. Also updates the initial offer by
2341// adding a new video track and replaces one of the audio tracks.
2342TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2343 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002344 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002345 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2346 {kMediaStream1}, 1, &opts);
2347 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2348 {kMediaStream1}, 1, &opts);
2349 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2350 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002351
Steve Anton4e70a722017-11-28 14:57:10 -08002352 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002353 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2354 {kMediaStream1}, 1, &opts);
2355 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2356 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002357
2358 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002359 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360
2361 ASSERT_TRUE(offer.get() != NULL);
2362 const ContentInfo* ac = offer->GetContentByName("audio");
2363 const ContentInfo* vc = offer->GetContentByName("video");
2364 const ContentInfo* dc = offer->GetContentByName("data");
2365 ASSERT_TRUE(ac != NULL);
2366 ASSERT_TRUE(vc != NULL);
2367 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002368 const AudioContentDescription* acd = ac->media_description()->as_audio();
2369 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002370 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002371 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002372 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002373
2374 const StreamParamsVec& audio_streams = acd->streams();
2375 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002376 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002377 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2378 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2379 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2380 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2381 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2382 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2383
2384 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2385 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002386 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387
2388 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002389 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002390 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002391
2392 const StreamParamsVec& video_streams = vcd->streams();
2393 ASSERT_EQ(1U, video_streams.size());
2394 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2395 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2396 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2397 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2398
2399 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002400 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002401 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002402
2403 const StreamParamsVec& data_streams = dcd->streams();
2404 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002405 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002406 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2407 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2408 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2409 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2410 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2411 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2412
2413 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002414 dcd->bandwidth()); // default bandwidth (auto)
2415 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002416 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002417
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002418 // Update the offer. Add a new video track that is not synched to the
2419 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002420 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2421 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002422 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002423 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2424 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002425 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002426 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2427 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002428 std::unique_ptr<SessionDescription> updated_offer(
2429 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002430
2431 ASSERT_TRUE(updated_offer.get() != NULL);
2432 ac = updated_offer->GetContentByName("audio");
2433 vc = updated_offer->GetContentByName("video");
2434 dc = updated_offer->GetContentByName("data");
2435 ASSERT_TRUE(ac != NULL);
2436 ASSERT_TRUE(vc != NULL);
2437 ASSERT_TRUE(dc != NULL);
2438 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002439 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002440 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002441 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002442 const RtpDataContentDescription* updated_dcd =
2443 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002444
2445 EXPECT_EQ(acd->type(), updated_acd->type());
2446 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2447 EXPECT_EQ(vcd->type(), updated_vcd->type());
2448 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2449 EXPECT_EQ(dcd->type(), updated_dcd->type());
2450 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002451 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002452 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002453 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002454 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002455 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002456 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2457
2458 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2459 ASSERT_EQ(2U, updated_audio_streams.size());
2460 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2461 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2462 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2463 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2464 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2465
2466 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2467 ASSERT_EQ(2U, updated_video_streams.size());
2468 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2469 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002470 // All the media streams in one PeerConnection share one RTCP CNAME.
2471 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002472
2473 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2474 ASSERT_EQ(2U, updated_data_streams.size());
2475 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2476 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2477 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2478 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2479 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002480 // The stream correctly got the CNAME from the MediaSessionOptions.
2481 // The Expected RTCP CNAME is the default one as we are using the default
2482 // MediaSessionOptions.
2483 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002484}
2485
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002486// Create an offer with simulcast video stream.
2487TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2488 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002489 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2490 RtpTransceiverDirection::kRecvOnly, kActive,
2491 &opts);
2492 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2493 RtpTransceiverDirection::kSendRecv, kActive,
2494 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002495 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002496 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2497 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002498 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002499
2500 ASSERT_TRUE(offer.get() != NULL);
2501 const ContentInfo* vc = offer->GetContentByName("video");
2502 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002503 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002504
2505 const StreamParamsVec& video_streams = vcd->streams();
2506 ASSERT_EQ(1U, video_streams.size());
2507 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2508 const SsrcGroup* sim_ssrc_group =
2509 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2510 ASSERT_TRUE(sim_ssrc_group != NULL);
2511 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2512}
2513
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002514MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2515 const RidDescription& rid1 = ::testing::get<0>(arg);
2516 const RidDescription& rid2 = ::testing::get<1>(arg);
2517 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2518}
2519
2520static void CheckSimulcastInSessionDescription(
2521 const SessionDescription* description,
2522 const std::string& content_name,
2523 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002524 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002525 ASSERT_NE(description, nullptr);
2526 const ContentInfo* content = description->GetContentByName(content_name);
2527 ASSERT_NE(content, nullptr);
2528 const MediaContentDescription* cd = content->media_description();
2529 ASSERT_NE(cd, nullptr);
2530 const StreamParamsVec& streams = cd->streams();
2531 ASSERT_THAT(streams, SizeIs(1));
2532 const StreamParams& stream = streams[0];
2533 ASSERT_THAT(stream.ssrcs, IsEmpty());
2534 EXPECT_TRUE(stream.has_rids());
2535 const std::vector<RidDescription> rids = stream.rids();
2536
2537 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2538
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002539 EXPECT_TRUE(cd->HasSimulcast());
2540 const SimulcastDescription& simulcast = cd->simulcast_description();
2541 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2542 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2543
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002544 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002545}
2546
2547// Create an offer with spec-compliant simulcast video stream.
2548TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2549 MediaSessionOptions opts;
2550 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2551 RtpTransceiverDirection::kSendRecv, kActive,
2552 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002553 std::vector<RidDescription> send_rids;
2554 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2555 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2556 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2557 SimulcastLayerList simulcast_layers;
2558 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2559 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2560 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2561 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2562 {kMediaStream1}, send_rids,
2563 simulcast_layers, 0, &opts);
2564 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2565
2566 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002567 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002568}
2569
2570// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2571// In this scenario, RIDs do not need to be negotiated (there is only one).
2572TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2573 MediaSessionOptions opts;
2574 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2575 RtpTransceiverDirection::kSendRecv, kActive,
2576 &opts);
2577 RidDescription rid("f", RidDirection::kSend);
2578 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2579 {kMediaStream1}, {rid},
2580 SimulcastLayerList(), 0, &opts);
2581 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2582
2583 ASSERT_NE(offer.get(), nullptr);
2584 const ContentInfo* content = offer->GetContentByName("video");
2585 ASSERT_NE(content, nullptr);
2586 const MediaContentDescription* cd = content->media_description();
2587 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002588 const StreamParamsVec& streams = cd->streams();
2589 ASSERT_THAT(streams, SizeIs(1));
2590 const StreamParams& stream = streams[0];
2591 ASSERT_THAT(stream.ssrcs, IsEmpty());
2592 EXPECT_FALSE(stream.has_rids());
2593 EXPECT_FALSE(cd->HasSimulcast());
2594}
2595
2596// Create an answer with spec-compliant simulcast video stream.
2597// In this scenario, the SFU is the caller requesting that we send Simulcast.
2598TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2599 MediaSessionOptions offer_opts;
2600 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2601 RtpTransceiverDirection::kSendRecv, kActive,
2602 &offer_opts);
2603 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2604 {kMediaStream1}, 1, &offer_opts);
2605 std::unique_ptr<SessionDescription> offer =
2606 f1_.CreateOffer(offer_opts, nullptr);
2607
2608 MediaSessionOptions answer_opts;
2609 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2610 RtpTransceiverDirection::kSendRecv, kActive,
2611 &answer_opts);
2612
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002613 std::vector<RidDescription> rid_descriptions{
2614 RidDescription("f", RidDirection::kSend),
2615 RidDescription("h", RidDirection::kSend),
2616 RidDescription("q", RidDirection::kSend),
2617 };
2618 SimulcastLayerList simulcast_layers;
2619 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2620 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2621 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2622 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2623 {kMediaStream1}, rid_descriptions,
2624 simulcast_layers, 0, &answer_opts);
2625 std::unique_ptr<SessionDescription> answer =
2626 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2627
2628 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002629 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002630}
2631
2632// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2633// In this scenario, RIDs do not need to be negotiated (there is only one).
2634// Note that RID Direction is not the same as the transceiver direction.
2635TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2636 MediaSessionOptions offer_opts;
2637 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2638 RtpTransceiverDirection::kSendRecv, kActive,
2639 &offer_opts);
2640 RidDescription rid_offer("f", RidDirection::kSend);
2641 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2642 {kMediaStream1}, {rid_offer},
2643 SimulcastLayerList(), 0, &offer_opts);
2644 std::unique_ptr<SessionDescription> offer =
2645 f1_.CreateOffer(offer_opts, nullptr);
2646
2647 MediaSessionOptions answer_opts;
2648 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2649 RtpTransceiverDirection::kSendRecv, kActive,
2650 &answer_opts);
2651
2652 RidDescription rid_answer("f", RidDirection::kReceive);
2653 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2654 {kMediaStream1}, {rid_answer},
2655 SimulcastLayerList(), 0, &answer_opts);
2656 std::unique_ptr<SessionDescription> answer =
2657 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2658
2659 ASSERT_NE(answer.get(), nullptr);
2660 const ContentInfo* content = offer->GetContentByName("video");
2661 ASSERT_NE(content, nullptr);
2662 const MediaContentDescription* cd = content->media_description();
2663 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002664 const StreamParamsVec& streams = cd->streams();
2665 ASSERT_THAT(streams, SizeIs(1));
2666 const StreamParams& stream = streams[0];
2667 ASSERT_THAT(stream.ssrcs, IsEmpty());
2668 EXPECT_FALSE(stream.has_rids());
2669 EXPECT_FALSE(cd->HasSimulcast());
2670}
2671
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002672// Create an audio and video answer to a standard video offer with:
2673// - one video track
2674// - two audio tracks
2675// - two data tracks
2676// and ensure it matches what we expect. Also updates the initial answer by
2677// adding a new video track and removes one of the audio tracks.
2678TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2679 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002680 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2681 RtpTransceiverDirection::kRecvOnly, kActive,
2682 &offer_opts);
2683 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2684 RtpTransceiverDirection::kRecvOnly, kActive,
2685 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002687 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2688 RtpTransceiverDirection::kRecvOnly, kActive,
2689 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002690 f1_.set_secure(SEC_ENABLED);
2691 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002692 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002693
zhihuang1c378ed2017-08-17 14:10:50 -07002694 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002695 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2696 RtpTransceiverDirection::kSendRecv, kActive,
2697 &answer_opts);
2698 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2699 RtpTransceiverDirection::kSendRecv, kActive,
2700 &answer_opts);
2701 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2702 {kMediaStream1}, 1, &answer_opts);
2703 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2704 {kMediaStream1}, 1, &answer_opts);
2705 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2706 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002707
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002708 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2709 RtpTransceiverDirection::kSendRecv, kActive,
2710 &answer_opts);
2711 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2712 {kMediaStream1}, 1, &answer_opts);
2713 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2714 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002715 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716
Steve Anton6fe1fba2018-12-11 10:15:23 -08002717 std::unique_ptr<SessionDescription> answer =
2718 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002719
2720 ASSERT_TRUE(answer.get() != NULL);
2721 const ContentInfo* ac = answer->GetContentByName("audio");
2722 const ContentInfo* vc = answer->GetContentByName("video");
2723 const ContentInfo* dc = answer->GetContentByName("data");
2724 ASSERT_TRUE(ac != NULL);
2725 ASSERT_TRUE(vc != NULL);
2726 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002727 const AudioContentDescription* acd = ac->media_description()->as_audio();
2728 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002729 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002730 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2731 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2732 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002733
2734 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002735 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002736
2737 const StreamParamsVec& audio_streams = acd->streams();
2738 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002739 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002740 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2741 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2742 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2743 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2744 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2745 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2746
2747 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2748 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2749
2750 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002751 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002752
2753 const StreamParamsVec& video_streams = vcd->streams();
2754 ASSERT_EQ(1U, video_streams.size());
2755 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2756 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2757 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2758 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2759
2760 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002761 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002762
2763 const StreamParamsVec& data_streams = dcd->streams();
2764 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002765 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002766 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2767 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2768 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2769 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2770 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2771 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2772
2773 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002774 dcd->bandwidth()); // default bandwidth (auto)
2775 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002776
2777 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002778 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002779 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2780 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002781 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2782 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002783 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002784 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002785
2786 ASSERT_TRUE(updated_answer.get() != NULL);
2787 ac = updated_answer->GetContentByName("audio");
2788 vc = updated_answer->GetContentByName("video");
2789 dc = updated_answer->GetContentByName("data");
2790 ASSERT_TRUE(ac != NULL);
2791 ASSERT_TRUE(vc != NULL);
2792 ASSERT_TRUE(dc != NULL);
2793 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002794 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002795 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002796 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002797 const RtpDataContentDescription* updated_dcd =
2798 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002799
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002800 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002801 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002802 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002803 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002804 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2806
2807 EXPECT_EQ(acd->type(), updated_acd->type());
2808 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2809 EXPECT_EQ(vcd->type(), updated_vcd->type());
2810 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2811 EXPECT_EQ(dcd->type(), updated_dcd->type());
2812 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2813
2814 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2815 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002816 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002817
2818 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2819 ASSERT_EQ(2U, updated_video_streams.size());
2820 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2821 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002822 // All media streams in one PeerConnection share one CNAME.
2823 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002824
2825 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2826 ASSERT_EQ(1U, updated_data_streams.size());
2827 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2828}
2829
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002830// Create an updated offer after creating an answer to the original offer and
2831// verify that the codecs that were part of the original answer are not changed
2832// in the updated offer.
2833TEST_F(MediaSessionDescriptionFactoryTest,
2834 RespondentCreatesOfferAfterCreatingAnswer) {
2835 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002836 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002837
Steve Anton6fe1fba2018-12-11 10:15:23 -08002838 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2839 std::unique_ptr<SessionDescription> answer =
2840 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002841
2842 const AudioContentDescription* acd =
2843 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002844 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002845
2846 const VideoContentDescription* vcd =
2847 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002848 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002849
kwiberg31022942016-03-11 14:18:21 -08002850 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002851 f2_.CreateOffer(opts, answer.get()));
2852
2853 // The expected audio codecs are the common audio codecs from the first
2854 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2855 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002856 // TODO(wu): |updated_offer| should not include the codec
2857 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002858 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002859 kAudioCodecsAnswer[0],
2860 kAudioCodecsAnswer[1],
2861 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002862 };
2863
2864 // The expected video codecs are the common video codecs from the first
2865 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2866 // preference order.
2867 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002868 kVideoCodecsAnswer[0],
2869 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002870 };
2871
2872 const AudioContentDescription* updated_acd =
2873 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002874 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002875
2876 const VideoContentDescription* updated_vcd =
2877 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002878 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002879}
2880
Steve Anton5c72e712018-12-10 14:25:30 -08002881// Test that a reoffer does not reuse audio codecs from a previous media section
2882// that is being recycled.
2883TEST_F(MediaSessionDescriptionFactoryTest,
2884 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002885 f1_.set_video_codecs({}, {});
2886 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002887
2888 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002889 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2890 RtpTransceiverDirection::kSendRecv, kActive,
2891 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002892 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2893 std::unique_ptr<SessionDescription> answer =
2894 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002895
2896 // Recycle the media section by changing its mid.
2897 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002898 std::unique_ptr<SessionDescription> reoffer =
2899 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002900
2901 // Expect that the results of the first negotiation are ignored. If the m=
2902 // section was not recycled the payload types would match the initial offerer.
2903 const AudioContentDescription* acd =
2904 GetFirstAudioContentDescription(reoffer.get());
2905 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2906}
2907
2908// Test that a reoffer does not reuse video codecs from a previous media section
2909// that is being recycled.
2910TEST_F(MediaSessionDescriptionFactoryTest,
2911 ReOfferDoesNotReUseRecycledVideoCodecs) {
2912 f1_.set_audio_codecs({}, {});
2913 f2_.set_audio_codecs({}, {});
2914
2915 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002916 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2917 RtpTransceiverDirection::kSendRecv, kActive,
2918 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002919 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2920 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002921
2922 // Recycle the media section by changing its mid.
2923 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002924 std::unique_ptr<SessionDescription> reoffer =
2925 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002926
2927 // Expect that the results of the first negotiation are ignored. If the m=
2928 // section was not recycled the payload types would match the initial offerer.
2929 const VideoContentDescription* vcd =
2930 GetFirstVideoContentDescription(reoffer.get());
2931 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2932}
2933
2934// Test that a reanswer does not reuse audio codecs from a previous media
2935// section that is being recycled.
2936TEST_F(MediaSessionDescriptionFactoryTest,
2937 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002938 f1_.set_video_codecs({}, {});
2939 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002940
2941 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2942 // second offer/answer is forward (|f1_| as offerer).
2943 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002944 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2945 RtpTransceiverDirection::kSendRecv, kActive,
2946 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002947 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2948 std::unique_ptr<SessionDescription> answer =
2949 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002950
2951 // Recycle the media section by changing its mid.
2952 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002953 std::unique_ptr<SessionDescription> reoffer =
2954 f1_.CreateOffer(opts, answer.get());
2955 std::unique_ptr<SessionDescription> reanswer =
2956 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002957
2958 // Expect that the results of the first negotiation are ignored. If the m=
2959 // section was not recycled the payload types would match the initial offerer.
2960 const AudioContentDescription* acd =
2961 GetFirstAudioContentDescription(reanswer.get());
2962 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2963}
2964
2965// Test that a reanswer does not reuse video codecs from a previous media
2966// section that is being recycled.
2967TEST_F(MediaSessionDescriptionFactoryTest,
2968 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2969 f1_.set_audio_codecs({}, {});
2970 f2_.set_audio_codecs({}, {});
2971
2972 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2973 // second offer/answer is forward (|f1_| as offerer).
2974 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002975 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2976 RtpTransceiverDirection::kSendRecv, kActive,
2977 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002978 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2979 std::unique_ptr<SessionDescription> answer =
2980 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002981
2982 // Recycle the media section by changing its mid.
2983 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002984 std::unique_ptr<SessionDescription> reoffer =
2985 f1_.CreateOffer(opts, answer.get());
2986 std::unique_ptr<SessionDescription> reanswer =
2987 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002988
2989 // Expect that the results of the first negotiation are ignored. If the m=
2990 // section was not recycled the payload types would match the initial offerer.
2991 const VideoContentDescription* vcd =
2992 GetFirstVideoContentDescription(reanswer.get());
2993 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2994}
2995
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002996// Create an updated offer after creating an answer to the original offer and
2997// verify that the codecs that were part of the original answer are not changed
2998// in the updated offer. In this test Rtx is enabled.
2999TEST_F(MediaSessionDescriptionFactoryTest,
3000 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
3001 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003002 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3003 RtpTransceiverDirection::kRecvOnly, kActive,
3004 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003005 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003006 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003007 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003008 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003009
3010 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003011 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003012 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003013 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003014
Steve Anton6fe1fba2018-12-11 10:15:23 -08003015 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003016 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003017 std::unique_ptr<SessionDescription> answer =
3018 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003019
3020 const VideoContentDescription* vcd =
3021 GetFirstVideoContentDescription(answer.get());
3022
3023 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003024 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3025 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003026
3027 EXPECT_EQ(expected_codecs, vcd->codecs());
3028
deadbeef67cf2c12016-04-13 10:07:16 -07003029 // Now, make sure we get same result (except for the order) if |f2_| creates
3030 // an updated offer even though the default payload types between |f1_| and
3031 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08003032 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003033 f2_.CreateOffer(opts, answer.get()));
3034 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003035 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003036 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3037
3038 const VideoContentDescription* updated_vcd =
3039 GetFirstVideoContentDescription(updated_answer.get());
3040
3041 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3042}
3043
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003044// Regression test for:
3045// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
3046// Existing codecs should always appear before new codecs in re-offers. But
3047// under a specific set of circumstances, the existing RTX codec was ending up
3048// added to the end of the list.
3049TEST_F(MediaSessionDescriptionFactoryTest,
3050 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
3051 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003052 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3053 RtpTransceiverDirection::kRecvOnly, kActive,
3054 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003055 // We specifically choose different preferred payload types for VP8 to
3056 // trigger the issue.
3057 cricket::VideoCodec vp8_offerer(100, "VP8");
3058 cricket::VideoCodec vp8_offerer_rtx =
3059 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
3060 cricket::VideoCodec vp8_answerer(110, "VP8");
3061 cricket::VideoCodec vp8_answerer_rtx =
3062 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
3063 cricket::VideoCodec vp9(120, "VP9");
3064 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
3065
3066 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
3067 // We also specifically cause the answerer to prefer VP9, such that if it
3068 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
3069 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
3070 vp8_answerer_rtx};
3071
Johannes Kron3e983682020-03-29 22:17:00 +02003072 f1_.set_video_codecs(f1_codecs, f1_codecs);
3073 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003074 std::vector<AudioCodec> audio_codecs;
3075 f1_.set_audio_codecs(audio_codecs, audio_codecs);
3076 f2_.set_audio_codecs(audio_codecs, audio_codecs);
3077
3078 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003079 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003080 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003081 std::unique_ptr<SessionDescription> answer =
3082 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003083
3084 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
3085 // But if the bug is triggered, RTX for VP8 ends up last.
3086 std::unique_ptr<SessionDescription> updated_offer(
3087 f2_.CreateOffer(opts, answer.get()));
3088
3089 const VideoContentDescription* vcd =
3090 GetFirstVideoContentDescription(updated_offer.get());
3091 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
3092 ASSERT_EQ(4u, codecs.size());
3093 EXPECT_EQ(vp8_offerer, codecs[0]);
3094 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
3095 EXPECT_EQ(vp9, codecs[2]);
3096 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07003097}
3098
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003099// Create an updated offer that adds video after creating an audio only answer
3100// to the original offer. This test verifies that if a video codec and the RTX
3101// codec have the same default payload type as an audio codec that is already in
3102// use, the added codecs payload types are changed.
3103TEST_F(MediaSessionDescriptionFactoryTest,
3104 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
3105 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003106 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003107 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003108 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003109
3110 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003111 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3112 RtpTransceiverDirection::kRecvOnly, kActive,
3113 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003114
Steve Anton6fe1fba2018-12-11 10:15:23 -08003115 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3116 std::unique_ptr<SessionDescription> answer =
3117 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003118
3119 const AudioContentDescription* acd =
3120 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003121 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003122
3123 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
3124 // reference be the same as an audio codec that was negotiated in the
3125 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07003126 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08003127 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003128
3129 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3130 int used_pl_type = acd->codecs()[0].id;
3131 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003132 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003133 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003134
kwiberg31022942016-03-11 14:18:21 -08003135 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003136 f2_.CreateOffer(opts, answer.get()));
3137 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08003138 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003139 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3140
3141 const AudioContentDescription* updated_acd =
3142 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08003143 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003144
3145 const VideoContentDescription* updated_vcd =
3146 GetFirstVideoContentDescription(updated_answer.get());
3147
3148 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08003149 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02003150 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003151 EXPECT_NE(used_pl_type, new_h264_pl_type);
3152 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003153 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003154 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3155 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3156}
3157
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003158// Create an updated offer with RTX after creating an answer to an offer
3159// without RTX, and with different default payload types.
3160// Verify that the added RTX codec references the correct payload type.
3161TEST_F(MediaSessionDescriptionFactoryTest,
3162 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3163 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003164 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003165
3166 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3167 // This creates rtx for H264 with the payload type |f2_| uses.
3168 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003169 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003170
Steve Anton6fe1fba2018-12-11 10:15:23 -08003171 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003172 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003173 std::unique_ptr<SessionDescription> answer =
3174 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003175
3176 const VideoContentDescription* vcd =
3177 GetFirstVideoContentDescription(answer.get());
3178
3179 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3180 EXPECT_EQ(expected_codecs, vcd->codecs());
3181
3182 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
3183 // updated offer, even though the default payload types are different from
3184 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08003185 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003186 f2_.CreateOffer(opts, answer.get()));
3187 ASSERT_TRUE(updated_offer);
3188
3189 const VideoContentDescription* updated_vcd =
3190 GetFirstVideoContentDescription(updated_offer.get());
3191
3192 // New offer should attempt to add H263, and RTX for H264.
3193 expected_codecs.push_back(kVideoCodecs2[1]);
3194 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3195 &expected_codecs);
3196 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3197}
3198
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003199// Test that RTX is ignored when there is no associated payload type parameter.
3200TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3201 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003202 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3203 RtpTransceiverDirection::kRecvOnly, kActive,
3204 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003205 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003206 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003207 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003208 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003209
3210 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003211 // This creates RTX for H264 with the payload type |f2_| uses.
3212 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003213 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003214
Steve Anton6fe1fba2018-12-11 10:15:23 -08003215 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003216 ASSERT_TRUE(offer.get() != NULL);
3217 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3218 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3219 // is possible to test that that RTX is dropped when
3220 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003221 MediaContentDescription* media_desc =
3222 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3223 ASSERT_TRUE(media_desc);
3224 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003225 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003226 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003227 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003228 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003229 }
3230 }
3231 desc->set_codecs(codecs);
3232
Steve Anton6fe1fba2018-12-11 10:15:23 -08003233 std::unique_ptr<SessionDescription> answer =
3234 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003235
Steve Anton64b626b2019-01-28 17:25:26 -08003236 EXPECT_THAT(
3237 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3238 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003239}
3240
3241// Test that RTX will be filtered out in the answer if its associated payload
3242// type doesn't match the local value.
3243TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3244 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003245 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3246 RtpTransceiverDirection::kRecvOnly, kActive,
3247 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003248 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3249 // This creates RTX for H264 in sender.
3250 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003251 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003252
3253 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3254 // This creates RTX for H263 in receiver.
3255 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003256 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003257
Steve Anton6fe1fba2018-12-11 10:15:23 -08003258 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003259 ASSERT_TRUE(offer.get() != NULL);
3260 // Associated payload type doesn't match, therefore, RTX codec is removed in
3261 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003262 std::unique_ptr<SessionDescription> answer =
3263 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003264
Steve Anton64b626b2019-01-28 17:25:26 -08003265 EXPECT_THAT(
3266 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3267 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003268}
3269
3270// Test that when multiple RTX codecs are offered, only the matched RTX codec
3271// is added in the answer, and the unsupported RTX codec is filtered out.
3272TEST_F(MediaSessionDescriptionFactoryTest,
3273 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3274 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003275 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3276 RtpTransceiverDirection::kRecvOnly, kActive,
3277 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003278 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3279 // This creates RTX for H264-SVC in sender.
3280 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003281 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003282
3283 // This creates RTX for H264 in sender.
3284 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003285 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003286
3287 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3288 // This creates RTX for H264 in receiver.
3289 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003290 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003291
3292 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3293 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003294 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003295 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003296 std::unique_ptr<SessionDescription> answer =
3297 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003298 const VideoContentDescription* vcd =
3299 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003300 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3301 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3302 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003303
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003304 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003305}
3306
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003307// Test that after one RTX codec has been negotiated, a new offer can attempt
3308// to add another.
3309TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3310 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003311 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3312 RtpTransceiverDirection::kRecvOnly, kActive,
3313 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003314 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3315 // This creates RTX for H264 for the offerer.
3316 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003317 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003318
Steve Anton6fe1fba2018-12-11 10:15:23 -08003319 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003320 ASSERT_TRUE(offer);
3321 const VideoContentDescription* vcd =
3322 GetFirstVideoContentDescription(offer.get());
3323
3324 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3325 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3326 &expected_codecs);
3327 EXPECT_EQ(expected_codecs, vcd->codecs());
3328
3329 // Now, attempt to add RTX for H264-SVC.
3330 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003331 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003332
kwiberg31022942016-03-11 14:18:21 -08003333 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003334 f1_.CreateOffer(opts, offer.get()));
3335 ASSERT_TRUE(updated_offer);
3336 vcd = GetFirstVideoContentDescription(updated_offer.get());
3337
3338 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3339 &expected_codecs);
3340 EXPECT_EQ(expected_codecs, vcd->codecs());
3341}
3342
Noah Richards2e7a0982015-05-18 14:02:54 -07003343// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3344// generated for each simulcast ssrc and correctly grouped.
3345TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3346 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003347 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3348 RtpTransceiverDirection::kSendRecv, kActive,
3349 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003350 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003351 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3352 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003353
3354 // Use a single real codec, and then add RTX for it.
3355 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003356 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003357 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003358 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003359
3360 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3361 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003362 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003363 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003364 MediaContentDescription* media_desc =
3365 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3366 ASSERT_TRUE(media_desc);
3367 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003368 const StreamParamsVec& streams = desc->streams();
3369 // Single stream.
3370 ASSERT_EQ(1u, streams.size());
3371 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3372 EXPECT_EQ(6u, streams[0].ssrcs.size());
3373 // And should have a SIM group for the simulcast.
3374 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3375 // And a FID group for RTX.
3376 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003377 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003378 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3379 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003380 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003381 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3382 EXPECT_EQ(3u, fid_ssrcs.size());
3383}
3384
brandtr03d5fb12016-11-22 03:37:59 -08003385// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3386// together with a FEC-FR grouping.
3387TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3388 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003389 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3390 RtpTransceiverDirection::kSendRecv, kActive,
3391 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003392 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003393 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3394 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003395
3396 // Use a single real codec, and then add FlexFEC for it.
3397 std::vector<VideoCodec> f1_codecs;
3398 f1_codecs.push_back(VideoCodec(97, "H264"));
3399 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003400 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003401
3402 // Ensure that the offer has a single FlexFEC ssrc and that
3403 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003404 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003405 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003406 MediaContentDescription* media_desc =
3407 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3408 ASSERT_TRUE(media_desc);
3409 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003410 const StreamParamsVec& streams = desc->streams();
3411 // Single stream.
3412 ASSERT_EQ(1u, streams.size());
3413 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3414 EXPECT_EQ(2u, streams[0].ssrcs.size());
3415 // And should have a FEC-FR group for FlexFEC.
3416 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3417 std::vector<uint32_t> primary_ssrcs;
3418 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3419 ASSERT_EQ(1u, primary_ssrcs.size());
3420 uint32_t flexfec_ssrc;
3421 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3422 EXPECT_NE(flexfec_ssrc, 0u);
3423}
3424
3425// Test that FlexFEC is disabled for simulcast.
3426// TODO(brandtr): Remove this test when we support simulcast, either through
3427// multiple FlexfecSenders, or through multistream protection.
3428TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3429 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003430 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3431 RtpTransceiverDirection::kSendRecv, kActive,
3432 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003433 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003434 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3435 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003436
3437 // Use a single real codec, and then add FlexFEC for it.
3438 std::vector<VideoCodec> f1_codecs;
3439 f1_codecs.push_back(VideoCodec(97, "H264"));
3440 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003441 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003442
3443 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3444 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003445 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003446 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003447 MediaContentDescription* media_desc =
3448 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3449 ASSERT_TRUE(media_desc);
3450 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003451 const StreamParamsVec& streams = desc->streams();
3452 // Single stream.
3453 ASSERT_EQ(1u, streams.size());
3454 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3455 EXPECT_EQ(3u, streams[0].ssrcs.size());
3456 // And should have a SIM group for the simulcast.
3457 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3458 // And not a FEC-FR group for FlexFEC.
3459 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3460 std::vector<uint32_t> primary_ssrcs;
3461 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3462 EXPECT_EQ(3u, primary_ssrcs.size());
3463 for (uint32_t primary_ssrc : primary_ssrcs) {
3464 uint32_t flexfec_ssrc;
3465 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3466 }
3467}
3468
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003469// Create an updated offer after creating an answer to the original offer and
3470// verify that the RTP header extensions that were part of the original answer
3471// are not changed in the updated offer.
3472TEST_F(MediaSessionDescriptionFactoryTest,
3473 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3474 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003475 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003476
Markus Handell71db9ac2020-06-08 19:48:49 +02003477 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3478 MAKE_VECTOR(kVideoRtpExtension1), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003479 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Markus Handell71db9ac2020-06-08 19:48:49 +02003480 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3481 MAKE_VECTOR(kVideoRtpExtension2), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003482 std::unique_ptr<SessionDescription> answer =
3483 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003484
Yves Gerey665174f2018-06-19 15:03:05 +02003485 EXPECT_EQ(
3486 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3487 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3488 EXPECT_EQ(
3489 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3490 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003491
kwiberg31022942016-03-11 14:18:21 -08003492 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003493 f2_.CreateOffer(opts, answer.get()));
3494
3495 // The expected RTP header extensions in the new offer are the resulting
3496 // extensions from the first offer/answer exchange plus the extensions only
3497 // |f2_| offer.
3498 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003499 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003500 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003501 kAudioRtpExtensionAnswer[0],
3502 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003503 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003504 };
3505
3506 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003507 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003508 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003509 kVideoRtpExtensionAnswer[0],
3510 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003511 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003512 };
3513
3514 const AudioContentDescription* updated_acd =
3515 GetFirstAudioContentDescription(updated_offer.get());
3516 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3517 updated_acd->rtp_header_extensions());
3518
3519 const VideoContentDescription* updated_vcd =
3520 GetFirstVideoContentDescription(updated_offer.get());
3521 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3522 updated_vcd->rtp_header_extensions());
3523}
3524
deadbeefa5b273a2015-08-20 17:30:13 -07003525// Verify that if the same RTP extension URI is used for audio and video, the
3526// same ID is used. Also verify that the ID isn't changed when creating an
3527// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003528TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003529 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003530 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003531
Markus Handell71db9ac2020-06-08 19:48:49 +02003532 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3533 MAKE_VECTOR(kVideoRtpExtension3), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003534 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003535
3536 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3537 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003538 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003539 kVideoRtpExtension3[0],
3540 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003541 };
3542
Yves Gerey665174f2018-06-19 15:03:05 +02003543 EXPECT_EQ(
3544 MAKE_VECTOR(kAudioRtpExtension3),
3545 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3546 EXPECT_EQ(
3547 MAKE_VECTOR(kExpectedVideoRtpExtension),
3548 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003549
3550 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003551 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003552 f1_.CreateOffer(opts, offer.get()));
3553
3554 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003555 GetFirstAudioContentDescription(updated_offer.get())
3556 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003557 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003558 GetFirstVideoContentDescription(updated_offer.get())
3559 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003560}
3561
jbauch5869f502017-06-29 12:31:36 -07003562// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3563TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3564 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003565 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003566
3567 f1_.set_enable_encrypted_rtp_header_extensions(true);
3568 f2_.set_enable_encrypted_rtp_header_extensions(true);
3569
Markus Handell71db9ac2020-06-08 19:48:49 +02003570 SetAudioVideoRtpHeaderExtensions(
3571 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3572 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003573 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003574
3575 // The extensions that are shared between audio and video should use the same
3576 // id.
3577 const RtpExtension kExpectedVideoRtpExtension[] = {
3578 kVideoRtpExtension3ForEncryption[0],
3579 kAudioRtpExtension3ForEncryptionOffer[1],
3580 kAudioRtpExtension3ForEncryptionOffer[2],
3581 };
3582
Yves Gerey665174f2018-06-19 15:03:05 +02003583 EXPECT_EQ(
3584 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3585 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3586 EXPECT_EQ(
3587 MAKE_VECTOR(kExpectedVideoRtpExtension),
3588 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003589
3590 // Nothing should change when creating a new offer
3591 std::unique_ptr<SessionDescription> updated_offer(
3592 f1_.CreateOffer(opts, offer.get()));
3593
3594 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003595 GetFirstAudioContentDescription(updated_offer.get())
3596 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003597 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003598 GetFirstVideoContentDescription(updated_offer.get())
3599 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003600}
3601
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003602TEST(MediaSessionDescription, CopySessionDescription) {
3603 SessionDescription source;
3604 cricket::ContentGroup group(cricket::CN_AUDIO);
3605 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003606 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003607 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003608 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3609 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003610 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003611 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003612 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003613 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3614 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003615 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003616
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003617 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003618 ASSERT_TRUE(copy.get() != NULL);
3619 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3620 const ContentInfo* ac = copy->GetContentByName("audio");
3621 const ContentInfo* vc = copy->GetContentByName("video");
3622 ASSERT_TRUE(ac != NULL);
3623 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003624 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003625 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003626 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3627 EXPECT_EQ(1u, acd->first_ssrc());
3628
Steve Anton5adfafd2017-12-20 16:34:00 -08003629 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003630 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003631 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3632 EXPECT_EQ(2u, vcd->first_ssrc());
3633}
3634
3635// The below TestTransportInfoXXX tests create different offers/answers, and
3636// ensure the TransportInfo in the SessionDescription matches what we expect.
3637TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3638 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003639 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3640 RtpTransceiverDirection::kRecvOnly, kActive,
3641 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003642 TestTransportInfo(true, options, false);
3643}
3644
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003645TEST_F(MediaSessionDescriptionFactoryTest,
3646 TestTransportInfoOfferIceRenomination) {
3647 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003648 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3649 RtpTransceiverDirection::kRecvOnly, kActive,
3650 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003651 options.media_description_options[0]
3652 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003653 TestTransportInfo(true, options, false);
3654}
3655
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003656TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3657 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003658 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3659 RtpTransceiverDirection::kRecvOnly, kActive,
3660 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003661 TestTransportInfo(true, options, true);
3662}
3663
3664TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3665 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003666 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3667 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3668 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003669 TestTransportInfo(true, options, false);
3670}
3671
3672TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003673 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003674 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003675 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3676 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3677 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003678 TestTransportInfo(true, options, true);
3679}
3680
3681TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3682 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003683 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3684 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3685 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003686 options.bundle_enabled = true;
3687 TestTransportInfo(true, options, false);
3688}
3689
3690TEST_F(MediaSessionDescriptionFactoryTest,
3691 TestTransportInfoOfferBundleCurrent) {
3692 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003693 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3694 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3695 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003696 options.bundle_enabled = true;
3697 TestTransportInfo(true, options, true);
3698}
3699
3700TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3701 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003702 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3703 RtpTransceiverDirection::kRecvOnly, kActive,
3704 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003705 TestTransportInfo(false, options, false);
3706}
3707
3708TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003709 TestTransportInfoAnswerIceRenomination) {
3710 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003711 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3712 RtpTransceiverDirection::kRecvOnly, kActive,
3713 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003714 options.media_description_options[0]
3715 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003716 TestTransportInfo(false, options, false);
3717}
3718
3719TEST_F(MediaSessionDescriptionFactoryTest,
3720 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003721 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003722 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3723 RtpTransceiverDirection::kRecvOnly, kActive,
3724 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003725 TestTransportInfo(false, options, true);
3726}
3727
3728TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3729 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003730 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3731 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3732 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003733 TestTransportInfo(false, options, false);
3734}
3735
3736TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003737 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003738 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(false, options, true);
3743}
3744
3745TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3746 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003747 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3748 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3749 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003750 options.bundle_enabled = true;
3751 TestTransportInfo(false, options, false);
3752}
3753
3754TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003755 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003756 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003757 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3758 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3759 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003760 options.bundle_enabled = true;
3761 TestTransportInfo(false, options, true);
3762}
3763
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003764TEST_F(MediaSessionDescriptionFactoryTest,
3765 TestTransportInfoOfferBundlesTransportOptions) {
3766 MediaSessionOptions options;
3767 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3768
3769 cricket::OpaqueTransportParameters audio_params;
3770 audio_params.protocol = "audio-transport";
3771 audio_params.parameters = "audio-params";
3772 FindFirstMediaDescriptionByMid("audio", &options)
3773 ->transport_options.opaque_parameters = audio_params;
3774
3775 cricket::OpaqueTransportParameters video_params;
3776 video_params.protocol = "video-transport";
3777 video_params.parameters = "video-params";
3778 FindFirstMediaDescriptionByMid("video", &options)
3779 ->transport_options.opaque_parameters = video_params;
3780
3781 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3782}
3783
3784TEST_F(MediaSessionDescriptionFactoryTest,
3785 TestTransportInfoAnswerBundlesTransportOptions) {
3786 MediaSessionOptions options;
3787 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3788
3789 cricket::OpaqueTransportParameters audio_params;
3790 audio_params.protocol = "audio-transport";
3791 audio_params.parameters = "audio-params";
3792 FindFirstMediaDescriptionByMid("audio", &options)
3793 ->transport_options.opaque_parameters = audio_params;
3794
3795 cricket::OpaqueTransportParameters video_params;
3796 video_params.protocol = "video-transport";
3797 video_params.parameters = "video-params";
3798 FindFirstMediaDescriptionByMid("video", &options)
3799 ->transport_options.opaque_parameters = video_params;
3800
3801 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3802}
3803
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003804TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3805 MediaSessionOptions options;
3806 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3807 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3808 &options);
3809
3810 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3811 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3812 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3813
3814 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3815
3816 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3817 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3818 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3819}
3820
3821TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3822 MediaSessionOptions options;
3823 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3824 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3825 &options);
3826
3827 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3828 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3829 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3830
3831 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3832 std::unique_ptr<SessionDescription> answer =
3833 f1_.CreateAnswer(offer.get(), options, nullptr);
3834
3835 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3836 "foo");
3837 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3838 "bar");
3839 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3840}
3841
3842TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3843 MediaSessionOptions options;
3844 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3845 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3846 &options);
3847
3848 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3849
3850 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3851 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3852 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3853
3854 std::unique_ptr<SessionDescription> answer =
3855 f1_.CreateAnswer(offer.get(), options, nullptr);
3856
3857 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3858 absl::nullopt);
3859 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3860 absl::nullopt);
3861 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3862 absl::nullopt);
3863}
3864
3865TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3866 MediaSessionOptions options;
3867 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3868 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3869 &options);
3870
3871 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3872 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3873 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3874
3875 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3876
3877 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3878 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3879 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3880
3881 std::unique_ptr<SessionDescription> answer =
3882 f1_.CreateAnswer(offer.get(), options, nullptr);
3883
3884 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3885 absl::nullopt);
3886 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3887 absl::nullopt);
3888 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3889 absl::nullopt);
3890}
3891
3892TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3893 MediaSessionOptions options;
3894 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3895 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3896 &options);
3897
3898 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3899 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3900 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3901
3902 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3903
3904 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3905 absl::nullopt;
3906 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3907 absl::nullopt;
3908 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3909 absl::nullopt;
3910
3911 std::unique_ptr<SessionDescription> answer =
3912 f1_.CreateAnswer(offer.get(), options, nullptr);
3913
3914 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3915 absl::nullopt);
3916 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3917 absl::nullopt);
3918 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3919 absl::nullopt);
3920}
3921
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003922// Create an offer with bundle enabled and verify the crypto parameters are
3923// the common set of the available cryptos.
3924TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3925 TestCryptoWithBundle(true);
3926}
3927
3928// Create an answer with bundle enabled and verify the crypto parameters are
3929// the common set of the available cryptos.
3930TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3931 TestCryptoWithBundle(false);
3932}
3933
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003934// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3935// DTLS is not enabled locally.
3936TEST_F(MediaSessionDescriptionFactoryTest,
3937 TestOfferDtlsSavpfWithoutDtlsFailed) {
3938 f1_.set_secure(SEC_ENABLED);
3939 f2_.set_secure(SEC_ENABLED);
3940 tdf1_.set_secure(SEC_DISABLED);
3941 tdf2_.set_secure(SEC_DISABLED);
3942
Steve Anton6fe1fba2018-12-11 10:15:23 -08003943 std::unique_ptr<SessionDescription> offer =
3944 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003945 ASSERT_TRUE(offer.get() != NULL);
3946 ContentInfo* offer_content = offer->GetContentByName("audio");
3947 ASSERT_TRUE(offer_content != NULL);
3948 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003949 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003950 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3951
Steve Anton6fe1fba2018-12-11 10:15:23 -08003952 std::unique_ptr<SessionDescription> answer =
3953 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003954 ASSERT_TRUE(answer != NULL);
3955 ContentInfo* answer_content = answer->GetContentByName("audio");
3956 ASSERT_TRUE(answer_content != NULL);
3957
3958 ASSERT_TRUE(answer_content->rejected);
3959}
3960
3961// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3962// UDP/TLS/RTP/SAVPF.
3963TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3964 f1_.set_secure(SEC_ENABLED);
3965 f2_.set_secure(SEC_ENABLED);
3966 tdf1_.set_secure(SEC_ENABLED);
3967 tdf2_.set_secure(SEC_ENABLED);
3968
Steve Anton6fe1fba2018-12-11 10:15:23 -08003969 std::unique_ptr<SessionDescription> offer =
3970 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003971 ASSERT_TRUE(offer.get() != NULL);
3972 ContentInfo* offer_content = offer->GetContentByName("audio");
3973 ASSERT_TRUE(offer_content != NULL);
3974 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003975 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003976 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3977
Steve Anton6fe1fba2018-12-11 10:15:23 -08003978 std::unique_ptr<SessionDescription> answer =
3979 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003980 ASSERT_TRUE(answer != NULL);
3981
3982 const ContentInfo* answer_content = answer->GetContentByName("audio");
3983 ASSERT_TRUE(answer_content != NULL);
3984 ASSERT_FALSE(answer_content->rejected);
3985
3986 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003987 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003988 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003989}
3990
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003991// Test that we include both SDES and DTLS in the offer, but only include SDES
3992// in the answer if DTLS isn't negotiated.
3993TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3994 f1_.set_secure(SEC_ENABLED);
3995 f2_.set_secure(SEC_ENABLED);
3996 tdf1_.set_secure(SEC_ENABLED);
3997 tdf2_.set_secure(SEC_DISABLED);
3998 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003999 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08004000 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004001 const cricket::MediaContentDescription* audio_media_desc;
4002 const cricket::MediaContentDescription* video_media_desc;
4003 const cricket::TransportDescription* audio_trans_desc;
4004 const cricket::TransportDescription* video_trans_desc;
4005
4006 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004007 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004008 ASSERT_TRUE(offer.get() != NULL);
4009
Steve Antonb1c1de12017-12-21 15:14:30 -08004010 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004011 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004012 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004013 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07004014 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004015 EXPECT_EQ(1u, video_media_desc->cryptos().size());
4016
4017 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
4018 ASSERT_TRUE(audio_trans_desc != NULL);
4019 video_trans_desc = offer->GetTransportDescriptionByName("video");
4020 ASSERT_TRUE(video_trans_desc != NULL);
4021 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
4022 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
4023
4024 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004025 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004026 ASSERT_TRUE(answer.get() != NULL);
4027
Steve Antonb1c1de12017-12-21 15:14:30 -08004028 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004029 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004030 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004031 ASSERT_TRUE(video_media_desc != NULL);
4032 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
4033 EXPECT_EQ(1u, video_media_desc->cryptos().size());
4034
4035 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
4036 ASSERT_TRUE(audio_trans_desc != NULL);
4037 video_trans_desc = answer->GetTransportDescriptionByName("video");
4038 ASSERT_TRUE(video_trans_desc != NULL);
4039 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
4040 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
4041
4042 // Enable DTLS; the answer should now only have DTLS support.
4043 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004044 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004045 ASSERT_TRUE(answer.get() != NULL);
4046
Steve Antonb1c1de12017-12-21 15:14:30 -08004047 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004048 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004049 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004050 ASSERT_TRUE(video_media_desc != NULL);
4051 EXPECT_TRUE(audio_media_desc->cryptos().empty());
4052 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08004053 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
4054 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004055
4056 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
4057 ASSERT_TRUE(audio_trans_desc != NULL);
4058 video_trans_desc = answer->GetTransportDescriptionByName("video");
4059 ASSERT_TRUE(video_trans_desc != NULL);
4060 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
4061 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00004062
4063 // Try creating offer again. DTLS enabled now, crypto's should be empty
4064 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004065 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00004066 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004067 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00004068 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004069 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00004070 ASSERT_TRUE(video_media_desc != NULL);
4071 EXPECT_TRUE(audio_media_desc->cryptos().empty());
4072 EXPECT_TRUE(video_media_desc->cryptos().empty());
4073
4074 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
4075 ASSERT_TRUE(audio_trans_desc != NULL);
4076 video_trans_desc = offer->GetTransportDescriptionByName("video");
4077 ASSERT_TRUE(video_trans_desc != NULL);
4078 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
4079 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004080}
4081
4082// Test that an answer can't be created if cryptos are required but the offer is
4083// unsecure.
4084TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004085 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004086 f1_.set_secure(SEC_DISABLED);
4087 tdf1_.set_secure(SEC_DISABLED);
4088 f2_.set_secure(SEC_REQUIRED);
4089 tdf1_.set_secure(SEC_ENABLED);
4090
Steve Anton6fe1fba2018-12-11 10:15:23 -08004091 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004092 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004093 std::unique_ptr<SessionDescription> answer =
4094 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004095 EXPECT_TRUE(answer.get() == NULL);
4096}
4097
4098// Test that we accept a DTLS offer without SDES and create an appropriate
4099// answer.
4100TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
4101 f1_.set_secure(SEC_DISABLED);
4102 f2_.set_secure(SEC_ENABLED);
4103 tdf1_.set_secure(SEC_ENABLED);
4104 tdf2_.set_secure(SEC_ENABLED);
4105 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004106 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
4107 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
4108 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004109
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004110 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004111 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004112 ASSERT_TRUE(offer.get() != NULL);
4113
4114 const AudioContentDescription* audio_offer =
4115 GetFirstAudioContentDescription(offer.get());
4116 ASSERT_TRUE(audio_offer->cryptos().empty());
4117 const VideoContentDescription* video_offer =
4118 GetFirstVideoContentDescription(offer.get());
4119 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004120 const RtpDataContentDescription* data_offer =
4121 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004122 ASSERT_TRUE(data_offer->cryptos().empty());
4123
4124 const cricket::TransportDescription* audio_offer_trans_desc =
4125 offer->GetTransportDescriptionByName("audio");
4126 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
4127 const cricket::TransportDescription* video_offer_trans_desc =
4128 offer->GetTransportDescriptionByName("video");
4129 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
4130 const cricket::TransportDescription* data_offer_trans_desc =
4131 offer->GetTransportDescriptionByName("data");
4132 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
4133
4134 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004135 std::unique_ptr<SessionDescription> answer =
4136 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004137 ASSERT_TRUE(answer.get() != NULL);
4138
4139 const cricket::TransportDescription* audio_answer_trans_desc =
4140 answer->GetTransportDescriptionByName("audio");
4141 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
4142 const cricket::TransportDescription* video_answer_trans_desc =
4143 answer->GetTransportDescriptionByName("video");
4144 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
4145 const cricket::TransportDescription* data_answer_trans_desc =
4146 answer->GetTransportDescriptionByName("data");
4147 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
4148}
4149
4150// Verifies if vad_enabled option is set to false, CN codecs are not present in
4151// offer or answer.
4152TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
4153 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08004154 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004155 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004156 ASSERT_TRUE(offer.get() != NULL);
4157 const ContentInfo* audio_content = offer->GetContentByName("audio");
4158 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
4159
4160 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08004161 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004162 ASSERT_TRUE(offer.get() != NULL);
4163 audio_content = offer->GetContentByName("audio");
4164 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08004165 std::unique_ptr<SessionDescription> answer =
4166 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004167 ASSERT_TRUE(answer.get() != NULL);
4168 audio_content = answer->GetContentByName("audio");
4169 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
4170}
deadbeef44f08192015-12-15 16:20:09 -08004171
zhihuang1c378ed2017-08-17 14:10:50 -07004172// Test that the generated MIDs match the existing offer.
4173TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08004174 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004175 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
4176 RtpTransceiverDirection::kRecvOnly, kActive,
4177 &opts);
4178 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
4179 RtpTransceiverDirection::kRecvOnly, kActive,
4180 &opts);
deadbeef44f08192015-12-15 16:20:09 -08004181 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004182 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
4183 RtpTransceiverDirection::kSendRecv, kActive,
4184 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004185 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004186 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08004187 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08004188 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07004189
deadbeef44f08192015-12-15 16:20:09 -08004190 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
4191 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
4192 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
4193 ASSERT_TRUE(audio_content != nullptr);
4194 ASSERT_TRUE(video_content != nullptr);
4195 ASSERT_TRUE(data_content != nullptr);
4196 EXPECT_EQ("audio_modified", audio_content->name);
4197 EXPECT_EQ("video_modified", video_content->name);
4198 EXPECT_EQ("data_modified", data_content->name);
4199}
zhihuangcf5b37c2016-05-05 11:44:35 -07004200
zhihuang1c378ed2017-08-17 14:10:50 -07004201// The following tests verify that the unified plan SDP is supported.
4202// Test that we can create an offer with multiple media sections of same media
4203// type.
4204TEST_F(MediaSessionDescriptionFactoryTest,
4205 CreateOfferWithMultipleAVMediaSections) {
4206 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004207 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4208 RtpTransceiverDirection::kSendRecv, kActive,
4209 &opts);
4210 AttachSenderToMediaDescriptionOptions(
4211 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004212
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004213 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4214 RtpTransceiverDirection::kSendRecv, kActive,
4215 &opts);
4216 AttachSenderToMediaDescriptionOptions(
4217 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004218
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004219 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4220 RtpTransceiverDirection::kSendRecv, kActive,
4221 &opts);
4222 AttachSenderToMediaDescriptionOptions(
4223 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004224
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004225 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4226 RtpTransceiverDirection::kSendRecv, kActive,
4227 &opts);
4228 AttachSenderToMediaDescriptionOptions(
4229 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004230 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004231 ASSERT_TRUE(offer);
4232
4233 ASSERT_EQ(4u, offer->contents().size());
4234 EXPECT_FALSE(offer->contents()[0].rejected);
4235 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004236 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004237 ASSERT_EQ(1u, acd->streams().size());
4238 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004239 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004240
4241 EXPECT_FALSE(offer->contents()[1].rejected);
4242 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004243 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004244 ASSERT_EQ(1u, vcd->streams().size());
4245 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004246 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004247
4248 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004249 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004250 ASSERT_EQ(1u, acd->streams().size());
4251 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004252 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004253
4254 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004255 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004256 ASSERT_EQ(1u, vcd->streams().size());
4257 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004258 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004259}
4260
4261// Test that we can create an answer with multiple media sections of same media
4262// type.
4263TEST_F(MediaSessionDescriptionFactoryTest,
4264 CreateAnswerWithMultipleAVMediaSections) {
4265 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004266 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4267 RtpTransceiverDirection::kSendRecv, kActive,
4268 &opts);
4269 AttachSenderToMediaDescriptionOptions(
4270 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004271
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004272 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4273 RtpTransceiverDirection::kSendRecv, kActive,
4274 &opts);
4275 AttachSenderToMediaDescriptionOptions(
4276 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004277
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004278 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4279 RtpTransceiverDirection::kSendRecv, kActive,
4280 &opts);
4281 AttachSenderToMediaDescriptionOptions(
4282 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004283
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004284 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4285 RtpTransceiverDirection::kSendRecv, kActive,
4286 &opts);
4287 AttachSenderToMediaDescriptionOptions(
4288 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004289
Steve Anton6fe1fba2018-12-11 10:15:23 -08004290 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004291 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004292 std::unique_ptr<SessionDescription> answer =
4293 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004294
4295 ASSERT_EQ(4u, answer->contents().size());
4296 EXPECT_FALSE(answer->contents()[0].rejected);
4297 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004298 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004299 ASSERT_EQ(1u, acd->streams().size());
4300 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004301 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004302
4303 EXPECT_FALSE(answer->contents()[1].rejected);
4304 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004305 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004306 ASSERT_EQ(1u, vcd->streams().size());
4307 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004308 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004309
4310 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004311 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004312 ASSERT_EQ(1u, acd->streams().size());
4313 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004314 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004315
4316 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004317 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004318 ASSERT_EQ(1u, vcd->streams().size());
4319 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004320 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004321}
4322
4323// Test that the media section will be rejected in offer if the corresponding
4324// MediaDescriptionOptions is stopped by the offerer.
4325TEST_F(MediaSessionDescriptionFactoryTest,
4326 CreateOfferWithMediaSectionStoppedByOfferer) {
4327 // Create an offer with two audio sections and one of them is stopped.
4328 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004329 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4330 RtpTransceiverDirection::kSendRecv, kActive,
4331 &offer_opts);
4332 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4333 RtpTransceiverDirection::kInactive, kStopped,
4334 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004335 std::unique_ptr<SessionDescription> offer =
4336 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004337 ASSERT_TRUE(offer);
4338 ASSERT_EQ(2u, offer->contents().size());
4339 EXPECT_FALSE(offer->contents()[0].rejected);
4340 EXPECT_TRUE(offer->contents()[1].rejected);
4341}
4342
4343// Test that the media section will be rejected in answer if the corresponding
4344// MediaDescriptionOptions is stopped by the offerer.
4345TEST_F(MediaSessionDescriptionFactoryTest,
4346 CreateAnswerWithMediaSectionStoppedByOfferer) {
4347 // Create an offer with two audio sections and one of them is stopped.
4348 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004349 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4350 RtpTransceiverDirection::kSendRecv, kActive,
4351 &offer_opts);
4352 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4353 RtpTransceiverDirection::kInactive, kStopped,
4354 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004355 std::unique_ptr<SessionDescription> offer =
4356 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004357 ASSERT_TRUE(offer);
4358 ASSERT_EQ(2u, offer->contents().size());
4359 EXPECT_FALSE(offer->contents()[0].rejected);
4360 EXPECT_TRUE(offer->contents()[1].rejected);
4361
4362 // Create an answer based on the offer.
4363 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004364 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4365 RtpTransceiverDirection::kSendRecv, kActive,
4366 &answer_opts);
4367 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4368 RtpTransceiverDirection::kSendRecv, kActive,
4369 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004370 std::unique_ptr<SessionDescription> answer =
4371 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004372 ASSERT_EQ(2u, answer->contents().size());
4373 EXPECT_FALSE(answer->contents()[0].rejected);
4374 EXPECT_TRUE(answer->contents()[1].rejected);
4375}
4376
4377// Test that the media section will be rejected in answer if the corresponding
4378// MediaDescriptionOptions is stopped by the answerer.
4379TEST_F(MediaSessionDescriptionFactoryTest,
4380 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4381 // Create an offer with two audio sections.
4382 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004383 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4384 RtpTransceiverDirection::kSendRecv, kActive,
4385 &offer_opts);
4386 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4387 RtpTransceiverDirection::kSendRecv, kActive,
4388 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004389 std::unique_ptr<SessionDescription> offer =
4390 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004391 ASSERT_TRUE(offer);
4392 ASSERT_EQ(2u, offer->contents().size());
4393 ASSERT_FALSE(offer->contents()[0].rejected);
4394 ASSERT_FALSE(offer->contents()[1].rejected);
4395
4396 // The answerer rejects one of the audio sections.
4397 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004398 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4399 RtpTransceiverDirection::kSendRecv, kActive,
4400 &answer_opts);
4401 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4402 RtpTransceiverDirection::kInactive, kStopped,
4403 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004404 std::unique_ptr<SessionDescription> answer =
4405 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004406 ASSERT_EQ(2u, answer->contents().size());
4407 EXPECT_FALSE(answer->contents()[0].rejected);
4408 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004409
4410 // The TransportInfo of the rejected m= section is expected to be added in the
4411 // answer.
4412 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004413}
4414
4415// Test the generated media sections has the same order of the
4416// corresponding MediaDescriptionOptions.
4417TEST_F(MediaSessionDescriptionFactoryTest,
4418 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4419 MediaSessionOptions opts;
4420 // This tests put video section first because normally audio comes first by
4421 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004422 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4423 RtpTransceiverDirection::kSendRecv, kActive,
4424 &opts);
4425 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4426 RtpTransceiverDirection::kSendRecv, kActive,
4427 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004428 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004429
4430 ASSERT_TRUE(offer);
4431 ASSERT_EQ(2u, offer->contents().size());
4432 EXPECT_EQ("video", offer->contents()[0].name);
4433 EXPECT_EQ("audio", offer->contents()[1].name);
4434}
4435
4436// Test that different media sections using the same codec have same payload
4437// type.
4438TEST_F(MediaSessionDescriptionFactoryTest,
4439 PayloadTypesSharedByMediaSectionsOfSameType) {
4440 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004441 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4442 RtpTransceiverDirection::kSendRecv, kActive,
4443 &opts);
4444 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4445 RtpTransceiverDirection::kSendRecv, kActive,
4446 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004447 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004448 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004449 ASSERT_TRUE(offer);
4450 ASSERT_EQ(2u, offer->contents().size());
4451 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004452 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004453 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004454 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004455 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4456 ASSERT_EQ(2u, vcd1->codecs().size());
4457 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4458 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4459 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4460 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4461
4462 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004463 std::unique_ptr<SessionDescription> answer =
4464 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004465 ASSERT_TRUE(answer);
4466 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004467 vcd1 = answer->contents()[0].media_description()->as_video();
4468 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004469 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4470 ASSERT_EQ(1u, vcd1->codecs().size());
4471 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4472 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4473}
4474
4475// Test that the codec preference order per media section is respected in
4476// subsequent offer.
4477TEST_F(MediaSessionDescriptionFactoryTest,
4478 CreateOfferRespectsCodecPreferenceOrder) {
4479 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004480 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4481 RtpTransceiverDirection::kSendRecv, kActive,
4482 &opts);
4483 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4484 RtpTransceiverDirection::kSendRecv, kActive,
4485 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004486 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004487 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004488 ASSERT_TRUE(offer);
4489 ASSERT_EQ(2u, offer->contents().size());
4490 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004491 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004492 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004493 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004494 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4495 EXPECT_EQ(video_codecs, vcd1->codecs());
4496 EXPECT_EQ(video_codecs, vcd2->codecs());
4497
4498 // Change the codec preference of the first video section and create a
4499 // follow-up offer.
4500 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4501 vcd1->set_codecs(video_codecs_reverse);
4502 std::unique_ptr<SessionDescription> updated_offer(
4503 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004504 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4505 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004506 // The video codec preference order should be respected.
4507 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4508 EXPECT_EQ(video_codecs, vcd2->codecs());
4509}
4510
4511// Test that the codec preference order per media section is respected in
4512// the answer.
4513TEST_F(MediaSessionDescriptionFactoryTest,
4514 CreateAnswerRespectsCodecPreferenceOrder) {
4515 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004516 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4517 RtpTransceiverDirection::kSendRecv, kActive,
4518 &opts);
4519 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4520 RtpTransceiverDirection::kSendRecv, kActive,
4521 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004522 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004523 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004524 ASSERT_TRUE(offer);
4525 ASSERT_EQ(2u, offer->contents().size());
4526 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004527 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004528 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004529 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004530 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4531 EXPECT_EQ(video_codecs, vcd1->codecs());
4532 EXPECT_EQ(video_codecs, vcd2->codecs());
4533
4534 // Change the codec preference of the first video section and create an
4535 // answer.
4536 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4537 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004538 std::unique_ptr<SessionDescription> answer =
4539 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004540 vcd1 = answer->contents()[0].media_description()->as_video();
4541 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004542 // The video codec preference order should be respected.
4543 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4544 EXPECT_EQ(video_codecs, vcd2->codecs());
4545}
4546
Zhi Huang6f367472017-11-22 13:20:02 -08004547// Test that when creating an answer, the codecs use local parameters instead of
4548// the remote ones.
4549TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4550 const std::string audio_param_name = "audio_param";
4551 const std::string audio_value1 = "audio_v1";
4552 const std::string audio_value2 = "audio_v2";
4553 const std::string video_param_name = "video_param";
4554 const std::string video_value1 = "video_v1";
4555 const std::string video_value2 = "video_v2";
4556
4557 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4558 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4559 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4560 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4561
4562 // Set the parameters for codecs.
4563 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4564 video_codecs1[0].SetParam(video_param_name, video_value1);
4565 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4566 video_codecs2[0].SetParam(video_param_name, video_value2);
4567
4568 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004569 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004570 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004571 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004572
4573 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004574 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4575 RtpTransceiverDirection::kSendRecv, kActive,
4576 &opts);
4577 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4578 RtpTransceiverDirection::kSendRecv, kActive,
4579 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004580
Steve Anton6fe1fba2018-12-11 10:15:23 -08004581 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004582 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004583 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4584 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004585 std::string value;
4586 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4587 EXPECT_EQ(audio_value1, value);
4588 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4589 EXPECT_EQ(video_value1, value);
4590
Steve Anton6fe1fba2018-12-11 10:15:23 -08004591 std::unique_ptr<SessionDescription> answer =
4592 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004593 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004594 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4595 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004596 // Use the parameters from the local codecs.
4597 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4598 EXPECT_EQ(audio_value2, value);
4599 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4600 EXPECT_EQ(video_value2, value);
4601}
4602
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004603// Test that matching packetization-mode is part of the criteria for matching
4604// H264 codecs (in addition to profile-level-id). Previously, this was not the
4605// case, so the first H264 codec with the same profile-level-id would match and
4606// the payload type in the answer would be incorrect.
4607// This is a regression test for bugs.webrtc.org/8808
4608TEST_F(MediaSessionDescriptionFactoryTest,
4609 H264MatchCriteriaIncludesPacketizationMode) {
4610 // Create two H264 codecs with the same profile level ID and different
4611 // packetization modes.
4612 VideoCodec h264_pm0(96, "H264");
4613 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4614 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4615 VideoCodec h264_pm1(97, "H264");
4616 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4617 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4618
4619 // Offerer will send both codecs, answerer should choose the one with matching
4620 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004621 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4622 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004623
4624 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004625 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4626 RtpTransceiverDirection::kSendRecv, kActive,
4627 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004628
Steve Anton6fe1fba2018-12-11 10:15:23 -08004629 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004630 ASSERT_TRUE(offer);
4631
Steve Anton6fe1fba2018-12-11 10:15:23 -08004632 std::unique_ptr<SessionDescription> answer =
4633 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004634 ASSERT_TRUE(answer);
4635
4636 // Answer should have one negotiated codec with packetization-mode=1 using the
4637 // offered payload type.
4638 ASSERT_EQ(1u, answer->contents().size());
4639 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4640 ASSERT_EQ(1u, answer_vcd->codecs().size());
4641 auto answer_codec = answer_vcd->codecs()[0];
4642 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4643}
4644
zhihuangcf5b37c2016-05-05 11:44:35 -07004645class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4646 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004647 MediaProtocolTest()
4648 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004649 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4650 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004651 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4652 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004653 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004654 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4655 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004656 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4657 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004658 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004659 f1_.set_secure(SEC_ENABLED);
4660 f2_.set_secure(SEC_ENABLED);
4661 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004662 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004663 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004664 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004665 tdf1_.set_secure(SEC_ENABLED);
4666 tdf2_.set_secure(SEC_ENABLED);
4667 }
4668
4669 protected:
4670 MediaSessionDescriptionFactory f1_;
4671 MediaSessionDescriptionFactory f2_;
4672 TransportDescriptionFactory tdf1_;
4673 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004674 UniqueRandomIdGenerator ssrc_generator1;
4675 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004676};
4677
4678TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4679 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004680 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004681 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004682 ASSERT_TRUE(offer.get() != nullptr);
4683 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004684 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004685 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004686 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004687 std::unique_ptr<SessionDescription> answer =
4688 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004689 const ContentInfo* ac = answer->GetContentByName("audio");
4690 const ContentInfo* vc = answer->GetContentByName("video");
4691 ASSERT_TRUE(ac != nullptr);
4692 ASSERT_TRUE(vc != nullptr);
4693 EXPECT_FALSE(ac->rejected); // the offer is accepted
4694 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004695 const AudioContentDescription* acd = ac->media_description()->as_audio();
4696 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004697 EXPECT_EQ(GetParam(), acd->protocol());
4698 EXPECT_EQ(GetParam(), vcd->protocol());
4699}
4700
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004701INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4702 MediaProtocolTest,
4703 ::testing::ValuesIn(kMediaProtocols));
4704INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4705 MediaProtocolTest,
4706 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004707
4708TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4709 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004710 UniqueRandomIdGenerator ssrc_generator;
4711 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004712 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4713 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4714
4715 // The merged list of codecs should contain any send codecs that are also
4716 // nominally in the recieve codecs list. Payload types should be picked from
4717 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4718 // (set to 1). This equals what happens when the send codecs are used in an
4719 // offer and the receive codecs are used in the following answer.
4720 const std::vector<AudioCodec> sendrecv_codecs =
4721 MAKE_VECTOR(kAudioCodecsAnswer);
4722 const std::vector<AudioCodec> no_codecs;
4723
4724 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4725 << "Please don't change shared test data!";
4726 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4727 << "Please don't change shared test data!";
4728 // Alter iLBC send codec to have zero channels, to test that that is handled
4729 // properly.
4730 send_codecs[1].channels = 0;
4731
Philipp Hanckeb41316c2020-05-26 13:45:20 +02004732 // Alter iLBC receive codec to be lowercase, to test that case conversions
ossu075af922016-06-14 03:29:38 -07004733 // are handled properly.
4734 recv_codecs[2].name = "ilbc";
4735
4736 // Test proper merge
4737 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004738 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4739 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4740 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004741
4742 // Test empty send codecs list
4743 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004744 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4745 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4746 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004747
4748 // Test empty recv codecs list
4749 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004750 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4751 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4752 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004753
4754 // Test all empty codec lists
4755 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004756 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4757 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4758 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004759}
4760
4761namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004762// Compare the two vectors of codecs ignoring the payload type.
4763template <class Codec>
4764bool CodecsMatch(const std::vector<Codec>& codecs1,
4765 const std::vector<Codec>& codecs2) {
4766 if (codecs1.size() != codecs2.size()) {
4767 return false;
4768 }
4769
4770 for (size_t i = 0; i < codecs1.size(); ++i) {
4771 if (!codecs1[i].Matches(codecs2[i])) {
4772 return false;
4773 }
4774 }
4775 return true;
4776}
4777
Steve Anton4e70a722017-11-28 14:57:10 -08004778void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004779 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004780 UniqueRandomIdGenerator ssrc_generator;
4781 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004782 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4783 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4784 const std::vector<AudioCodec> sendrecv_codecs =
4785 MAKE_VECTOR(kAudioCodecsAnswer);
4786 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004787
4788 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004789 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4790 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004791
Steve Anton4e70a722017-11-28 14:57:10 -08004792 if (direction == RtpTransceiverDirection::kSendRecv ||
4793 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004794 AttachSenderToMediaDescriptionOptions(
4795 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004796 }
ossu075af922016-06-14 03:29:38 -07004797
Steve Anton6fe1fba2018-12-11 10:15:23 -08004798 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004799 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004800 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004801
4802 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004803 // that the codecs put in are right. This happens when we neither want to
4804 // send nor receive audio. The checks are still in place if at some point
4805 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004806 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004807 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004808 // sendrecv and inactive should both present lists as if the channel was
4809 // to be used for sending and receiving. Inactive essentially means it
4810 // might eventually be used anything, but we don't know more at this
4811 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004812 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004813 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004814 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004815 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004816 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004817 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004818 }
4819 }
4820}
4821
4822static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004823 AudioCodec(0, "codec0", 16000, -1, 1),
4824 AudioCodec(1, "codec1", 8000, 13300, 1),
4825 AudioCodec(2, "codec2", 8000, 64000, 1),
4826 AudioCodec(3, "codec3", 8000, 64000, 1),
4827 AudioCodec(4, "codec4", 8000, 0, 2),
4828 AudioCodec(5, "codec5", 32000, 0, 1),
4829 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004830
zhihuang1c378ed2017-08-17 14:10:50 -07004831/* The codecs groups below are chosen as per the matrix below. The objective
4832 * is to have different sets of codecs in the inputs, to get unique sets of
4833 * codecs after negotiation, depending on offer and answer communication
4834 * directions. One-way directions in the offer should either result in the
4835 * opposite direction in the answer, or an inactive answer. Regardless, the
4836 * choice of codecs should be as if the answer contained the opposite
4837 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004838 *
4839 * | Offer | Answer | Result
4840 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4841 * 0 | x - - | - x - | x - - - -
4842 * 1 | x x x | - x - | x - - x -
4843 * 2 | - x - | x - - | - x - - -
4844 * 3 | x x x | x - - | - x x - -
4845 * 4 | - x - | x x x | - x - - -
4846 * 5 | x - - | x x x | x - - - -
4847 * 6 | x x x | x x x | x x x x x
4848 */
4849// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004850static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4851static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004852// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4853// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004854static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4855static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004856// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004857static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4858static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4859static const int kResultSendrecv_SendCodecs[] = {3, 6};
4860static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4861static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004862
4863template <typename T, int IDXS>
4864std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4865 std::vector<T> out;
4866 out.reserve(IDXS);
4867 for (int idx : indices)
4868 out.push_back(array[idx]);
4869
4870 return out;
4871}
4872
Steve Anton4e70a722017-11-28 14:57:10 -08004873void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4874 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004875 bool add_legacy_stream) {
4876 TransportDescriptionFactory offer_tdf;
4877 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004878 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4879 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4880 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004881 offer_factory.set_audio_codecs(
4882 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4883 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4884 answer_factory.set_audio_codecs(
4885 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4886 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4887
ossu075af922016-06-14 03:29:38 -07004888 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004889 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4890 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004891
Steve Anton4e70a722017-11-28 14:57:10 -08004892 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004893 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4894 kAudioTrack1, {kMediaStream1}, 1,
4895 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004896 }
4897
Steve Anton6fe1fba2018-12-11 10:15:23 -08004898 std::unique_ptr<SessionDescription> offer =
4899 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004900 ASSERT_TRUE(offer.get() != NULL);
4901
4902 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004903 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4904 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004905
Steve Anton4e70a722017-11-28 14:57:10 -08004906 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004907 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4908 kAudioTrack1, {kMediaStream1}, 1,
4909 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004910 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004911 std::unique_ptr<SessionDescription> answer =
4912 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004913 const ContentInfo* ac = answer->GetContentByName("audio");
4914
zhihuang1c378ed2017-08-17 14:10:50 -07004915 // If the factory didn't add any audio content to the answer, we cannot
4916 // check that the codecs put in are right. This happens when we neither want
4917 // to send nor receive audio. The checks are still in place if at some point
4918 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004919 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004920 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4921 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004922
ossu075af922016-06-14 03:29:38 -07004923 std::vector<AudioCodec> target_codecs;
4924 // For offers with sendrecv or inactive, we should never reply with more
4925 // codecs than offered, with these codec sets.
4926 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004927 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004928 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4929 kResultSendrecv_SendrecvCodecs);
4930 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004931 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004932 target_codecs =
4933 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004934 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004935 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004936 target_codecs =
4937 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004938 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004939 case RtpTransceiverDirection::kSendRecv:
4940 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004941 target_codecs =
4942 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004943 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004944 target_codecs =
4945 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004946 } else {
4947 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4948 kResultSendrecv_SendrecvCodecs);
4949 }
4950 break;
Markus Handell45c104b2020-03-11 10:51:13 +01004951 default:
4952 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004953 }
4954
zhihuang1c378ed2017-08-17 14:10:50 -07004955 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004956 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004957 bool first = true;
4958 os << "{";
4959 for (const auto& c : codecs) {
4960 os << (first ? " " : ", ") << c.id;
4961 first = false;
4962 }
4963 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004964 return os.Release();
ossu075af922016-06-14 03:29:38 -07004965 };
4966
4967 EXPECT_TRUE(acd->codecs() == target_codecs)
4968 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004969 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4970 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004971 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004972 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4973 << "; got: "
4974 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004975 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004976 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004977 << "Only inactive offers are allowed to not generate any audio "
4978 "content";
ossu075af922016-06-14 03:29:38 -07004979 }
4980}
brandtr03d5fb12016-11-22 03:37:59 -08004981
4982} // namespace
ossu075af922016-06-14 03:29:38 -07004983
4984class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004985 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004986
4987TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004988 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004989}
4990
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004991INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4992 AudioCodecsOfferTest,
4993 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4994 RtpTransceiverDirection::kRecvOnly,
4995 RtpTransceiverDirection::kSendRecv,
4996 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004997
4998class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004999 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
5000 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07005001 bool>> {};
ossu075af922016-06-14 03:29:38 -07005002
5003TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08005004 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
5005 ::testing::get<1>(GetParam()),
5006 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07005007}
5008
Mirko Bonadeic84f6612019-01-31 12:20:57 +01005009INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07005010 MediaSessionDescriptionFactoryTest,
5011 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08005012 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
5013 RtpTransceiverDirection::kRecvOnly,
5014 RtpTransceiverDirection::kSendRecv,
5015 RtpTransceiverDirection::kInactive),
5016 ::testing::Values(RtpTransceiverDirection::kSendOnly,
5017 RtpTransceiverDirection::kRecvOnly,
5018 RtpTransceiverDirection::kSendRecv,
5019 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07005020 ::testing::Bool()));