blob: 1a4b507c2b8a328ed1a0092edb14ae8b83cef70b [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
416// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
417// was designed for Plan B SDP, where only one audio "m=" section and one video
418// "m=" section could be generated, and ordering couldn't be controlled. Many of
419// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200420class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800422 MediaSessionDescriptionFactoryTest()
423 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700424 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
425 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200426 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
427 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200428 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700429 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
430 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200431 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
432 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200433 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200434 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700435 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200436 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700437 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 }
439
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000440 // Create a video StreamParamsVec object with:
441 // - one video stream with 3 simulcast streams and FEC,
442 StreamParamsVec CreateComplexVideoStreamParamsVec() {
443 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
444 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
445 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
446 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
447
448 std::vector<SsrcGroup> ssrc_groups;
449 ssrc_groups.push_back(sim_group);
450 ssrc_groups.push_back(fec_group1);
451 ssrc_groups.push_back(fec_group2);
452 ssrc_groups.push_back(fec_group3);
453
454 StreamParams simulcast_params;
455 simulcast_params.id = kVideoTrack1;
456 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
457 simulcast_params.ssrc_groups = ssrc_groups;
458 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800459 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000460
461 StreamParamsVec video_streams;
462 video_streams.push_back(simulcast_params);
463
464 return video_streams;
465 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000466
467 bool CompareCryptoParams(const CryptoParamsVec& c1,
468 const CryptoParamsVec& c2) {
469 if (c1.size() != c2.size())
470 return false;
471 for (size_t i = 0; i < c1.size(); ++i)
472 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
473 c1[i].key_params != c2[i].key_params ||
474 c1[i].session_params != c2[i].session_params)
475 return false;
476 return true;
477 }
478
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700479 // Returns true if the transport info contains "renomination" as an
480 // ICE option.
481 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800482 return absl::c_linear_search(transport_info->description.transport_options,
483 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700484 }
485
zhihuang1c378ed2017-08-17 14:10:50 -0700486 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700487 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000488 bool has_current_desc) {
489 const std::string current_audio_ufrag = "current_audio_ufrag";
490 const std::string current_audio_pwd = "current_audio_pwd";
491 const std::string current_video_ufrag = "current_video_ufrag";
492 const std::string current_video_pwd = "current_video_pwd";
493 const std::string current_data_ufrag = "current_data_ufrag";
494 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800495 std::unique_ptr<SessionDescription> current_desc;
496 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200498 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800499 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200500 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800501 TransportDescription(current_audio_ufrag, current_audio_pwd)));
502 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200503 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800504 TransportDescription(current_video_ufrag, current_video_pwd)));
505 current_desc->AddTransportInfo(TransportInfo(
506 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 }
508 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800509 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 } else {
kwiberg31022942016-03-11 14:18:21 -0800511 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800512 offer = f1_.CreateOffer(options, NULL);
513 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 }
515 ASSERT_TRUE(desc.get() != NULL);
516 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000517 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 EXPECT_TRUE(ti_audio != NULL);
519 if (has_current_desc) {
520 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
521 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
522 } else {
523 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
524 ti_audio->description.ice_ufrag.size());
525 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
526 ti_audio->description.ice_pwd.size());
527 }
zhihuang1c378ed2017-08-17 14:10:50 -0700528 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700529 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700530 EXPECT_EQ(
531 media_desc_options_it->transport_options.enable_ice_renomination,
532 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700533 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
534 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535
536 } else {
537 EXPECT_TRUE(ti_audio == NULL);
538 }
539 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000540 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700542 auto media_desc_options_it =
543 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 if (options.bundle_enabled) {
545 EXPECT_EQ(ti_audio->description.ice_ufrag,
546 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200547 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700548 EXPECT_EQ(ti_audio->description.opaque_parameters,
549 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 } else {
551 if (has_current_desc) {
552 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
553 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
554 } else {
555 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
556 ti_video->description.ice_ufrag.size());
557 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
558 ti_video->description.ice_pwd.size());
559 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700560 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
561 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 }
zhihuang1c378ed2017-08-17 14:10:50 -0700563 EXPECT_EQ(
564 media_desc_options_it->transport_options.enable_ice_renomination,
565 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 } else {
567 EXPECT_TRUE(ti_video == NULL);
568 }
569 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
570 if (options.has_data()) {
571 EXPECT_TRUE(ti_data != NULL);
572 if (options.bundle_enabled) {
573 EXPECT_EQ(ti_audio->description.ice_ufrag,
574 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200575 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 } else {
577 if (has_current_desc) {
578 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
579 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
580 } else {
581 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
582 ti_data->description.ice_ufrag.size());
583 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
584 ti_data->description.ice_pwd.size());
585 }
586 }
zhihuang1c378ed2017-08-17 14:10:50 -0700587 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700588 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700589 EXPECT_EQ(
590 media_desc_options_it->transport_options.enable_ice_renomination,
591 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700592
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700594 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 }
596 }
597
598 void TestCryptoWithBundle(bool offer) {
599 f1_.set_secure(SEC_ENABLED);
600 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800601 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
602 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
603 &options);
kwiberg31022942016-03-11 14:18:21 -0800604 std::unique_ptr<SessionDescription> ref_desc;
605 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 if (offer) {
607 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800608 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800610 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000611 } else {
612 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800613 ref_desc = f1_.CreateOffer(options, NULL);
614 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800616 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800618 desc->GetContentDescriptionByName("audio");
619 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800621 desc->GetContentDescriptionByName("video");
622 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
624 video_media_desc->cryptos()));
625 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800626 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 audio_media_desc->cryptos()[0].cipher_suite);
628
629 // Verify the selected crypto is one from the reference audio
630 // media content.
631 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800632 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000633 bool found = false;
634 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
635 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200636 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000637 found = true;
638 break;
639 }
640 }
641 EXPECT_TRUE(found);
642 }
643
644 // This test that the audio and video media direction is set to
645 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700646 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800648 RtpTransceiverDirection direction_in_offer,
649 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700650 MediaSessionOptions offer_opts;
651 AddAudioVideoSections(direction_in_offer, &offer_opts);
652
Steve Anton6fe1fba2018-12-11 10:15:23 -0800653 std::unique_ptr<SessionDescription> offer =
654 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700656 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700658 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660
zhihuang1c378ed2017-08-17 14:10:50 -0700661 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800662 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800663 std::unique_ptr<SessionDescription> answer =
664 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 const AudioContentDescription* acd_answer =
666 GetFirstAudioContentDescription(answer.get());
667 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
668 const VideoContentDescription* vcd_answer =
669 GetFirstVideoContentDescription(answer.get());
670 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
671 }
672
673 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800674 RTC_DCHECK(content);
675 RTC_CHECK(content->media_description());
676 const cricket::AudioContentDescription* audio_desc =
677 content->media_description()->as_audio();
678 RTC_CHECK(audio_desc);
679 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
680 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000681 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800682 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683 }
684 return true;
685 }
686
jbauchcb560652016-08-04 05:20:32 -0700687 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
688 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800689 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700690 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700691
jbauchcb560652016-08-04 05:20:32 -0700692 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800693 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700694 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700695
jbauchcb560652016-08-04 05:20:32 -0700696 f1_.set_secure(SEC_ENABLED);
697 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800698 std::unique_ptr<SessionDescription> offer =
699 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700700 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800701 std::unique_ptr<SessionDescription> answer =
702 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700703 const ContentInfo* ac = answer->GetContentByName("audio");
704 const ContentInfo* vc = answer->GetContentByName("video");
705 ASSERT_TRUE(ac != NULL);
706 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800707 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
708 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800709 const AudioContentDescription* acd = ac->media_description()->as_audio();
710 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700711 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800712 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700713 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700714 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700715 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
716 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700717 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700718 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700719 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700720 }
721 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800722 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200723 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
724 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700725 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700726 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700727 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700728 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700729 }
Steve Antone38a5a12018-11-21 16:05:15 -0800730 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700731 }
732
Johannes Kronce8e8672019-02-22 13:06:44 +0100733 void TestTransportSequenceNumberNegotiation(
734 const cricket::RtpHeaderExtensions& local,
735 const cricket::RtpHeaderExtensions& offered,
736 const cricket::RtpHeaderExtensions& expectedAnswer) {
737 MediaSessionOptions opts;
738 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
739 f1_.set_audio_rtp_header_extensions(offered);
740 f1_.set_video_rtp_header_extensions(offered);
741 f2_.set_audio_rtp_header_extensions(local);
742 f2_.set_video_rtp_header_extensions(local);
743
744 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
745 ASSERT_TRUE(offer.get() != NULL);
746 std::unique_ptr<SessionDescription> answer =
747 f2_.CreateAnswer(offer.get(), opts, NULL);
748
749 EXPECT_EQ(
750 expectedAnswer,
751 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
752 EXPECT_EQ(
753 expectedAnswer,
754 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
755 }
756
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800758 UniqueRandomIdGenerator ssrc_generator1;
759 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 MediaSessionDescriptionFactory f1_;
761 MediaSessionDescriptionFactory f2_;
762 TransportDescriptionFactory tdf1_;
763 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764};
765
766// Create a typical audio offer, and ensure it matches what we expect.
767TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
768 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800769 std::unique_ptr<SessionDescription> offer =
770 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771 ASSERT_TRUE(offer.get() != NULL);
772 const ContentInfo* ac = offer->GetContentByName("audio");
773 const ContentInfo* vc = offer->GetContentByName("video");
774 ASSERT_TRUE(ac != NULL);
775 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800776 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800777 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700779 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700780 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
782 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700783 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800784 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785}
786
787// Create a typical video offer, and ensure it matches what we expect.
788TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
789 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800790 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800792 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 ASSERT_TRUE(offer.get() != NULL);
794 const ContentInfo* ac = offer->GetContentByName("audio");
795 const ContentInfo* vc = offer->GetContentByName("video");
796 ASSERT_TRUE(ac != NULL);
797 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800798 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
799 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800800 const AudioContentDescription* acd = ac->media_description()->as_audio();
801 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700803 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700804 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
806 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700807 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800808 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200810 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700811 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
813 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700814 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800815 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816}
817
818// Test creating an offer with bundle where the Codecs have the same dynamic
819// RTP playlod type. The test verifies that the offer don't contain the
820// duplicate RTP payload types.
821TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200822 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700823 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200824 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
826 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
827
828 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800829 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
830 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800832 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 const VideoContentDescription* vcd =
834 GetFirstVideoContentDescription(offer.get());
835 const AudioContentDescription* acd =
836 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200837 const RtpDataContentDescription* dcd =
838 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000839 ASSERT_TRUE(NULL != vcd);
840 ASSERT_TRUE(NULL != acd);
841 ASSERT_TRUE(NULL != dcd);
842 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
843 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
844 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
845 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
846 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
847 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
848}
849
zhihuang1c378ed2017-08-17 14:10:50 -0700850// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851// after an audio only session has been negotiated.
852TEST_F(MediaSessionDescriptionFactoryTest,
853 TestCreateUpdatedVideoOfferWithBundle) {
854 f1_.set_secure(SEC_ENABLED);
855 f2_.set_secure(SEC_ENABLED);
856 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800857 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
858 RtpTransceiverDirection::kRecvOnly, kActive,
859 &opts);
860 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
861 RtpTransceiverDirection::kInactive, kStopped,
862 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 opts.data_channel_type = cricket::DCT_NONE;
864 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800865 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
866 std::unique_ptr<SessionDescription> answer =
867 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868
869 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800870 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
871 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
872 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800874 std::unique_ptr<SessionDescription> updated_offer(
875 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876
877 const AudioContentDescription* acd =
878 GetFirstAudioContentDescription(updated_offer.get());
879 const VideoContentDescription* vcd =
880 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200881 const RtpDataContentDescription* dcd =
882 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 EXPECT_TRUE(NULL != vcd);
884 EXPECT_TRUE(NULL != acd);
885 EXPECT_TRUE(NULL != dcd);
886
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700887 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800888 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700889 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800890 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700891 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800892 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893}
deadbeef44f08192015-12-15 16:20:09 -0800894
wu@webrtc.org78187522013-10-07 23:32:02 +0000895// Create a RTP data offer, and ensure it matches what we expect.
896TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800898 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
899 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800901 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 ASSERT_TRUE(offer.get() != NULL);
903 const ContentInfo* ac = offer->GetContentByName("audio");
904 const ContentInfo* dc = offer->GetContentByName("data");
905 ASSERT_TRUE(ac != NULL);
906 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800907 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
908 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800909 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200910 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700912 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700913 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
915 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700916 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800917 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200919 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700920 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000921 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200922 dcd->bandwidth()); // default bandwidth (auto)
923 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700924 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800925 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000926}
927
wu@webrtc.org78187522013-10-07 23:32:02 +0000928// Create an SCTP data offer with bundle without error.
929TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
930 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000931 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800932 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000933 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800934 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000935 EXPECT_TRUE(offer.get() != NULL);
936 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000937 auto dcd = GetFirstSctpDataContentDescription(offer.get());
938 ASSERT_TRUE(dcd);
939 // Since this transport is insecure, the protocol should be "SCTP".
940 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
941}
942
943// Create an SCTP data offer with bundle without error.
944TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
945 MediaSessionOptions opts;
946 opts.bundle_enabled = true;
947 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
948 f1_.set_secure(SEC_ENABLED);
949 tdf1_.set_secure(SEC_ENABLED);
950 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
951 EXPECT_TRUE(offer.get() != NULL);
952 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
953 auto dcd = GetFirstSctpDataContentDescription(offer.get());
954 ASSERT_TRUE(dcd);
955 // The protocol should now be "UDP/DTLS/SCTP"
956 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000957}
958
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000959// Test creating an sctp data channel from an already generated offer.
960TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
961 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000962 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800963 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000964 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800965 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000966 ASSERT_TRUE(offer1.get() != NULL);
967 const ContentInfo* data = offer1->GetContentByName("data");
968 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800969 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000970
971 // Now set data_channel_type to 'none' (default) and make sure that the
972 // datachannel type that gets generated from the previous offer, is of the
973 // same type.
974 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800975 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000976 f1_.CreateOffer(opts, offer1.get()));
977 data = offer2->GetContentByName("data");
978 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800979 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000980}
981
Steve Anton2bed3972019-01-04 17:04:30 -0800982// Test that if BUNDLE is enabled and all media sections are rejected then the
983// BUNDLE group is not present in the re-offer.
984TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
985 MediaSessionOptions opts;
986 opts.bundle_enabled = true;
987 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
988 RtpTransceiverDirection::kSendRecv, kActive,
989 &opts);
990 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
991
992 opts.media_description_options[0].stopped = true;
993 std::unique_ptr<SessionDescription> reoffer =
994 f1_.CreateOffer(opts, offer.get());
995
996 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
997}
998
999// Test that if BUNDLE is enabled and the remote re-offer does not include a
1000// BUNDLE group since all media sections are rejected, then the re-answer also
1001// does not include a BUNDLE group.
1002TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
1003 MediaSessionOptions opts;
1004 opts.bundle_enabled = true;
1005 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1006 RtpTransceiverDirection::kSendRecv, kActive,
1007 &opts);
1008 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1009 std::unique_ptr<SessionDescription> answer =
1010 f2_.CreateAnswer(offer.get(), opts, nullptr);
1011
1012 opts.media_description_options[0].stopped = true;
1013 std::unique_ptr<SessionDescription> reoffer =
1014 f1_.CreateOffer(opts, offer.get());
1015 std::unique_ptr<SessionDescription> reanswer =
1016 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1017
1018 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1019}
1020
1021// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1022// was rejected then the new offerer-tagged media section is the non-rejected
1023// media section.
1024TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1025 MediaSessionOptions opts;
1026 opts.bundle_enabled = true;
1027 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1028 RtpTransceiverDirection::kSendRecv, kActive,
1029 &opts);
1030 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1031
1032 // Reject the audio m= section and add a video m= section.
1033 opts.media_description_options[0].stopped = true;
1034 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1035 RtpTransceiverDirection::kSendRecv, kActive,
1036 &opts);
1037 std::unique_ptr<SessionDescription> reoffer =
1038 f1_.CreateOffer(opts, offer.get());
1039
1040 const cricket::ContentGroup* bundle_group =
1041 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1042 ASSERT_TRUE(bundle_group);
1043 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1044 EXPECT_TRUE(bundle_group->HasContentName("video"));
1045}
1046
1047// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1048// was rejected and a new media section is added, then the re-answer BUNDLE
1049// group will contain only the non-rejected media section.
1050TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1051 MediaSessionOptions opts;
1052 opts.bundle_enabled = true;
1053 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1054 RtpTransceiverDirection::kSendRecv, kActive,
1055 &opts);
1056 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1057 std::unique_ptr<SessionDescription> answer =
1058 f2_.CreateAnswer(offer.get(), opts, nullptr);
1059
1060 // Reject the audio m= section and add a video m= section.
1061 opts.media_description_options[0].stopped = true;
1062 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1063 RtpTransceiverDirection::kSendRecv, kActive,
1064 &opts);
1065 std::unique_ptr<SessionDescription> reoffer =
1066 f1_.CreateOffer(opts, offer.get());
1067 std::unique_ptr<SessionDescription> reanswer =
1068 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1069
1070 const cricket::ContentGroup* bundle_group =
1071 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1072 ASSERT_TRUE(bundle_group);
1073 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1074 EXPECT_TRUE(bundle_group->HasContentName("video"));
1075}
1076
1077// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1078// and there is still a non-rejected media section that was in the initial
1079// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1080// media section.
1081TEST_F(MediaSessionDescriptionFactoryTest,
1082 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1083 MediaSessionOptions opts;
1084 opts.bundle_enabled = true;
1085 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1086 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1087 std::unique_ptr<SessionDescription> answer =
1088 f2_.CreateAnswer(offer.get(), opts, nullptr);
1089
1090 // Reject the audio m= section.
1091 opts.media_description_options[0].stopped = true;
1092 std::unique_ptr<SessionDescription> reoffer =
1093 f1_.CreateOffer(opts, offer.get());
1094
1095 const TransportDescription* offer_tagged =
1096 offer->GetTransportDescriptionByName("audio");
1097 ASSERT_TRUE(offer_tagged);
1098 const TransportDescription* reoffer_tagged =
1099 reoffer->GetTransportDescriptionByName("video");
1100 ASSERT_TRUE(reoffer_tagged);
1101 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1102 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1103}
1104
1105// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1106// and there is still a non-rejected media section that was in the initial
1107// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1108// media section.
1109TEST_F(MediaSessionDescriptionFactoryTest,
1110 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1111 MediaSessionOptions opts;
1112 opts.bundle_enabled = true;
1113 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1114 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1115 std::unique_ptr<SessionDescription> answer =
1116 f2_.CreateAnswer(offer.get(), opts, nullptr);
1117
1118 // Reject the audio m= section.
1119 opts.media_description_options[0].stopped = true;
1120 std::unique_ptr<SessionDescription> reoffer =
1121 f1_.CreateOffer(opts, offer.get());
1122 std::unique_ptr<SessionDescription> reanswer =
1123 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1124
1125 const TransportDescription* answer_tagged =
1126 answer->GetTransportDescriptionByName("audio");
1127 ASSERT_TRUE(answer_tagged);
1128 const TransportDescription* reanswer_tagged =
1129 reanswer->GetTransportDescriptionByName("video");
1130 ASSERT_TRUE(reanswer_tagged);
1131 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1132 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1133}
1134
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001135// Create an audio, video offer without legacy StreamParams.
1136TEST_F(MediaSessionDescriptionFactoryTest,
1137 TestCreateOfferWithoutLegacyStreams) {
1138 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001139 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001140 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001141 ASSERT_TRUE(offer.get() != NULL);
1142 const ContentInfo* ac = offer->GetContentByName("audio");
1143 const ContentInfo* vc = offer->GetContentByName("video");
1144 ASSERT_TRUE(ac != NULL);
1145 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001146 const AudioContentDescription* acd = ac->media_description()->as_audio();
1147 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148
Yves Gerey665174f2018-06-19 15:03:05 +02001149 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1150 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001151}
1152
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001153// Creates an audio+video sendonly offer.
1154TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001155 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001156 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001157 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1158 {kMediaStream1}, 1, &opts);
1159 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1160 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001161
Steve Anton6fe1fba2018-12-11 10:15:23 -08001162 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001163 ASSERT_TRUE(offer.get() != NULL);
1164 EXPECT_EQ(2u, offer->contents().size());
1165 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1166 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1167
Steve Anton4e70a722017-11-28 14:57:10 -08001168 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1169 GetMediaDirection(&offer->contents()[0]));
1170 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1171 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001172}
1173
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001174// Verifies that the order of the media contents in the current
1175// SessionDescription is preserved in the new SessionDescription.
1176TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1177 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001178 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001179
kwiberg31022942016-03-11 14:18:21 -08001180 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001181 ASSERT_TRUE(offer1.get() != NULL);
1182 EXPECT_EQ(1u, offer1->contents().size());
1183 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1184
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001185 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1186 RtpTransceiverDirection::kRecvOnly, kActive,
1187 &opts);
kwiberg31022942016-03-11 14:18:21 -08001188 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001189 f1_.CreateOffer(opts, offer1.get()));
1190 ASSERT_TRUE(offer2.get() != NULL);
1191 EXPECT_EQ(2u, offer2->contents().size());
1192 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1193 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1194
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001195 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1196 RtpTransceiverDirection::kRecvOnly, kActive,
1197 &opts);
kwiberg31022942016-03-11 14:18:21 -08001198 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001199 f1_.CreateOffer(opts, offer2.get()));
1200 ASSERT_TRUE(offer3.get() != NULL);
1201 EXPECT_EQ(3u, offer3->contents().size());
1202 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1203 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1204 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001205}
1206
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001207// Create a typical audio answer, and ensure it matches what we expect.
1208TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1209 f1_.set_secure(SEC_ENABLED);
1210 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001211 std::unique_ptr<SessionDescription> offer =
1212 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001213 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001214 std::unique_ptr<SessionDescription> answer =
1215 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001216 const ContentInfo* ac = answer->GetContentByName("audio");
1217 const ContentInfo* vc = answer->GetContentByName("video");
1218 ASSERT_TRUE(ac != NULL);
1219 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001220 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001221 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001223 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001224 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1226 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001227 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001228 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229}
1230
jbauchcb560652016-08-04 05:20:32 -07001231// Create a typical audio answer with GCM ciphers enabled, and ensure it
1232// matches what we expect.
1233TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1234 f1_.set_secure(SEC_ENABLED);
1235 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001236 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001237 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001238 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001239 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001240 std::unique_ptr<SessionDescription> answer =
1241 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001242 const ContentInfo* ac = answer->GetContentByName("audio");
1243 const ContentInfo* vc = answer->GetContentByName("video");
1244 ASSERT_TRUE(ac != NULL);
1245 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001246 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001247 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001248 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001249 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001250 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001251 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1252 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001253 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001254 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001255}
1256
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257// Create a typical video answer, and ensure it matches what we expect.
1258TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1259 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001260 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 f1_.set_secure(SEC_ENABLED);
1262 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001263 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001265 std::unique_ptr<SessionDescription> answer =
1266 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267 const ContentInfo* ac = answer->GetContentByName("audio");
1268 const ContentInfo* vc = answer->GetContentByName("video");
1269 ASSERT_TRUE(ac != NULL);
1270 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001271 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1272 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001273 const AudioContentDescription* acd = ac->media_description()->as_audio();
1274 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001276 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001277 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001278 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001279 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001280 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001281 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001282 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001283 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1284 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001285 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001286 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287}
1288
jbauchcb560652016-08-04 05:20:32 -07001289// Create a typical video answer with GCM ciphers enabled, and ensure it
1290// matches what we expect.
1291TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1292 TestVideoGcmCipher(true, true);
1293}
1294
1295// Create a typical video answer with GCM ciphers enabled for the offer only,
1296// and ensure it matches what we expect.
1297TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1298 TestVideoGcmCipher(true, false);
1299}
1300
1301// Create a typical video answer with GCM ciphers enabled for the answer only,
1302// and ensure it matches what we expect.
1303TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1304 TestVideoGcmCipher(false, true);
1305}
1306
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001308 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001309 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 f1_.set_secure(SEC_ENABLED);
1311 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001312 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001313 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001314 std::unique_ptr<SessionDescription> answer =
1315 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001317 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001319 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001320 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1321 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001322 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001323 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001324 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001325 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001326 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001327 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001329 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001330 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001331 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001332 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001333 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001334 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001335 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001336}
1337
jbauchcb560652016-08-04 05:20:32 -07001338TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001339 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001340 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001341 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001342 f1_.set_secure(SEC_ENABLED);
1343 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001344 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001345 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001346 std::unique_ptr<SessionDescription> answer =
1347 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001348 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001349 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001350 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001351 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001352 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1353 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001354 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001355 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001356 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001357 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001358 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001359 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001360 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001361 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001362 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001363 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001364 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001365 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001366 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001367 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001368}
1369
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001370// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1371// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001372TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1373 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001374 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001375 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001376 ASSERT_TRUE(offer.get() != NULL);
1377 ContentInfo* dc_offer = offer->GetContentByName("data");
1378 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001379 SctpDataContentDescription* dcd_offer =
1380 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001381 EXPECT_TRUE(dcd_offer->use_sctpmap());
1382
Steve Anton6fe1fba2018-12-11 10:15:23 -08001383 std::unique_ptr<SessionDescription> answer =
1384 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001385 const ContentInfo* dc_answer = answer->GetContentByName("data");
1386 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001387 const SctpDataContentDescription* dcd_answer =
1388 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001389 EXPECT_TRUE(dcd_answer->use_sctpmap());
1390}
1391
1392// The answer's use_sctpmap flag should match the offer's.
1393TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1394 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001395 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001396 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001397 ASSERT_TRUE(offer.get() != NULL);
1398 ContentInfo* dc_offer = offer->GetContentByName("data");
1399 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001400 SctpDataContentDescription* dcd_offer =
1401 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001402 dcd_offer->set_use_sctpmap(false);
1403
Steve Anton6fe1fba2018-12-11 10:15:23 -08001404 std::unique_ptr<SessionDescription> answer =
1405 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001406 const ContentInfo* dc_answer = answer->GetContentByName("data");
1407 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001408 const SctpDataContentDescription* dcd_answer =
1409 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001410 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001411}
1412
deadbeef8b7e9ad2017-05-25 09:38:55 -07001413// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1414// and "TCP/DTLS/SCTP" offers.
1415TEST_F(MediaSessionDescriptionFactoryTest,
1416 TestCreateDataAnswerToDifferentOfferedProtos) {
1417 // Need to enable DTLS offer/answer generation (disabled by default in this
1418 // test).
1419 f1_.set_secure(SEC_ENABLED);
1420 f2_.set_secure(SEC_ENABLED);
1421 tdf1_.set_secure(SEC_ENABLED);
1422 tdf2_.set_secure(SEC_ENABLED);
1423
1424 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001425 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001426 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001427 ASSERT_TRUE(offer.get() != nullptr);
1428 ContentInfo* dc_offer = offer->GetContentByName("data");
1429 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001430 SctpDataContentDescription* dcd_offer =
1431 dc_offer->media_description()->as_sctp();
1432 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001433
1434 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1435 "TCP/DTLS/SCTP"};
1436 for (const std::string& proto : protos) {
1437 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001438 std::unique_ptr<SessionDescription> answer =
1439 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001440 const ContentInfo* dc_answer = answer->GetContentByName("data");
1441 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001442 const SctpDataContentDescription* dcd_answer =
1443 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001444 EXPECT_FALSE(dc_answer->rejected);
1445 EXPECT_EQ(proto, dcd_answer->protocol());
1446 }
1447}
1448
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001449TEST_F(MediaSessionDescriptionFactoryTest,
1450 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1451 // Need to enable DTLS offer/answer generation (disabled by default in this
1452 // test).
1453 f1_.set_secure(SEC_ENABLED);
1454 f2_.set_secure(SEC_ENABLED);
1455 tdf1_.set_secure(SEC_ENABLED);
1456 tdf2_.set_secure(SEC_ENABLED);
1457
1458 MediaSessionOptions opts;
1459 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1460 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1461 ASSERT_TRUE(offer.get() != nullptr);
1462 ContentInfo* dc_offer = offer->GetContentByName("data");
1463 ASSERT_TRUE(dc_offer != nullptr);
1464 SctpDataContentDescription* dcd_offer =
1465 dc_offer->media_description()->as_sctp();
1466 ASSERT_TRUE(dcd_offer);
1467 dcd_offer->set_max_message_size(1234);
1468 std::unique_ptr<SessionDescription> answer =
1469 f2_.CreateAnswer(offer.get(), opts, nullptr);
1470 const ContentInfo* dc_answer = answer->GetContentByName("data");
1471 ASSERT_TRUE(dc_answer != nullptr);
1472 const SctpDataContentDescription* dcd_answer =
1473 dc_answer->media_description()->as_sctp();
1474 EXPECT_FALSE(dc_answer->rejected);
1475 EXPECT_EQ(1234, dcd_answer->max_message_size());
1476}
1477
1478TEST_F(MediaSessionDescriptionFactoryTest,
1479 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1480 // Need to enable DTLS offer/answer generation (disabled by default in this
1481 // test).
1482 f1_.set_secure(SEC_ENABLED);
1483 f2_.set_secure(SEC_ENABLED);
1484 tdf1_.set_secure(SEC_ENABLED);
1485 tdf2_.set_secure(SEC_ENABLED);
1486
1487 MediaSessionOptions opts;
1488 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1489 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1490 ASSERT_TRUE(offer.get() != nullptr);
1491 ContentInfo* dc_offer = offer->GetContentByName("data");
1492 ASSERT_TRUE(dc_offer != nullptr);
1493 SctpDataContentDescription* dcd_offer =
1494 dc_offer->media_description()->as_sctp();
1495 ASSERT_TRUE(dcd_offer);
1496 dcd_offer->set_max_message_size(0);
1497 std::unique_ptr<SessionDescription> answer =
1498 f2_.CreateAnswer(offer.get(), opts, nullptr);
1499 const ContentInfo* dc_answer = answer->GetContentByName("data");
1500 ASSERT_TRUE(dc_answer != nullptr);
1501 const SctpDataContentDescription* dcd_answer =
1502 dc_answer->media_description()->as_sctp();
1503 EXPECT_FALSE(dc_answer->rejected);
1504 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1505}
1506
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001507// Verifies that the order of the media contents in the offer is preserved in
1508// the answer.
1509TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1510 MediaSessionOptions opts;
1511
1512 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001513 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001514 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001515 ASSERT_TRUE(offer1.get() != NULL);
1516
1517 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001518 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1519 RtpTransceiverDirection::kRecvOnly, kActive,
1520 &opts);
kwiberg31022942016-03-11 14:18:21 -08001521 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001522 f1_.CreateOffer(opts, offer1.get()));
1523 ASSERT_TRUE(offer2.get() != NULL);
1524
1525 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001526 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1527 RtpTransceiverDirection::kRecvOnly, kActive,
1528 &opts);
kwiberg31022942016-03-11 14:18:21 -08001529 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001530 f1_.CreateOffer(opts, offer2.get()));
1531 ASSERT_TRUE(offer3.get() != NULL);
1532
Steve Anton6fe1fba2018-12-11 10:15:23 -08001533 std::unique_ptr<SessionDescription> answer =
1534 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001535 ASSERT_TRUE(answer.get() != NULL);
1536 EXPECT_EQ(3u, answer->contents().size());
1537 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1538 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1539 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1540}
1541
ossu075af922016-06-14 03:29:38 -07001542// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1543// answerer settings.
1544
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001545// This test that the media direction is set to send/receive in an answer if
1546// the offer is send receive.
1547TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001548 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1549 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001550}
1551
1552// This test that the media direction is set to receive only in an answer if
1553// the offer is send only.
1554TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001555 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1556 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001557}
1558
1559// This test that the media direction is set to send only in an answer if
1560// the offer is recv only.
1561TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001562 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1563 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001564}
1565
1566// This test that the media direction is set to inactive in an answer if
1567// the offer is inactive.
1568TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001569 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1570 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001571}
1572
1573// Test that a data content with an unknown protocol is rejected in an answer.
1574TEST_F(MediaSessionDescriptionFactoryTest,
1575 CreateDataAnswerToOfferWithUnknownProtocol) {
1576 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001577 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578 f1_.set_secure(SEC_ENABLED);
1579 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001580 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001581 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001583 RtpDataContentDescription* dcd_offer =
1584 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001585 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001586 // Offer must be acceptable as an RTP protocol in order to be set.
1587 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001588 dcd_offer->set_protocol(protocol);
1589
Steve Anton6fe1fba2018-12-11 10:15:23 -08001590 std::unique_ptr<SessionDescription> answer =
1591 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001592
1593 const ContentInfo* dc_answer = answer->GetContentByName("data");
1594 ASSERT_TRUE(dc_answer != NULL);
1595 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001596 const RtpDataContentDescription* dcd_answer =
1597 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001598 ASSERT_TRUE(dcd_answer != NULL);
1599 EXPECT_EQ(protocol, dcd_answer->protocol());
1600}
1601
1602// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1603TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001604 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605 f1_.set_secure(SEC_DISABLED);
1606 f2_.set_secure(SEC_DISABLED);
1607 tdf1_.set_secure(SEC_DISABLED);
1608 tdf2_.set_secure(SEC_DISABLED);
1609
Steve Anton6fe1fba2018-12-11 10:15:23 -08001610 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611 const AudioContentDescription* offer_acd =
1612 GetFirstAudioContentDescription(offer.get());
1613 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001614 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001615
Steve Anton6fe1fba2018-12-11 10:15:23 -08001616 std::unique_ptr<SessionDescription> answer =
1617 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001618
1619 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1620 ASSERT_TRUE(ac_answer != NULL);
1621 EXPECT_FALSE(ac_answer->rejected);
1622
1623 const AudioContentDescription* answer_acd =
1624 GetFirstAudioContentDescription(answer.get());
1625 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001626 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001627}
1628
1629// Create a video offer and answer and ensure the RTP header extensions
1630// matches what we expect.
1631TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1632 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001633 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1635 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1636 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1637 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1638
Steve Anton6fe1fba2018-12-11 10:15:23 -08001639 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001641 std::unique_ptr<SessionDescription> answer =
1642 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001643
Yves Gerey665174f2018-06-19 15:03:05 +02001644 EXPECT_EQ(
1645 MAKE_VECTOR(kAudioRtpExtension1),
1646 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1647 EXPECT_EQ(
1648 MAKE_VECTOR(kVideoRtpExtension1),
1649 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1650 EXPECT_EQ(
1651 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1652 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1653 EXPECT_EQ(
1654 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1655 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001656}
1657
Johannes Kronce8e8672019-02-22 13:06:44 +01001658// Create a audio/video offer and answer and ensure that the
1659// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1660// supported and should take precedence even though not listed among locally
1661// supported extensions.
1662TEST_F(MediaSessionDescriptionFactoryTest,
1663 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1664 TestTransportSequenceNumberNegotiation(
1665 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1666 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1667 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1668}
1669TEST_F(MediaSessionDescriptionFactoryTest,
1670 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1671 TestTransportSequenceNumberNegotiation(
1672 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1673 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1674 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1675}
1676TEST_F(MediaSessionDescriptionFactoryTest,
1677 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1678 TestTransportSequenceNumberNegotiation(
1679 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1680 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1681 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1682}
1683
jbauch5869f502017-06-29 12:31:36 -07001684TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001685 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1686 MediaSessionOptions opts;
1687 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1688
1689 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1690 f1_.set_audio_rtp_header_extensions(offered);
1691 f1_.set_video_rtp_header_extensions(offered);
1692 const auto local = MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01);
1693 f2_.set_audio_rtp_header_extensions(local);
1694 f2_.set_video_rtp_header_extensions(local);
1695 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1696 std::unique_ptr<SessionDescription> answer =
1697 f2_.CreateAnswer(offer.get(), opts, nullptr);
1698 EXPECT_THAT(
1699 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1700 ElementsAreArray(offered));
1701 EXPECT_THAT(
1702 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1703 ElementsAreArray(offered));
1704}
1705
1706TEST_F(MediaSessionDescriptionFactoryTest,
1707 TestNegotiateFrameDescriptorWhenExposedLocally) {
1708 MediaSessionOptions opts;
1709 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1710
1711 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1712 f1_.set_audio_rtp_header_extensions(offered);
1713 f1_.set_video_rtp_header_extensions(offered);
1714 const auto local = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1715 f2_.set_audio_rtp_header_extensions(local);
1716 f2_.set_video_rtp_header_extensions(local);
1717 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1718 std::unique_ptr<SessionDescription> answer =
1719 f2_.CreateAnswer(offer.get(), opts, nullptr);
1720 EXPECT_THAT(
1721 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1722 ElementsAreArray(offered));
1723 EXPECT_THAT(
1724 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1725 ElementsAreArray(offered));
1726}
1727
1728TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001729 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1730 MediaSessionOptions opts;
1731 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1732
1733 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1734 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1735 f1_.set_video_rtp_header_extensions({offer_dd});
1736 f2_.set_video_rtp_header_extensions({local_tsn});
1737 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1738 std::unique_ptr<SessionDescription> answer =
1739 f2_.CreateAnswer(offer.get(), opts, nullptr);
1740 EXPECT_THAT(
1741 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1742 ElementsAre(offer_dd));
1743}
1744
1745TEST_F(MediaSessionDescriptionFactoryTest,
1746 NegotiateDependencyDescriptorWhenExposedLocally) {
1747 MediaSessionOptions opts;
1748 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1749
1750 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1751 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
1752 f1_.set_video_rtp_header_extensions({offer_dd});
1753 f2_.set_video_rtp_header_extensions({local_dd});
1754 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1755 std::unique_ptr<SessionDescription> answer =
1756 f2_.CreateAnswer(offer.get(), opts, nullptr);
1757 EXPECT_THAT(
1758 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1759 ElementsAre(offer_dd));
1760}
1761
1762TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001763 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1764 MediaSessionOptions opts;
1765 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1766
1767 const cricket::RtpHeaderExtensions offered_extensions = {
1768 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1769 const cricket::RtpHeaderExtensions local_extensions = {
1770 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
1771 f1_.set_video_rtp_header_extensions(offered_extensions);
1772 f1_.set_audio_rtp_header_extensions(offered_extensions);
1773 f2_.set_video_rtp_header_extensions(local_extensions);
1774 f2_.set_audio_rtp_header_extensions(local_extensions);
1775
1776 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1777 std::unique_ptr<SessionDescription> answer =
1778 f2_.CreateAnswer(offer.get(), opts, nullptr);
1779 EXPECT_THAT(
1780 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1781 ElementsAreArray(offered_extensions));
1782 EXPECT_THAT(
1783 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1784 ElementsAreArray(offered_extensions));
1785}
1786
1787TEST_F(MediaSessionDescriptionFactoryTest,
1788 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1789 MediaSessionOptions opts;
1790 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1791
1792 const cricket::RtpHeaderExtensions offered_extensions = {
1793 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1794 const cricket::RtpHeaderExtensions local_extensions = {
1795 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
1796 f1_.set_video_rtp_header_extensions(offered_extensions);
1797 f1_.set_audio_rtp_header_extensions(offered_extensions);
1798 f2_.set_video_rtp_header_extensions(local_extensions);
1799 f2_.set_audio_rtp_header_extensions(local_extensions);
1800
1801 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1802 std::unique_ptr<SessionDescription> answer =
1803 f2_.CreateAnswer(offer.get(), opts, nullptr);
1804 EXPECT_THAT(
1805 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1806 ElementsAreArray(offered_extensions));
1807 EXPECT_THAT(
1808 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1809 ElementsAreArray(offered_extensions));
1810}
1811
1812TEST_F(MediaSessionDescriptionFactoryTest,
1813 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1814 MediaSessionOptions opts;
1815 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1816
1817 const cricket::RtpHeaderExtensions offered_extensions = {
1818 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1819 const cricket::RtpHeaderExtensions local_extensions = {
1820 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
1821 f1_.set_video_rtp_header_extensions(offered_extensions);
1822 f1_.set_audio_rtp_header_extensions(offered_extensions);
1823 f2_.set_video_rtp_header_extensions(local_extensions);
1824 f2_.set_audio_rtp_header_extensions(local_extensions);
1825
1826 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1827 std::unique_ptr<SessionDescription> answer =
1828 f2_.CreateAnswer(offer.get(), opts, nullptr);
1829 EXPECT_THAT(
1830 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1831 IsEmpty());
1832 EXPECT_THAT(
1833 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1834 IsEmpty());
1835}
1836
1837TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001838 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001839 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001840 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001841
1842 f1_.set_enable_encrypted_rtp_header_extensions(true);
1843 f2_.set_enable_encrypted_rtp_header_extensions(true);
1844
Yves Gerey665174f2018-06-19 15:03:05 +02001845 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1846 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1847 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1848 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001849
Steve Anton6fe1fba2018-12-11 10:15:23 -08001850 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001851 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001852 std::unique_ptr<SessionDescription> answer =
1853 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001854
Yves Gerey665174f2018-06-19 15:03:05 +02001855 EXPECT_EQ(
1856 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1857 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1858 EXPECT_EQ(
1859 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1860 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1861 EXPECT_EQ(
1862 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1863 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1864 EXPECT_EQ(
1865 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1866 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001867}
1868
1869TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001870 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001871 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001872 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001873
1874 f1_.set_enable_encrypted_rtp_header_extensions(true);
1875
Yves Gerey665174f2018-06-19 15:03:05 +02001876 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1877 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1878 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1879 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001880
Steve Anton6fe1fba2018-12-11 10:15:23 -08001881 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001882 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001883 std::unique_ptr<SessionDescription> answer =
1884 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001885
Yves Gerey665174f2018-06-19 15:03:05 +02001886 EXPECT_EQ(
1887 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1888 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1889 EXPECT_EQ(
1890 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1891 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1892 EXPECT_EQ(
1893 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1894 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1895 EXPECT_EQ(
1896 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1897 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001898}
1899
1900TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001901 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001902 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001903 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001904
1905 f2_.set_enable_encrypted_rtp_header_extensions(true);
1906
Yves Gerey665174f2018-06-19 15:03:05 +02001907 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1908 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1909 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1910 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001911
Steve Anton6fe1fba2018-12-11 10:15:23 -08001912 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001913 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001914 std::unique_ptr<SessionDescription> answer =
1915 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001916
Yves Gerey665174f2018-06-19 15:03:05 +02001917 EXPECT_EQ(
1918 MAKE_VECTOR(kAudioRtpExtension1),
1919 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1920 EXPECT_EQ(
1921 MAKE_VECTOR(kVideoRtpExtension1),
1922 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1923 EXPECT_EQ(
1924 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1925 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1926 EXPECT_EQ(
1927 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1928 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001929}
1930
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001931// Create an audio, video, data answer without legacy StreamParams.
1932TEST_F(MediaSessionDescriptionFactoryTest,
1933 TestCreateAnswerWithoutLegacyStreams) {
1934 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001935 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1936 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001937 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001938 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001939 std::unique_ptr<SessionDescription> answer =
1940 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941 const ContentInfo* ac = answer->GetContentByName("audio");
1942 const ContentInfo* vc = answer->GetContentByName("video");
1943 const ContentInfo* dc = answer->GetContentByName("data");
1944 ASSERT_TRUE(ac != NULL);
1945 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001946 const AudioContentDescription* acd = ac->media_description()->as_audio();
1947 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001948 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001949
1950 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1951 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1952 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1953}
1954
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001955// Create a typical video answer, and ensure it matches what we expect.
1956TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1957 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001958 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1959 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1960 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001961
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001962 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001963 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1964 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1965 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001966
kwiberg31022942016-03-11 14:18:21 -08001967 std::unique_ptr<SessionDescription> offer;
1968 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001969
1970 offer_opts.rtcp_mux_enabled = true;
1971 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001972 offer = f1_.CreateOffer(offer_opts, NULL);
1973 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001974 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1975 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001976 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1978 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001979 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001980 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1981 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001982 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1984 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001985 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001986
1987 offer_opts.rtcp_mux_enabled = true;
1988 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001989 offer = f1_.CreateOffer(offer_opts, NULL);
1990 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001991 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1992 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001993 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1995 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001996 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001997 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1998 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001999 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002000 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2001 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002002 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002003
2004 offer_opts.rtcp_mux_enabled = false;
2005 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002006 offer = f1_.CreateOffer(offer_opts, NULL);
2007 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2009 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002010 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2012 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002013 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2015 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002016 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002017 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2018 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002019 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002020
2021 offer_opts.rtcp_mux_enabled = false;
2022 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002023 offer = f1_.CreateOffer(offer_opts, NULL);
2024 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2026 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002027 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2029 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002030 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002031 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2032 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002033 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2035 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002036 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002037}
2038
2039// Create an audio-only answer to a video offer.
2040TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2041 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002042 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2043 RtpTransceiverDirection::kRecvOnly, kActive,
2044 &opts);
2045 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2046 RtpTransceiverDirection::kRecvOnly, kActive,
2047 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002048 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002049 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002050
2051 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002052 std::unique_ptr<SessionDescription> answer =
2053 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002054 const ContentInfo* ac = answer->GetContentByName("audio");
2055 const ContentInfo* vc = answer->GetContentByName("video");
2056 ASSERT_TRUE(ac != NULL);
2057 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002058 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002059 EXPECT_TRUE(vc->rejected);
2060}
2061
2062// Create an audio-only answer to an offer with data.
2063TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002064 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002066 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2067 RtpTransceiverDirection::kRecvOnly, kActive,
2068 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002069 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002070 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002071
2072 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002073 std::unique_ptr<SessionDescription> answer =
2074 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002075 const ContentInfo* ac = answer->GetContentByName("audio");
2076 const ContentInfo* dc = answer->GetContentByName("data");
2077 ASSERT_TRUE(ac != NULL);
2078 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002079 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002080 EXPECT_TRUE(dc->rejected);
2081}
2082
2083// Create an answer that rejects the contents which are rejected in the offer.
2084TEST_F(MediaSessionDescriptionFactoryTest,
2085 CreateAnswerToOfferWithRejectedMedia) {
2086 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002087 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2088 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002089 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002090 ASSERT_TRUE(offer.get() != NULL);
2091 ContentInfo* ac = offer->GetContentByName("audio");
2092 ContentInfo* vc = offer->GetContentByName("video");
2093 ContentInfo* dc = offer->GetContentByName("data");
2094 ASSERT_TRUE(ac != NULL);
2095 ASSERT_TRUE(vc != NULL);
2096 ASSERT_TRUE(dc != NULL);
2097 ac->rejected = true;
2098 vc->rejected = true;
2099 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002100 std::unique_ptr<SessionDescription> answer =
2101 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002102 ac = answer->GetContentByName("audio");
2103 vc = answer->GetContentByName("video");
2104 dc = answer->GetContentByName("data");
2105 ASSERT_TRUE(ac != NULL);
2106 ASSERT_TRUE(vc != NULL);
2107 ASSERT_TRUE(dc != NULL);
2108 EXPECT_TRUE(ac->rejected);
2109 EXPECT_TRUE(vc->rejected);
2110 EXPECT_TRUE(dc->rejected);
2111}
2112
Johannes Kron0854eb62018-10-10 22:33:20 +02002113TEST_F(MediaSessionDescriptionFactoryTest,
2114 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2115 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002116 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002117 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002118 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002119 ASSERT_TRUE(offer.get() != NULL);
2120 std::unique_ptr<SessionDescription> answer_no_support(
2121 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002122 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002123
2124 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002125 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002126 ASSERT_TRUE(offer.get() != NULL);
2127 std::unique_ptr<SessionDescription> answer_support(
2128 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002129 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002130}
2131
2132TEST_F(MediaSessionDescriptionFactoryTest,
2133 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2134 MediaSessionOptions opts;
2135 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002136 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002137 MediaContentDescription* video_offer =
2138 offer->GetContentDescriptionByName("video");
2139 ASSERT_TRUE(video_offer);
2140 MediaContentDescription* audio_offer =
2141 offer->GetContentDescriptionByName("audio");
2142 ASSERT_TRUE(audio_offer);
2143
2144 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002145 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2146 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002147
2148 ASSERT_TRUE(offer.get() != NULL);
2149 std::unique_ptr<SessionDescription> answer_no_support(
2150 f2_.CreateAnswer(offer.get(), opts, NULL));
2151 MediaContentDescription* video_answer =
2152 answer_no_support->GetContentDescriptionByName("video");
2153 MediaContentDescription* audio_answer =
2154 answer_no_support->GetContentDescriptionByName("audio");
2155 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002156 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002157 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002158 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002159
2160 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002161 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2162 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002163 ASSERT_TRUE(offer.get() != NULL);
2164 std::unique_ptr<SessionDescription> answer_support(
2165 f2_.CreateAnswer(offer.get(), opts, NULL));
2166 video_answer = answer_support->GetContentDescriptionByName("video");
2167 audio_answer = answer_support->GetContentDescriptionByName("audio");
2168 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002169 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002170 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002171 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002172}
2173
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174// Create an audio and video offer with:
2175// - one video track
2176// - two audio tracks
2177// - two data tracks
2178// and ensure it matches what we expect. Also updates the initial offer by
2179// adding a new video track and replaces one of the audio tracks.
2180TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2181 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002182 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002183 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2184 {kMediaStream1}, 1, &opts);
2185 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2186 {kMediaStream1}, 1, &opts);
2187 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2188 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002189
Steve Anton4e70a722017-11-28 14:57:10 -08002190 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002191 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2192 {kMediaStream1}, 1, &opts);
2193 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2194 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002195
2196 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002197 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002198
2199 ASSERT_TRUE(offer.get() != NULL);
2200 const ContentInfo* ac = offer->GetContentByName("audio");
2201 const ContentInfo* vc = offer->GetContentByName("video");
2202 const ContentInfo* dc = offer->GetContentByName("data");
2203 ASSERT_TRUE(ac != NULL);
2204 ASSERT_TRUE(vc != NULL);
2205 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002206 const AudioContentDescription* acd = ac->media_description()->as_audio();
2207 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002208 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002210 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002211
2212 const StreamParamsVec& audio_streams = acd->streams();
2213 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002214 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002215 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2216 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2217 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2218 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2219 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2220 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2221
2222 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2223 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002224 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002225
2226 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002227 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002228 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002229
2230 const StreamParamsVec& video_streams = vcd->streams();
2231 ASSERT_EQ(1U, video_streams.size());
2232 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2233 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2234 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2235 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2236
2237 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002238 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002239 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002240
2241 const StreamParamsVec& data_streams = dcd->streams();
2242 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002243 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2245 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2246 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2247 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2248 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2249 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2250
2251 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002252 dcd->bandwidth()); // default bandwidth (auto)
2253 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002254 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002255
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002256 // Update the offer. Add a new video track that is not synched to the
2257 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002258 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2259 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002260 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002261 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2262 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002263 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002264 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2265 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002266 std::unique_ptr<SessionDescription> updated_offer(
2267 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002268
2269 ASSERT_TRUE(updated_offer.get() != NULL);
2270 ac = updated_offer->GetContentByName("audio");
2271 vc = updated_offer->GetContentByName("video");
2272 dc = updated_offer->GetContentByName("data");
2273 ASSERT_TRUE(ac != NULL);
2274 ASSERT_TRUE(vc != NULL);
2275 ASSERT_TRUE(dc != NULL);
2276 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002277 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002278 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002279 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002280 const RtpDataContentDescription* updated_dcd =
2281 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002282
2283 EXPECT_EQ(acd->type(), updated_acd->type());
2284 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2285 EXPECT_EQ(vcd->type(), updated_vcd->type());
2286 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2287 EXPECT_EQ(dcd->type(), updated_dcd->type());
2288 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002289 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002290 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002291 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002292 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002293 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002294 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2295
2296 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2297 ASSERT_EQ(2U, updated_audio_streams.size());
2298 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2299 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2300 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2301 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2302 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2303
2304 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2305 ASSERT_EQ(2U, updated_video_streams.size());
2306 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2307 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002308 // All the media streams in one PeerConnection share one RTCP CNAME.
2309 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310
2311 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2312 ASSERT_EQ(2U, updated_data_streams.size());
2313 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2314 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2315 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2316 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2317 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002318 // The stream correctly got the CNAME from the MediaSessionOptions.
2319 // The Expected RTCP CNAME is the default one as we are using the default
2320 // MediaSessionOptions.
2321 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002322}
2323
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002324// Create an offer with simulcast video stream.
2325TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2326 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002327 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2328 RtpTransceiverDirection::kRecvOnly, kActive,
2329 &opts);
2330 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2331 RtpTransceiverDirection::kSendRecv, kActive,
2332 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002333 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002334 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2335 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002336 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002337
2338 ASSERT_TRUE(offer.get() != NULL);
2339 const ContentInfo* vc = offer->GetContentByName("video");
2340 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002341 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002342
2343 const StreamParamsVec& video_streams = vcd->streams();
2344 ASSERT_EQ(1U, video_streams.size());
2345 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2346 const SsrcGroup* sim_ssrc_group =
2347 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2348 ASSERT_TRUE(sim_ssrc_group != NULL);
2349 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2350}
2351
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002352MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2353 const RidDescription& rid1 = ::testing::get<0>(arg);
2354 const RidDescription& rid2 = ::testing::get<1>(arg);
2355 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2356}
2357
2358static void CheckSimulcastInSessionDescription(
2359 const SessionDescription* description,
2360 const std::string& content_name,
2361 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002362 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002363 ASSERT_NE(description, nullptr);
2364 const ContentInfo* content = description->GetContentByName(content_name);
2365 ASSERT_NE(content, nullptr);
2366 const MediaContentDescription* cd = content->media_description();
2367 ASSERT_NE(cd, nullptr);
2368 const StreamParamsVec& streams = cd->streams();
2369 ASSERT_THAT(streams, SizeIs(1));
2370 const StreamParams& stream = streams[0];
2371 ASSERT_THAT(stream.ssrcs, IsEmpty());
2372 EXPECT_TRUE(stream.has_rids());
2373 const std::vector<RidDescription> rids = stream.rids();
2374
2375 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2376
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002377 EXPECT_TRUE(cd->HasSimulcast());
2378 const SimulcastDescription& simulcast = cd->simulcast_description();
2379 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2380 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2381
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002382 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002383}
2384
2385// Create an offer with spec-compliant simulcast video stream.
2386TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2387 MediaSessionOptions opts;
2388 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2389 RtpTransceiverDirection::kSendRecv, kActive,
2390 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002391 std::vector<RidDescription> send_rids;
2392 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2393 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2394 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2395 SimulcastLayerList simulcast_layers;
2396 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2397 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2398 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2399 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2400 {kMediaStream1}, send_rids,
2401 simulcast_layers, 0, &opts);
2402 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2403
2404 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002405 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002406}
2407
2408// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2409// In this scenario, RIDs do not need to be negotiated (there is only one).
2410TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2411 MediaSessionOptions opts;
2412 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2413 RtpTransceiverDirection::kSendRecv, kActive,
2414 &opts);
2415 RidDescription rid("f", RidDirection::kSend);
2416 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2417 {kMediaStream1}, {rid},
2418 SimulcastLayerList(), 0, &opts);
2419 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2420
2421 ASSERT_NE(offer.get(), nullptr);
2422 const ContentInfo* content = offer->GetContentByName("video");
2423 ASSERT_NE(content, nullptr);
2424 const MediaContentDescription* cd = content->media_description();
2425 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002426 const StreamParamsVec& streams = cd->streams();
2427 ASSERT_THAT(streams, SizeIs(1));
2428 const StreamParams& stream = streams[0];
2429 ASSERT_THAT(stream.ssrcs, IsEmpty());
2430 EXPECT_FALSE(stream.has_rids());
2431 EXPECT_FALSE(cd->HasSimulcast());
2432}
2433
2434// Create an answer with spec-compliant simulcast video stream.
2435// In this scenario, the SFU is the caller requesting that we send Simulcast.
2436TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2437 MediaSessionOptions offer_opts;
2438 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2439 RtpTransceiverDirection::kSendRecv, kActive,
2440 &offer_opts);
2441 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2442 {kMediaStream1}, 1, &offer_opts);
2443 std::unique_ptr<SessionDescription> offer =
2444 f1_.CreateOffer(offer_opts, nullptr);
2445
2446 MediaSessionOptions answer_opts;
2447 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2448 RtpTransceiverDirection::kSendRecv, kActive,
2449 &answer_opts);
2450
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002451 std::vector<RidDescription> rid_descriptions{
2452 RidDescription("f", RidDirection::kSend),
2453 RidDescription("h", RidDirection::kSend),
2454 RidDescription("q", RidDirection::kSend),
2455 };
2456 SimulcastLayerList simulcast_layers;
2457 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2458 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2459 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2460 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2461 {kMediaStream1}, rid_descriptions,
2462 simulcast_layers, 0, &answer_opts);
2463 std::unique_ptr<SessionDescription> answer =
2464 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2465
2466 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002467 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002468}
2469
2470// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2471// In this scenario, RIDs do not need to be negotiated (there is only one).
2472// Note that RID Direction is not the same as the transceiver direction.
2473TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2474 MediaSessionOptions offer_opts;
2475 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2476 RtpTransceiverDirection::kSendRecv, kActive,
2477 &offer_opts);
2478 RidDescription rid_offer("f", RidDirection::kSend);
2479 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2480 {kMediaStream1}, {rid_offer},
2481 SimulcastLayerList(), 0, &offer_opts);
2482 std::unique_ptr<SessionDescription> offer =
2483 f1_.CreateOffer(offer_opts, nullptr);
2484
2485 MediaSessionOptions answer_opts;
2486 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2487 RtpTransceiverDirection::kSendRecv, kActive,
2488 &answer_opts);
2489
2490 RidDescription rid_answer("f", RidDirection::kReceive);
2491 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2492 {kMediaStream1}, {rid_answer},
2493 SimulcastLayerList(), 0, &answer_opts);
2494 std::unique_ptr<SessionDescription> answer =
2495 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2496
2497 ASSERT_NE(answer.get(), nullptr);
2498 const ContentInfo* content = offer->GetContentByName("video");
2499 ASSERT_NE(content, nullptr);
2500 const MediaContentDescription* cd = content->media_description();
2501 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002502 const StreamParamsVec& streams = cd->streams();
2503 ASSERT_THAT(streams, SizeIs(1));
2504 const StreamParams& stream = streams[0];
2505 ASSERT_THAT(stream.ssrcs, IsEmpty());
2506 EXPECT_FALSE(stream.has_rids());
2507 EXPECT_FALSE(cd->HasSimulcast());
2508}
2509
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002510// Create an audio and video answer to a standard video offer with:
2511// - one video track
2512// - two audio tracks
2513// - two data tracks
2514// and ensure it matches what we expect. Also updates the initial answer by
2515// adding a new video track and removes one of the audio tracks.
2516TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2517 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002518 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2519 RtpTransceiverDirection::kRecvOnly, kActive,
2520 &offer_opts);
2521 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2522 RtpTransceiverDirection::kRecvOnly, kActive,
2523 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002524 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002525 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2526 RtpTransceiverDirection::kRecvOnly, kActive,
2527 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528 f1_.set_secure(SEC_ENABLED);
2529 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002530 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002531
zhihuang1c378ed2017-08-17 14:10:50 -07002532 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002533 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2534 RtpTransceiverDirection::kSendRecv, kActive,
2535 &answer_opts);
2536 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2537 RtpTransceiverDirection::kSendRecv, kActive,
2538 &answer_opts);
2539 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2540 {kMediaStream1}, 1, &answer_opts);
2541 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2542 {kMediaStream1}, 1, &answer_opts);
2543 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2544 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002545
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002546 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2547 RtpTransceiverDirection::kSendRecv, kActive,
2548 &answer_opts);
2549 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2550 {kMediaStream1}, 1, &answer_opts);
2551 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2552 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002553 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002554
Steve Anton6fe1fba2018-12-11 10:15:23 -08002555 std::unique_ptr<SessionDescription> answer =
2556 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002557
2558 ASSERT_TRUE(answer.get() != NULL);
2559 const ContentInfo* ac = answer->GetContentByName("audio");
2560 const ContentInfo* vc = answer->GetContentByName("video");
2561 const ContentInfo* dc = answer->GetContentByName("data");
2562 ASSERT_TRUE(ac != NULL);
2563 ASSERT_TRUE(vc != NULL);
2564 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002565 const AudioContentDescription* acd = ac->media_description()->as_audio();
2566 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002567 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002568 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2569 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2570 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002571
2572 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002573 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002574
2575 const StreamParamsVec& audio_streams = acd->streams();
2576 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002577 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002578 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2579 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2580 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2581 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2582 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2583 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2584
2585 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2586 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2587
2588 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002589 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002590
2591 const StreamParamsVec& video_streams = vcd->streams();
2592 ASSERT_EQ(1U, video_streams.size());
2593 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2594 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2595 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2596 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2597
2598 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002599 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002600
2601 const StreamParamsVec& data_streams = dcd->streams();
2602 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002603 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002604 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2605 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2606 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2607 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2608 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2609 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2610
2611 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002612 dcd->bandwidth()); // default bandwidth (auto)
2613 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002614
2615 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002616 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002617 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2618 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002619 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2620 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002621 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002622 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002623
2624 ASSERT_TRUE(updated_answer.get() != NULL);
2625 ac = updated_answer->GetContentByName("audio");
2626 vc = updated_answer->GetContentByName("video");
2627 dc = updated_answer->GetContentByName("data");
2628 ASSERT_TRUE(ac != NULL);
2629 ASSERT_TRUE(vc != NULL);
2630 ASSERT_TRUE(dc != NULL);
2631 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002632 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002633 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002634 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002635 const RtpDataContentDescription* updated_dcd =
2636 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002637
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002638 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002640 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002641 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002642 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002643 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2644
2645 EXPECT_EQ(acd->type(), updated_acd->type());
2646 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2647 EXPECT_EQ(vcd->type(), updated_vcd->type());
2648 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2649 EXPECT_EQ(dcd->type(), updated_dcd->type());
2650 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2651
2652 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2653 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002654 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002655
2656 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2657 ASSERT_EQ(2U, updated_video_streams.size());
2658 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2659 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002660 // All media streams in one PeerConnection share one CNAME.
2661 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002662
2663 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2664 ASSERT_EQ(1U, updated_data_streams.size());
2665 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2666}
2667
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002668// Create an updated offer after creating an answer to the original offer and
2669// verify that the codecs that were part of the original answer are not changed
2670// in the updated offer.
2671TEST_F(MediaSessionDescriptionFactoryTest,
2672 RespondentCreatesOfferAfterCreatingAnswer) {
2673 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002674 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002675
Steve Anton6fe1fba2018-12-11 10:15:23 -08002676 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2677 std::unique_ptr<SessionDescription> answer =
2678 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002679
2680 const AudioContentDescription* acd =
2681 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002682 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002683
2684 const VideoContentDescription* vcd =
2685 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002686 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002687
kwiberg31022942016-03-11 14:18:21 -08002688 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002689 f2_.CreateOffer(opts, answer.get()));
2690
2691 // The expected audio codecs are the common audio codecs from the first
2692 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2693 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002694 // TODO(wu): |updated_offer| should not include the codec
2695 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002697 kAudioCodecsAnswer[0],
2698 kAudioCodecsAnswer[1],
2699 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002700 };
2701
2702 // The expected video codecs are the common video codecs from the first
2703 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2704 // preference order.
2705 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002706 kVideoCodecsAnswer[0],
2707 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002708 };
2709
2710 const AudioContentDescription* updated_acd =
2711 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002712 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713
2714 const VideoContentDescription* updated_vcd =
2715 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002716 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002717}
2718
Steve Anton5c72e712018-12-10 14:25:30 -08002719// Test that a reoffer does not reuse audio codecs from a previous media section
2720// that is being recycled.
2721TEST_F(MediaSessionDescriptionFactoryTest,
2722 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002723 f1_.set_video_codecs({}, {});
2724 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002725
2726 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002727 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2728 RtpTransceiverDirection::kSendRecv, kActive,
2729 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002730 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2731 std::unique_ptr<SessionDescription> answer =
2732 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002733
2734 // Recycle the media section by changing its mid.
2735 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002736 std::unique_ptr<SessionDescription> reoffer =
2737 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002738
2739 // Expect that the results of the first negotiation are ignored. If the m=
2740 // section was not recycled the payload types would match the initial offerer.
2741 const AudioContentDescription* acd =
2742 GetFirstAudioContentDescription(reoffer.get());
2743 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2744}
2745
2746// Test that a reoffer does not reuse video codecs from a previous media section
2747// that is being recycled.
2748TEST_F(MediaSessionDescriptionFactoryTest,
2749 ReOfferDoesNotReUseRecycledVideoCodecs) {
2750 f1_.set_audio_codecs({}, {});
2751 f2_.set_audio_codecs({}, {});
2752
2753 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002754 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2755 RtpTransceiverDirection::kSendRecv, kActive,
2756 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002757 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2758 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002759
2760 // Recycle the media section by changing its mid.
2761 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002762 std::unique_ptr<SessionDescription> reoffer =
2763 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002764
2765 // Expect that the results of the first negotiation are ignored. If the m=
2766 // section was not recycled the payload types would match the initial offerer.
2767 const VideoContentDescription* vcd =
2768 GetFirstVideoContentDescription(reoffer.get());
2769 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2770}
2771
2772// Test that a reanswer does not reuse audio codecs from a previous media
2773// section that is being recycled.
2774TEST_F(MediaSessionDescriptionFactoryTest,
2775 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002776 f1_.set_video_codecs({}, {});
2777 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002778
2779 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2780 // second offer/answer is forward (|f1_| as offerer).
2781 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002782 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2783 RtpTransceiverDirection::kSendRecv, kActive,
2784 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002785 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2786 std::unique_ptr<SessionDescription> answer =
2787 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002788
2789 // Recycle the media section by changing its mid.
2790 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002791 std::unique_ptr<SessionDescription> reoffer =
2792 f1_.CreateOffer(opts, answer.get());
2793 std::unique_ptr<SessionDescription> reanswer =
2794 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002795
2796 // Expect that the results of the first negotiation are ignored. If the m=
2797 // section was not recycled the payload types would match the initial offerer.
2798 const AudioContentDescription* acd =
2799 GetFirstAudioContentDescription(reanswer.get());
2800 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2801}
2802
2803// Test that a reanswer does not reuse video codecs from a previous media
2804// section that is being recycled.
2805TEST_F(MediaSessionDescriptionFactoryTest,
2806 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2807 f1_.set_audio_codecs({}, {});
2808 f2_.set_audio_codecs({}, {});
2809
2810 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2811 // second offer/answer is forward (|f1_| as offerer).
2812 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002813 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2814 RtpTransceiverDirection::kSendRecv, kActive,
2815 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002816 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2817 std::unique_ptr<SessionDescription> answer =
2818 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002819
2820 // Recycle the media section by changing its mid.
2821 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002822 std::unique_ptr<SessionDescription> reoffer =
2823 f1_.CreateOffer(opts, answer.get());
2824 std::unique_ptr<SessionDescription> reanswer =
2825 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002826
2827 // Expect that the results of the first negotiation are ignored. If the m=
2828 // section was not recycled the payload types would match the initial offerer.
2829 const VideoContentDescription* vcd =
2830 GetFirstVideoContentDescription(reanswer.get());
2831 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2832}
2833
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002834// Create an updated offer after creating an answer to the original offer and
2835// verify that the codecs that were part of the original answer are not changed
2836// in the updated offer. In this test Rtx is enabled.
2837TEST_F(MediaSessionDescriptionFactoryTest,
2838 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2839 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002840 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2841 RtpTransceiverDirection::kRecvOnly, kActive,
2842 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002843 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002844 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002845 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002846 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002847
2848 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002849 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002850 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002851 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002852
Steve Anton6fe1fba2018-12-11 10:15:23 -08002853 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002854 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002855 std::unique_ptr<SessionDescription> answer =
2856 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002857
2858 const VideoContentDescription* vcd =
2859 GetFirstVideoContentDescription(answer.get());
2860
2861 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002862 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2863 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002864
2865 EXPECT_EQ(expected_codecs, vcd->codecs());
2866
deadbeef67cf2c12016-04-13 10:07:16 -07002867 // Now, make sure we get same result (except for the order) if |f2_| creates
2868 // an updated offer even though the default payload types between |f1_| and
2869 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002870 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002871 f2_.CreateOffer(opts, answer.get()));
2872 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002873 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2875
2876 const VideoContentDescription* updated_vcd =
2877 GetFirstVideoContentDescription(updated_answer.get());
2878
2879 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2880}
2881
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002882// Regression test for:
2883// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2884// Existing codecs should always appear before new codecs in re-offers. But
2885// under a specific set of circumstances, the existing RTX codec was ending up
2886// added to the end of the list.
2887TEST_F(MediaSessionDescriptionFactoryTest,
2888 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2889 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002890 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2891 RtpTransceiverDirection::kRecvOnly, kActive,
2892 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002893 // We specifically choose different preferred payload types for VP8 to
2894 // trigger the issue.
2895 cricket::VideoCodec vp8_offerer(100, "VP8");
2896 cricket::VideoCodec vp8_offerer_rtx =
2897 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2898 cricket::VideoCodec vp8_answerer(110, "VP8");
2899 cricket::VideoCodec vp8_answerer_rtx =
2900 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2901 cricket::VideoCodec vp9(120, "VP9");
2902 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2903
2904 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2905 // We also specifically cause the answerer to prefer VP9, such that if it
2906 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2907 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2908 vp8_answerer_rtx};
2909
Johannes Kron3e983682020-03-29 22:17:00 +02002910 f1_.set_video_codecs(f1_codecs, f1_codecs);
2911 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002912 std::vector<AudioCodec> audio_codecs;
2913 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2914 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2915
2916 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002917 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002918 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002919 std::unique_ptr<SessionDescription> answer =
2920 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002921
2922 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2923 // But if the bug is triggered, RTX for VP8 ends up last.
2924 std::unique_ptr<SessionDescription> updated_offer(
2925 f2_.CreateOffer(opts, answer.get()));
2926
2927 const VideoContentDescription* vcd =
2928 GetFirstVideoContentDescription(updated_offer.get());
2929 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2930 ASSERT_EQ(4u, codecs.size());
2931 EXPECT_EQ(vp8_offerer, codecs[0]);
2932 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2933 EXPECT_EQ(vp9, codecs[2]);
2934 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002935}
2936
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002937// Create an updated offer that adds video after creating an audio only answer
2938// to the original offer. This test verifies that if a video codec and the RTX
2939// codec have the same default payload type as an audio codec that is already in
2940// use, the added codecs payload types are changed.
2941TEST_F(MediaSessionDescriptionFactoryTest,
2942 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2943 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002944 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002945 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002946 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002947
2948 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002949 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2950 RtpTransceiverDirection::kRecvOnly, kActive,
2951 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002952
Steve Anton6fe1fba2018-12-11 10:15:23 -08002953 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2954 std::unique_ptr<SessionDescription> answer =
2955 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002956
2957 const AudioContentDescription* acd =
2958 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002959 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002960
2961 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2962 // reference be the same as an audio codec that was negotiated in the
2963 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002964 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002965 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002966
2967 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2968 int used_pl_type = acd->codecs()[0].id;
2969 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002970 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002971 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002972
kwiberg31022942016-03-11 14:18:21 -08002973 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974 f2_.CreateOffer(opts, answer.get()));
2975 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002976 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002977 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2978
2979 const AudioContentDescription* updated_acd =
2980 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002981 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002982
2983 const VideoContentDescription* updated_vcd =
2984 GetFirstVideoContentDescription(updated_answer.get());
2985
2986 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002987 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002988 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002989 EXPECT_NE(used_pl_type, new_h264_pl_type);
2990 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002991 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002992 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2993 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2994}
2995
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002996// Create an updated offer with RTX after creating an answer to an offer
2997// without RTX, and with different default payload types.
2998// Verify that the added RTX codec references the correct payload type.
2999TEST_F(MediaSessionDescriptionFactoryTest,
3000 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3001 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003002 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003003
3004 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3005 // This creates rtx for H264 with the payload type |f2_| uses.
3006 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003007 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003008
Steve Anton6fe1fba2018-12-11 10:15:23 -08003009 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003010 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003011 std::unique_ptr<SessionDescription> answer =
3012 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003013
3014 const VideoContentDescription* vcd =
3015 GetFirstVideoContentDescription(answer.get());
3016
3017 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3018 EXPECT_EQ(expected_codecs, vcd->codecs());
3019
3020 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
3021 // updated offer, even though the default payload types are different from
3022 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08003023 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003024 f2_.CreateOffer(opts, answer.get()));
3025 ASSERT_TRUE(updated_offer);
3026
3027 const VideoContentDescription* updated_vcd =
3028 GetFirstVideoContentDescription(updated_offer.get());
3029
3030 // New offer should attempt to add H263, and RTX for H264.
3031 expected_codecs.push_back(kVideoCodecs2[1]);
3032 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3033 &expected_codecs);
3034 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3035}
3036
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003037// Test that RTX is ignored when there is no associated payload type parameter.
3038TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3039 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003040 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3041 RtpTransceiverDirection::kRecvOnly, kActive,
3042 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003043 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003044 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003045 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003046 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003047
3048 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003049 // This creates RTX for H264 with the payload type |f2_| uses.
3050 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003051 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003052
Steve Anton6fe1fba2018-12-11 10:15:23 -08003053 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003054 ASSERT_TRUE(offer.get() != NULL);
3055 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3056 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3057 // is possible to test that that RTX is dropped when
3058 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003059 MediaContentDescription* media_desc =
3060 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3061 ASSERT_TRUE(media_desc);
3062 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003063 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003064 for (VideoCodec& codec : codecs) {
Mirko Bonadei57cabed2020-04-01 12:03:11 +02003065 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
Steve Anton3a66edf2018-09-10 12:57:37 -07003066 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003067 }
3068 }
3069 desc->set_codecs(codecs);
3070
Steve Anton6fe1fba2018-12-11 10:15:23 -08003071 std::unique_ptr<SessionDescription> answer =
3072 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003073
Steve Anton64b626b2019-01-28 17:25:26 -08003074 EXPECT_THAT(
3075 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3076 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003077}
3078
3079// Test that RTX will be filtered out in the answer if its associated payload
3080// type doesn't match the local value.
3081TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3082 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003083 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3084 RtpTransceiverDirection::kRecvOnly, kActive,
3085 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003086 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3087 // This creates RTX for H264 in sender.
3088 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003089 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003090
3091 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3092 // This creates RTX for H263 in receiver.
3093 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003094 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003095
Steve Anton6fe1fba2018-12-11 10:15:23 -08003096 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003097 ASSERT_TRUE(offer.get() != NULL);
3098 // Associated payload type doesn't match, therefore, RTX codec is removed in
3099 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003100 std::unique_ptr<SessionDescription> answer =
3101 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003102
Steve Anton64b626b2019-01-28 17:25:26 -08003103 EXPECT_THAT(
3104 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3105 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003106}
3107
3108// Test that when multiple RTX codecs are offered, only the matched RTX codec
3109// is added in the answer, and the unsupported RTX codec is filtered out.
3110TEST_F(MediaSessionDescriptionFactoryTest,
3111 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3112 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003113 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3114 RtpTransceiverDirection::kRecvOnly, kActive,
3115 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003116 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3117 // This creates RTX for H264-SVC in sender.
3118 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003119 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003120
3121 // This creates RTX for H264 in sender.
3122 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003123 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003124
3125 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3126 // This creates RTX for H264 in receiver.
3127 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003128 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003129
3130 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3131 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003132 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003133 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003134 std::unique_ptr<SessionDescription> answer =
3135 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003136 const VideoContentDescription* vcd =
3137 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003138 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3139 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3140 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003141
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003142 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003143}
3144
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003145// Test that after one RTX codec has been negotiated, a new offer can attempt
3146// to add another.
3147TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3148 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003149 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3150 RtpTransceiverDirection::kRecvOnly, kActive,
3151 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003152 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3153 // This creates RTX for H264 for the offerer.
3154 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003155 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003156
Steve Anton6fe1fba2018-12-11 10:15:23 -08003157 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003158 ASSERT_TRUE(offer);
3159 const VideoContentDescription* vcd =
3160 GetFirstVideoContentDescription(offer.get());
3161
3162 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3163 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3164 &expected_codecs);
3165 EXPECT_EQ(expected_codecs, vcd->codecs());
3166
3167 // Now, attempt to add RTX for H264-SVC.
3168 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003169 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003170
kwiberg31022942016-03-11 14:18:21 -08003171 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003172 f1_.CreateOffer(opts, offer.get()));
3173 ASSERT_TRUE(updated_offer);
3174 vcd = GetFirstVideoContentDescription(updated_offer.get());
3175
3176 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3177 &expected_codecs);
3178 EXPECT_EQ(expected_codecs, vcd->codecs());
3179}
3180
Noah Richards2e7a0982015-05-18 14:02:54 -07003181// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3182// generated for each simulcast ssrc and correctly grouped.
3183TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3184 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003185 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3186 RtpTransceiverDirection::kSendRecv, kActive,
3187 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003188 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003189 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3190 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003191
3192 // Use a single real codec, and then add RTX for it.
3193 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003194 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003195 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003196 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003197
3198 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3199 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003200 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003201 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003202 MediaContentDescription* media_desc =
3203 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3204 ASSERT_TRUE(media_desc);
3205 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003206 const StreamParamsVec& streams = desc->streams();
3207 // Single stream.
3208 ASSERT_EQ(1u, streams.size());
3209 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3210 EXPECT_EQ(6u, streams[0].ssrcs.size());
3211 // And should have a SIM group for the simulcast.
3212 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3213 // And a FID group for RTX.
3214 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003215 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003216 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3217 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003218 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003219 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3220 EXPECT_EQ(3u, fid_ssrcs.size());
3221}
3222
brandtr03d5fb12016-11-22 03:37:59 -08003223// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3224// together with a FEC-FR grouping.
3225TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3226 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003227 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3228 RtpTransceiverDirection::kSendRecv, kActive,
3229 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003230 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003231 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3232 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003233
3234 // Use a single real codec, and then add FlexFEC for it.
3235 std::vector<VideoCodec> f1_codecs;
3236 f1_codecs.push_back(VideoCodec(97, "H264"));
3237 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003238 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003239
3240 // Ensure that the offer has a single FlexFEC ssrc and that
3241 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003242 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003243 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003244 MediaContentDescription* media_desc =
3245 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3246 ASSERT_TRUE(media_desc);
3247 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003248 const StreamParamsVec& streams = desc->streams();
3249 // Single stream.
3250 ASSERT_EQ(1u, streams.size());
3251 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3252 EXPECT_EQ(2u, streams[0].ssrcs.size());
3253 // And should have a FEC-FR group for FlexFEC.
3254 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3255 std::vector<uint32_t> primary_ssrcs;
3256 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3257 ASSERT_EQ(1u, primary_ssrcs.size());
3258 uint32_t flexfec_ssrc;
3259 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3260 EXPECT_NE(flexfec_ssrc, 0u);
3261}
3262
3263// Test that FlexFEC is disabled for simulcast.
3264// TODO(brandtr): Remove this test when we support simulcast, either through
3265// multiple FlexfecSenders, or through multistream protection.
3266TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3267 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003268 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3269 RtpTransceiverDirection::kSendRecv, kActive,
3270 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003271 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003272 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3273 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003274
3275 // Use a single real codec, and then add FlexFEC for it.
3276 std::vector<VideoCodec> f1_codecs;
3277 f1_codecs.push_back(VideoCodec(97, "H264"));
3278 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003279 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003280
3281 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3282 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003283 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003284 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003285 MediaContentDescription* media_desc =
3286 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3287 ASSERT_TRUE(media_desc);
3288 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003289 const StreamParamsVec& streams = desc->streams();
3290 // Single stream.
3291 ASSERT_EQ(1u, streams.size());
3292 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3293 EXPECT_EQ(3u, streams[0].ssrcs.size());
3294 // And should have a SIM group for the simulcast.
3295 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3296 // And not a FEC-FR group for FlexFEC.
3297 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3298 std::vector<uint32_t> primary_ssrcs;
3299 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3300 EXPECT_EQ(3u, primary_ssrcs.size());
3301 for (uint32_t primary_ssrc : primary_ssrcs) {
3302 uint32_t flexfec_ssrc;
3303 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3304 }
3305}
3306
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003307// Create an updated offer after creating an answer to the original offer and
3308// verify that the RTP header extensions that were part of the original answer
3309// are not changed in the updated offer.
3310TEST_F(MediaSessionDescriptionFactoryTest,
3311 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3312 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003313 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003314
3315 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3316 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3317 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3318 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3319
Steve Anton6fe1fba2018-12-11 10:15:23 -08003320 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3321 std::unique_ptr<SessionDescription> answer =
3322 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003323
Yves Gerey665174f2018-06-19 15:03:05 +02003324 EXPECT_EQ(
3325 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3326 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3327 EXPECT_EQ(
3328 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3329 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003330
kwiberg31022942016-03-11 14:18:21 -08003331 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003332 f2_.CreateOffer(opts, answer.get()));
3333
3334 // The expected RTP header extensions in the new offer are the resulting
3335 // extensions from the first offer/answer exchange plus the extensions only
3336 // |f2_| offer.
3337 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003338 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003339 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003340 kAudioRtpExtensionAnswer[0],
3341 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003342 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003343 };
3344
3345 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003346 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003347 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003348 kVideoRtpExtensionAnswer[0],
3349 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003350 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003351 };
3352
3353 const AudioContentDescription* updated_acd =
3354 GetFirstAudioContentDescription(updated_offer.get());
3355 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3356 updated_acd->rtp_header_extensions());
3357
3358 const VideoContentDescription* updated_vcd =
3359 GetFirstVideoContentDescription(updated_offer.get());
3360 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3361 updated_vcd->rtp_header_extensions());
3362}
3363
deadbeefa5b273a2015-08-20 17:30:13 -07003364// Verify that if the same RTP extension URI is used for audio and video, the
3365// same ID is used. Also verify that the ID isn't changed when creating an
3366// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003367TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003368 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003369 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003370
3371 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3372 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3373
Steve Anton6fe1fba2018-12-11 10:15:23 -08003374 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003375
3376 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3377 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003378 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003379 kVideoRtpExtension3[0],
3380 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003381 };
3382
Yves Gerey665174f2018-06-19 15:03:05 +02003383 EXPECT_EQ(
3384 MAKE_VECTOR(kAudioRtpExtension3),
3385 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3386 EXPECT_EQ(
3387 MAKE_VECTOR(kExpectedVideoRtpExtension),
3388 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003389
3390 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003391 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003392 f1_.CreateOffer(opts, offer.get()));
3393
3394 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003395 GetFirstAudioContentDescription(updated_offer.get())
3396 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003397 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003398 GetFirstVideoContentDescription(updated_offer.get())
3399 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003400}
3401
jbauch5869f502017-06-29 12:31:36 -07003402// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3403TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3404 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003405 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003406
3407 f1_.set_enable_encrypted_rtp_header_extensions(true);
3408 f2_.set_enable_encrypted_rtp_header_extensions(true);
3409
3410 f1_.set_audio_rtp_header_extensions(
3411 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3412 f1_.set_video_rtp_header_extensions(
3413 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3414
Steve Anton6fe1fba2018-12-11 10:15:23 -08003415 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003416
3417 // The extensions that are shared between audio and video should use the same
3418 // id.
3419 const RtpExtension kExpectedVideoRtpExtension[] = {
3420 kVideoRtpExtension3ForEncryption[0],
3421 kAudioRtpExtension3ForEncryptionOffer[1],
3422 kAudioRtpExtension3ForEncryptionOffer[2],
3423 };
3424
Yves Gerey665174f2018-06-19 15:03:05 +02003425 EXPECT_EQ(
3426 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3427 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3428 EXPECT_EQ(
3429 MAKE_VECTOR(kExpectedVideoRtpExtension),
3430 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003431
3432 // Nothing should change when creating a new offer
3433 std::unique_ptr<SessionDescription> updated_offer(
3434 f1_.CreateOffer(opts, offer.get()));
3435
3436 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003437 GetFirstAudioContentDescription(updated_offer.get())
3438 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003439 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003440 GetFirstVideoContentDescription(updated_offer.get())
3441 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003442}
3443
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003444TEST(MediaSessionDescription, CopySessionDescription) {
3445 SessionDescription source;
3446 cricket::ContentGroup group(cricket::CN_AUDIO);
3447 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003448 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003449 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003450 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3451 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003452 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003453 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003454 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003455 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3456 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003457 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003458
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003459 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003460 ASSERT_TRUE(copy.get() != NULL);
3461 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3462 const ContentInfo* ac = copy->GetContentByName("audio");
3463 const ContentInfo* vc = copy->GetContentByName("video");
3464 ASSERT_TRUE(ac != NULL);
3465 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003466 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003467 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003468 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3469 EXPECT_EQ(1u, acd->first_ssrc());
3470
Steve Anton5adfafd2017-12-20 16:34:00 -08003471 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003472 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003473 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3474 EXPECT_EQ(2u, vcd->first_ssrc());
3475}
3476
3477// The below TestTransportInfoXXX tests create different offers/answers, and
3478// ensure the TransportInfo in the SessionDescription matches what we expect.
3479TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3480 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003481 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3482 RtpTransceiverDirection::kRecvOnly, kActive,
3483 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003484 TestTransportInfo(true, options, false);
3485}
3486
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003487TEST_F(MediaSessionDescriptionFactoryTest,
3488 TestTransportInfoOfferIceRenomination) {
3489 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003490 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3491 RtpTransceiverDirection::kRecvOnly, kActive,
3492 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003493 options.media_description_options[0]
3494 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003495 TestTransportInfo(true, options, false);
3496}
3497
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003498TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3499 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003500 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3501 RtpTransceiverDirection::kRecvOnly, kActive,
3502 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003503 TestTransportInfo(true, options, true);
3504}
3505
3506TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3507 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003508 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3509 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3510 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003511 TestTransportInfo(true, options, false);
3512}
3513
3514TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003515 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003516 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003517 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3518 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3519 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003520 TestTransportInfo(true, options, true);
3521}
3522
3523TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3524 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003525 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3526 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3527 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003528 options.bundle_enabled = true;
3529 TestTransportInfo(true, options, false);
3530}
3531
3532TEST_F(MediaSessionDescriptionFactoryTest,
3533 TestTransportInfoOfferBundleCurrent) {
3534 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003535 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3536 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3537 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003538 options.bundle_enabled = true;
3539 TestTransportInfo(true, options, true);
3540}
3541
3542TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3543 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003544 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3545 RtpTransceiverDirection::kRecvOnly, kActive,
3546 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003547 TestTransportInfo(false, options, false);
3548}
3549
3550TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003551 TestTransportInfoAnswerIceRenomination) {
3552 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003553 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3554 RtpTransceiverDirection::kRecvOnly, kActive,
3555 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003556 options.media_description_options[0]
3557 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003558 TestTransportInfo(false, options, false);
3559}
3560
3561TEST_F(MediaSessionDescriptionFactoryTest,
3562 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003563 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003564 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3565 RtpTransceiverDirection::kRecvOnly, kActive,
3566 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003567 TestTransportInfo(false, options, true);
3568}
3569
3570TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3571 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003572 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3573 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3574 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003575 TestTransportInfo(false, options, false);
3576}
3577
3578TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003579 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003580 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003581 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3582 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3583 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003584 TestTransportInfo(false, options, true);
3585}
3586
3587TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3588 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003589 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3590 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3591 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003592 options.bundle_enabled = true;
3593 TestTransportInfo(false, options, false);
3594}
3595
3596TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003597 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003598 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003599 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3600 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3601 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003602 options.bundle_enabled = true;
3603 TestTransportInfo(false, options, true);
3604}
3605
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003606TEST_F(MediaSessionDescriptionFactoryTest,
3607 TestTransportInfoOfferBundlesTransportOptions) {
3608 MediaSessionOptions options;
3609 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3610
3611 cricket::OpaqueTransportParameters audio_params;
3612 audio_params.protocol = "audio-transport";
3613 audio_params.parameters = "audio-params";
3614 FindFirstMediaDescriptionByMid("audio", &options)
3615 ->transport_options.opaque_parameters = audio_params;
3616
3617 cricket::OpaqueTransportParameters video_params;
3618 video_params.protocol = "video-transport";
3619 video_params.parameters = "video-params";
3620 FindFirstMediaDescriptionByMid("video", &options)
3621 ->transport_options.opaque_parameters = video_params;
3622
3623 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3624}
3625
3626TEST_F(MediaSessionDescriptionFactoryTest,
3627 TestTransportInfoAnswerBundlesTransportOptions) {
3628 MediaSessionOptions options;
3629 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3630
3631 cricket::OpaqueTransportParameters audio_params;
3632 audio_params.protocol = "audio-transport";
3633 audio_params.parameters = "audio-params";
3634 FindFirstMediaDescriptionByMid("audio", &options)
3635 ->transport_options.opaque_parameters = audio_params;
3636
3637 cricket::OpaqueTransportParameters video_params;
3638 video_params.protocol = "video-transport";
3639 video_params.parameters = "video-params";
3640 FindFirstMediaDescriptionByMid("video", &options)
3641 ->transport_options.opaque_parameters = video_params;
3642
3643 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3644}
3645
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003646TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3647 MediaSessionOptions options;
3648 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3649 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3650 &options);
3651
3652 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3653 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3654 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3655
3656 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3657
3658 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3659 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3660 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3661}
3662
3663TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3664 MediaSessionOptions options;
3665 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3666 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3667 &options);
3668
3669 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3670 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3671 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3672
3673 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3674 std::unique_ptr<SessionDescription> answer =
3675 f1_.CreateAnswer(offer.get(), options, nullptr);
3676
3677 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3678 "foo");
3679 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3680 "bar");
3681 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3682}
3683
3684TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3685 MediaSessionOptions options;
3686 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3687 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3688 &options);
3689
3690 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3691
3692 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3693 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3694 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3695
3696 std::unique_ptr<SessionDescription> answer =
3697 f1_.CreateAnswer(offer.get(), options, nullptr);
3698
3699 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3700 absl::nullopt);
3701 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3702 absl::nullopt);
3703 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3704 absl::nullopt);
3705}
3706
3707TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3708 MediaSessionOptions options;
3709 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3710 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3711 &options);
3712
3713 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3714 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3715 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3716
3717 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3718
3719 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3720 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3721 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3722
3723 std::unique_ptr<SessionDescription> answer =
3724 f1_.CreateAnswer(offer.get(), options, nullptr);
3725
3726 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3727 absl::nullopt);
3728 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3729 absl::nullopt);
3730 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3731 absl::nullopt);
3732}
3733
3734TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3735 MediaSessionOptions options;
3736 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3737 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3738 &options);
3739
3740 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3741 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3742 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3743
3744 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3745
3746 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3747 absl::nullopt;
3748 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3749 absl::nullopt;
3750 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3751 absl::nullopt;
3752
3753 std::unique_ptr<SessionDescription> answer =
3754 f1_.CreateAnswer(offer.get(), options, nullptr);
3755
3756 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3757 absl::nullopt);
3758 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3759 absl::nullopt);
3760 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3761 absl::nullopt);
3762}
3763
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003764// Create an offer with bundle enabled and verify the crypto parameters are
3765// the common set of the available cryptos.
3766TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3767 TestCryptoWithBundle(true);
3768}
3769
3770// Create an answer with bundle enabled and verify the crypto parameters are
3771// the common set of the available cryptos.
3772TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3773 TestCryptoWithBundle(false);
3774}
3775
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003776// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3777// DTLS is not enabled locally.
3778TEST_F(MediaSessionDescriptionFactoryTest,
3779 TestOfferDtlsSavpfWithoutDtlsFailed) {
3780 f1_.set_secure(SEC_ENABLED);
3781 f2_.set_secure(SEC_ENABLED);
3782 tdf1_.set_secure(SEC_DISABLED);
3783 tdf2_.set_secure(SEC_DISABLED);
3784
Steve Anton6fe1fba2018-12-11 10:15:23 -08003785 std::unique_ptr<SessionDescription> offer =
3786 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003787 ASSERT_TRUE(offer.get() != NULL);
3788 ContentInfo* offer_content = offer->GetContentByName("audio");
3789 ASSERT_TRUE(offer_content != NULL);
3790 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003791 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003792 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3793
Steve Anton6fe1fba2018-12-11 10:15:23 -08003794 std::unique_ptr<SessionDescription> answer =
3795 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003796 ASSERT_TRUE(answer != NULL);
3797 ContentInfo* answer_content = answer->GetContentByName("audio");
3798 ASSERT_TRUE(answer_content != NULL);
3799
3800 ASSERT_TRUE(answer_content->rejected);
3801}
3802
3803// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3804// UDP/TLS/RTP/SAVPF.
3805TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3806 f1_.set_secure(SEC_ENABLED);
3807 f2_.set_secure(SEC_ENABLED);
3808 tdf1_.set_secure(SEC_ENABLED);
3809 tdf2_.set_secure(SEC_ENABLED);
3810
Steve Anton6fe1fba2018-12-11 10:15:23 -08003811 std::unique_ptr<SessionDescription> offer =
3812 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003813 ASSERT_TRUE(offer.get() != NULL);
3814 ContentInfo* offer_content = offer->GetContentByName("audio");
3815 ASSERT_TRUE(offer_content != NULL);
3816 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003817 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003818 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3819
Steve Anton6fe1fba2018-12-11 10:15:23 -08003820 std::unique_ptr<SessionDescription> answer =
3821 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003822 ASSERT_TRUE(answer != NULL);
3823
3824 const ContentInfo* answer_content = answer->GetContentByName("audio");
3825 ASSERT_TRUE(answer_content != NULL);
3826 ASSERT_FALSE(answer_content->rejected);
3827
3828 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003829 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003830 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003831}
3832
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003833// Test that we include both SDES and DTLS in the offer, but only include SDES
3834// in the answer if DTLS isn't negotiated.
3835TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3836 f1_.set_secure(SEC_ENABLED);
3837 f2_.set_secure(SEC_ENABLED);
3838 tdf1_.set_secure(SEC_ENABLED);
3839 tdf2_.set_secure(SEC_DISABLED);
3840 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003841 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003842 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003843 const cricket::MediaContentDescription* audio_media_desc;
3844 const cricket::MediaContentDescription* video_media_desc;
3845 const cricket::TransportDescription* audio_trans_desc;
3846 const cricket::TransportDescription* video_trans_desc;
3847
3848 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003849 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003850 ASSERT_TRUE(offer.get() != NULL);
3851
Steve Antonb1c1de12017-12-21 15:14:30 -08003852 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003853 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003854 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003855 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003856 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003857 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3858
3859 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3860 ASSERT_TRUE(audio_trans_desc != NULL);
3861 video_trans_desc = offer->GetTransportDescriptionByName("video");
3862 ASSERT_TRUE(video_trans_desc != NULL);
3863 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3864 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3865
3866 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003867 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003868 ASSERT_TRUE(answer.get() != NULL);
3869
Steve Antonb1c1de12017-12-21 15:14:30 -08003870 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003871 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003872 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003873 ASSERT_TRUE(video_media_desc != NULL);
3874 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3875 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3876
3877 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3878 ASSERT_TRUE(audio_trans_desc != NULL);
3879 video_trans_desc = answer->GetTransportDescriptionByName("video");
3880 ASSERT_TRUE(video_trans_desc != NULL);
3881 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3882 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3883
3884 // Enable DTLS; the answer should now only have DTLS support.
3885 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003886 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003887 ASSERT_TRUE(answer.get() != NULL);
3888
Steve Antonb1c1de12017-12-21 15:14:30 -08003889 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003890 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003891 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003892 ASSERT_TRUE(video_media_desc != NULL);
3893 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3894 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003895 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3896 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003897
3898 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3899 ASSERT_TRUE(audio_trans_desc != NULL);
3900 video_trans_desc = answer->GetTransportDescriptionByName("video");
3901 ASSERT_TRUE(video_trans_desc != NULL);
3902 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3903 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003904
3905 // Try creating offer again. DTLS enabled now, crypto's should be empty
3906 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003907 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003908 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003909 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003910 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003911 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003912 ASSERT_TRUE(video_media_desc != NULL);
3913 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3914 EXPECT_TRUE(video_media_desc->cryptos().empty());
3915
3916 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3917 ASSERT_TRUE(audio_trans_desc != NULL);
3918 video_trans_desc = offer->GetTransportDescriptionByName("video");
3919 ASSERT_TRUE(video_trans_desc != NULL);
3920 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3921 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003922}
3923
3924// Test that an answer can't be created if cryptos are required but the offer is
3925// unsecure.
3926TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003927 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003928 f1_.set_secure(SEC_DISABLED);
3929 tdf1_.set_secure(SEC_DISABLED);
3930 f2_.set_secure(SEC_REQUIRED);
3931 tdf1_.set_secure(SEC_ENABLED);
3932
Steve Anton6fe1fba2018-12-11 10:15:23 -08003933 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003934 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003935 std::unique_ptr<SessionDescription> answer =
3936 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003937 EXPECT_TRUE(answer.get() == NULL);
3938}
3939
3940// Test that we accept a DTLS offer without SDES and create an appropriate
3941// answer.
3942TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3943 f1_.set_secure(SEC_DISABLED);
3944 f2_.set_secure(SEC_ENABLED);
3945 tdf1_.set_secure(SEC_ENABLED);
3946 tdf2_.set_secure(SEC_ENABLED);
3947 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003948 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3949 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3950 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003951
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003952 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003953 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003954 ASSERT_TRUE(offer.get() != NULL);
3955
3956 const AudioContentDescription* audio_offer =
3957 GetFirstAudioContentDescription(offer.get());
3958 ASSERT_TRUE(audio_offer->cryptos().empty());
3959 const VideoContentDescription* video_offer =
3960 GetFirstVideoContentDescription(offer.get());
3961 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003962 const RtpDataContentDescription* data_offer =
3963 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003964 ASSERT_TRUE(data_offer->cryptos().empty());
3965
3966 const cricket::TransportDescription* audio_offer_trans_desc =
3967 offer->GetTransportDescriptionByName("audio");
3968 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3969 const cricket::TransportDescription* video_offer_trans_desc =
3970 offer->GetTransportDescriptionByName("video");
3971 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3972 const cricket::TransportDescription* data_offer_trans_desc =
3973 offer->GetTransportDescriptionByName("data");
3974 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3975
3976 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003977 std::unique_ptr<SessionDescription> answer =
3978 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003979 ASSERT_TRUE(answer.get() != NULL);
3980
3981 const cricket::TransportDescription* audio_answer_trans_desc =
3982 answer->GetTransportDescriptionByName("audio");
3983 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3984 const cricket::TransportDescription* video_answer_trans_desc =
3985 answer->GetTransportDescriptionByName("video");
3986 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3987 const cricket::TransportDescription* data_answer_trans_desc =
3988 answer->GetTransportDescriptionByName("data");
3989 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3990}
3991
3992// Verifies if vad_enabled option is set to false, CN codecs are not present in
3993// offer or answer.
3994TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3995 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003996 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003997 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003998 ASSERT_TRUE(offer.get() != NULL);
3999 const ContentInfo* audio_content = offer->GetContentByName("audio");
4000 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
4001
4002 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08004003 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004004 ASSERT_TRUE(offer.get() != NULL);
4005 audio_content = offer->GetContentByName("audio");
4006 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08004007 std::unique_ptr<SessionDescription> answer =
4008 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004009 ASSERT_TRUE(answer.get() != NULL);
4010 audio_content = answer->GetContentByName("audio");
4011 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
4012}
deadbeef44f08192015-12-15 16:20:09 -08004013
zhihuang1c378ed2017-08-17 14:10:50 -07004014// Test that the generated MIDs match the existing offer.
4015TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08004016 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004017 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
4018 RtpTransceiverDirection::kRecvOnly, kActive,
4019 &opts);
4020 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
4021 RtpTransceiverDirection::kRecvOnly, kActive,
4022 &opts);
deadbeef44f08192015-12-15 16:20:09 -08004023 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004024 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
4025 RtpTransceiverDirection::kSendRecv, kActive,
4026 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004027 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004028 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08004029 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08004030 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07004031
deadbeef44f08192015-12-15 16:20:09 -08004032 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
4033 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
4034 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
4035 ASSERT_TRUE(audio_content != nullptr);
4036 ASSERT_TRUE(video_content != nullptr);
4037 ASSERT_TRUE(data_content != nullptr);
4038 EXPECT_EQ("audio_modified", audio_content->name);
4039 EXPECT_EQ("video_modified", video_content->name);
4040 EXPECT_EQ("data_modified", data_content->name);
4041}
zhihuangcf5b37c2016-05-05 11:44:35 -07004042
zhihuang1c378ed2017-08-17 14:10:50 -07004043// The following tests verify that the unified plan SDP is supported.
4044// Test that we can create an offer with multiple media sections of same media
4045// type.
4046TEST_F(MediaSessionDescriptionFactoryTest,
4047 CreateOfferWithMultipleAVMediaSections) {
4048 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004049 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4050 RtpTransceiverDirection::kSendRecv, kActive,
4051 &opts);
4052 AttachSenderToMediaDescriptionOptions(
4053 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004054
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004055 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4056 RtpTransceiverDirection::kSendRecv, kActive,
4057 &opts);
4058 AttachSenderToMediaDescriptionOptions(
4059 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004060
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004061 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4062 RtpTransceiverDirection::kSendRecv, kActive,
4063 &opts);
4064 AttachSenderToMediaDescriptionOptions(
4065 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004066
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004067 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4068 RtpTransceiverDirection::kSendRecv, kActive,
4069 &opts);
4070 AttachSenderToMediaDescriptionOptions(
4071 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004072 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004073 ASSERT_TRUE(offer);
4074
4075 ASSERT_EQ(4u, offer->contents().size());
4076 EXPECT_FALSE(offer->contents()[0].rejected);
4077 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004078 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004079 ASSERT_EQ(1u, acd->streams().size());
4080 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004081 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004082
4083 EXPECT_FALSE(offer->contents()[1].rejected);
4084 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004085 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004086 ASSERT_EQ(1u, vcd->streams().size());
4087 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004088 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004089
4090 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004091 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004092 ASSERT_EQ(1u, acd->streams().size());
4093 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004094 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004095
4096 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004097 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004098 ASSERT_EQ(1u, vcd->streams().size());
4099 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004100 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004101}
4102
4103// Test that we can create an answer with multiple media sections of same media
4104// type.
4105TEST_F(MediaSessionDescriptionFactoryTest,
4106 CreateAnswerWithMultipleAVMediaSections) {
4107 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004108 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4109 RtpTransceiverDirection::kSendRecv, kActive,
4110 &opts);
4111 AttachSenderToMediaDescriptionOptions(
4112 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004113
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004114 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4115 RtpTransceiverDirection::kSendRecv, kActive,
4116 &opts);
4117 AttachSenderToMediaDescriptionOptions(
4118 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004119
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004120 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4121 RtpTransceiverDirection::kSendRecv, kActive,
4122 &opts);
4123 AttachSenderToMediaDescriptionOptions(
4124 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004125
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004126 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4127 RtpTransceiverDirection::kSendRecv, kActive,
4128 &opts);
4129 AttachSenderToMediaDescriptionOptions(
4130 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004131
Steve Anton6fe1fba2018-12-11 10:15:23 -08004132 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004133 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004134 std::unique_ptr<SessionDescription> answer =
4135 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004136
4137 ASSERT_EQ(4u, answer->contents().size());
4138 EXPECT_FALSE(answer->contents()[0].rejected);
4139 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004140 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004141 ASSERT_EQ(1u, acd->streams().size());
4142 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004143 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004144
4145 EXPECT_FALSE(answer->contents()[1].rejected);
4146 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004147 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004148 ASSERT_EQ(1u, vcd->streams().size());
4149 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004150 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004151
4152 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004153 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004154 ASSERT_EQ(1u, acd->streams().size());
4155 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004156 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004157
4158 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004159 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004160 ASSERT_EQ(1u, vcd->streams().size());
4161 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004162 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004163}
4164
4165// Test that the media section will be rejected in offer if the corresponding
4166// MediaDescriptionOptions is stopped by the offerer.
4167TEST_F(MediaSessionDescriptionFactoryTest,
4168 CreateOfferWithMediaSectionStoppedByOfferer) {
4169 // Create an offer with two audio sections and one of them is stopped.
4170 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004171 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4172 RtpTransceiverDirection::kSendRecv, kActive,
4173 &offer_opts);
4174 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4175 RtpTransceiverDirection::kInactive, kStopped,
4176 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004177 std::unique_ptr<SessionDescription> offer =
4178 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004179 ASSERT_TRUE(offer);
4180 ASSERT_EQ(2u, offer->contents().size());
4181 EXPECT_FALSE(offer->contents()[0].rejected);
4182 EXPECT_TRUE(offer->contents()[1].rejected);
4183}
4184
4185// Test that the media section will be rejected in answer if the corresponding
4186// MediaDescriptionOptions is stopped by the offerer.
4187TEST_F(MediaSessionDescriptionFactoryTest,
4188 CreateAnswerWithMediaSectionStoppedByOfferer) {
4189 // Create an offer with two audio sections and one of them is stopped.
4190 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004191 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4192 RtpTransceiverDirection::kSendRecv, kActive,
4193 &offer_opts);
4194 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4195 RtpTransceiverDirection::kInactive, kStopped,
4196 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004197 std::unique_ptr<SessionDescription> offer =
4198 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004199 ASSERT_TRUE(offer);
4200 ASSERT_EQ(2u, offer->contents().size());
4201 EXPECT_FALSE(offer->contents()[0].rejected);
4202 EXPECT_TRUE(offer->contents()[1].rejected);
4203
4204 // Create an answer based on the offer.
4205 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004206 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4207 RtpTransceiverDirection::kSendRecv, kActive,
4208 &answer_opts);
4209 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4210 RtpTransceiverDirection::kSendRecv, kActive,
4211 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004212 std::unique_ptr<SessionDescription> answer =
4213 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004214 ASSERT_EQ(2u, answer->contents().size());
4215 EXPECT_FALSE(answer->contents()[0].rejected);
4216 EXPECT_TRUE(answer->contents()[1].rejected);
4217}
4218
4219// Test that the media section will be rejected in answer if the corresponding
4220// MediaDescriptionOptions is stopped by the answerer.
4221TEST_F(MediaSessionDescriptionFactoryTest,
4222 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4223 // Create an offer with two audio sections.
4224 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004225 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4226 RtpTransceiverDirection::kSendRecv, kActive,
4227 &offer_opts);
4228 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4229 RtpTransceiverDirection::kSendRecv, kActive,
4230 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004231 std::unique_ptr<SessionDescription> offer =
4232 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004233 ASSERT_TRUE(offer);
4234 ASSERT_EQ(2u, offer->contents().size());
4235 ASSERT_FALSE(offer->contents()[0].rejected);
4236 ASSERT_FALSE(offer->contents()[1].rejected);
4237
4238 // The answerer rejects one of the audio sections.
4239 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004240 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4241 RtpTransceiverDirection::kSendRecv, kActive,
4242 &answer_opts);
4243 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4244 RtpTransceiverDirection::kInactive, kStopped,
4245 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004246 std::unique_ptr<SessionDescription> answer =
4247 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004248 ASSERT_EQ(2u, answer->contents().size());
4249 EXPECT_FALSE(answer->contents()[0].rejected);
4250 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004251
4252 // The TransportInfo of the rejected m= section is expected to be added in the
4253 // answer.
4254 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004255}
4256
4257// Test the generated media sections has the same order of the
4258// corresponding MediaDescriptionOptions.
4259TEST_F(MediaSessionDescriptionFactoryTest,
4260 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4261 MediaSessionOptions opts;
4262 // This tests put video section first because normally audio comes first by
4263 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004264 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4265 RtpTransceiverDirection::kSendRecv, kActive,
4266 &opts);
4267 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4268 RtpTransceiverDirection::kSendRecv, kActive,
4269 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004270 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004271
4272 ASSERT_TRUE(offer);
4273 ASSERT_EQ(2u, offer->contents().size());
4274 EXPECT_EQ("video", offer->contents()[0].name);
4275 EXPECT_EQ("audio", offer->contents()[1].name);
4276}
4277
4278// Test that different media sections using the same codec have same payload
4279// type.
4280TEST_F(MediaSessionDescriptionFactoryTest,
4281 PayloadTypesSharedByMediaSectionsOfSameType) {
4282 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004283 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4284 RtpTransceiverDirection::kSendRecv, kActive,
4285 &opts);
4286 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4287 RtpTransceiverDirection::kSendRecv, kActive,
4288 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004289 // Create an offer with two video sections using same codecs.
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);
4292 ASSERT_EQ(2u, offer->contents().size());
4293 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004294 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004295 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004296 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004297 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4298 ASSERT_EQ(2u, vcd1->codecs().size());
4299 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4300 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4301 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4302 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4303
4304 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004305 std::unique_ptr<SessionDescription> answer =
4306 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004307 ASSERT_TRUE(answer);
4308 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004309 vcd1 = answer->contents()[0].media_description()->as_video();
4310 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004311 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4312 ASSERT_EQ(1u, vcd1->codecs().size());
4313 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4314 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4315}
4316
4317// Test that the codec preference order per media section is respected in
4318// subsequent offer.
4319TEST_F(MediaSessionDescriptionFactoryTest,
4320 CreateOfferRespectsCodecPreferenceOrder) {
4321 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004322 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4323 RtpTransceiverDirection::kSendRecv, kActive,
4324 &opts);
4325 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4326 RtpTransceiverDirection::kSendRecv, kActive,
4327 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004328 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004329 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004330 ASSERT_TRUE(offer);
4331 ASSERT_EQ(2u, offer->contents().size());
4332 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004333 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004334 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004335 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004336 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4337 EXPECT_EQ(video_codecs, vcd1->codecs());
4338 EXPECT_EQ(video_codecs, vcd2->codecs());
4339
4340 // Change the codec preference of the first video section and create a
4341 // follow-up offer.
4342 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4343 vcd1->set_codecs(video_codecs_reverse);
4344 std::unique_ptr<SessionDescription> updated_offer(
4345 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004346 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4347 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004348 // The video codec preference order should be respected.
4349 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4350 EXPECT_EQ(video_codecs, vcd2->codecs());
4351}
4352
4353// Test that the codec preference order per media section is respected in
4354// the answer.
4355TEST_F(MediaSessionDescriptionFactoryTest,
4356 CreateAnswerRespectsCodecPreferenceOrder) {
4357 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004358 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4359 RtpTransceiverDirection::kSendRecv, kActive,
4360 &opts);
4361 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4362 RtpTransceiverDirection::kSendRecv, kActive,
4363 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004364 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004365 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004366 ASSERT_TRUE(offer);
4367 ASSERT_EQ(2u, offer->contents().size());
4368 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004369 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004370 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004371 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004372 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4373 EXPECT_EQ(video_codecs, vcd1->codecs());
4374 EXPECT_EQ(video_codecs, vcd2->codecs());
4375
4376 // Change the codec preference of the first video section and create an
4377 // answer.
4378 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4379 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004380 std::unique_ptr<SessionDescription> answer =
4381 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004382 vcd1 = answer->contents()[0].media_description()->as_video();
4383 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004384 // The video codec preference order should be respected.
4385 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4386 EXPECT_EQ(video_codecs, vcd2->codecs());
4387}
4388
Zhi Huang6f367472017-11-22 13:20:02 -08004389// Test that when creating an answer, the codecs use local parameters instead of
4390// the remote ones.
4391TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4392 const std::string audio_param_name = "audio_param";
4393 const std::string audio_value1 = "audio_v1";
4394 const std::string audio_value2 = "audio_v2";
4395 const std::string video_param_name = "video_param";
4396 const std::string video_value1 = "video_v1";
4397 const std::string video_value2 = "video_v2";
4398
4399 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4400 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4401 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4402 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4403
4404 // Set the parameters for codecs.
4405 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4406 video_codecs1[0].SetParam(video_param_name, video_value1);
4407 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4408 video_codecs2[0].SetParam(video_param_name, video_value2);
4409
4410 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004411 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004412 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004413 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004414
4415 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004416 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4417 RtpTransceiverDirection::kSendRecv, kActive,
4418 &opts);
4419 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4420 RtpTransceiverDirection::kSendRecv, kActive,
4421 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004422
Steve Anton6fe1fba2018-12-11 10:15:23 -08004423 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004424 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004425 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4426 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004427 std::string value;
4428 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4429 EXPECT_EQ(audio_value1, value);
4430 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4431 EXPECT_EQ(video_value1, value);
4432
Steve Anton6fe1fba2018-12-11 10:15:23 -08004433 std::unique_ptr<SessionDescription> answer =
4434 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004435 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004436 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4437 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004438 // Use the parameters from the local codecs.
4439 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4440 EXPECT_EQ(audio_value2, value);
4441 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4442 EXPECT_EQ(video_value2, value);
4443}
4444
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004445// Test that matching packetization-mode is part of the criteria for matching
4446// H264 codecs (in addition to profile-level-id). Previously, this was not the
4447// case, so the first H264 codec with the same profile-level-id would match and
4448// the payload type in the answer would be incorrect.
4449// This is a regression test for bugs.webrtc.org/8808
4450TEST_F(MediaSessionDescriptionFactoryTest,
4451 H264MatchCriteriaIncludesPacketizationMode) {
4452 // Create two H264 codecs with the same profile level ID and different
4453 // packetization modes.
4454 VideoCodec h264_pm0(96, "H264");
4455 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4456 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4457 VideoCodec h264_pm1(97, "H264");
4458 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4459 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4460
4461 // Offerer will send both codecs, answerer should choose the one with matching
4462 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004463 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4464 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004465
4466 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004467 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4468 RtpTransceiverDirection::kSendRecv, kActive,
4469 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004470
Steve Anton6fe1fba2018-12-11 10:15:23 -08004471 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004472 ASSERT_TRUE(offer);
4473
Steve Anton6fe1fba2018-12-11 10:15:23 -08004474 std::unique_ptr<SessionDescription> answer =
4475 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004476 ASSERT_TRUE(answer);
4477
4478 // Answer should have one negotiated codec with packetization-mode=1 using the
4479 // offered payload type.
4480 ASSERT_EQ(1u, answer->contents().size());
4481 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4482 ASSERT_EQ(1u, answer_vcd->codecs().size());
4483 auto answer_codec = answer_vcd->codecs()[0];
4484 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4485}
4486
zhihuangcf5b37c2016-05-05 11:44:35 -07004487class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4488 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004489 MediaProtocolTest()
4490 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004491 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4492 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004493 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4494 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004495 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004496 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4497 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004498 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4499 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004500 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004501 f1_.set_secure(SEC_ENABLED);
4502 f2_.set_secure(SEC_ENABLED);
4503 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004504 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004505 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004506 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004507 tdf1_.set_secure(SEC_ENABLED);
4508 tdf2_.set_secure(SEC_ENABLED);
4509 }
4510
4511 protected:
4512 MediaSessionDescriptionFactory f1_;
4513 MediaSessionDescriptionFactory f2_;
4514 TransportDescriptionFactory tdf1_;
4515 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004516 UniqueRandomIdGenerator ssrc_generator1;
4517 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004518};
4519
4520TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4521 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004522 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004523 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004524 ASSERT_TRUE(offer.get() != nullptr);
4525 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004526 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004527 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004528 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004529 std::unique_ptr<SessionDescription> answer =
4530 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004531 const ContentInfo* ac = answer->GetContentByName("audio");
4532 const ContentInfo* vc = answer->GetContentByName("video");
4533 ASSERT_TRUE(ac != nullptr);
4534 ASSERT_TRUE(vc != nullptr);
4535 EXPECT_FALSE(ac->rejected); // the offer is accepted
4536 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004537 const AudioContentDescription* acd = ac->media_description()->as_audio();
4538 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004539 EXPECT_EQ(GetParam(), acd->protocol());
4540 EXPECT_EQ(GetParam(), vcd->protocol());
4541}
4542
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004543INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4544 MediaProtocolTest,
4545 ::testing::ValuesIn(kMediaProtocols));
4546INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4547 MediaProtocolTest,
4548 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004549
4550TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4551 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004552 UniqueRandomIdGenerator ssrc_generator;
4553 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004554 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4555 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4556
4557 // The merged list of codecs should contain any send codecs that are also
4558 // nominally in the recieve codecs list. Payload types should be picked from
4559 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4560 // (set to 1). This equals what happens when the send codecs are used in an
4561 // offer and the receive codecs are used in the following answer.
4562 const std::vector<AudioCodec> sendrecv_codecs =
4563 MAKE_VECTOR(kAudioCodecsAnswer);
4564 const std::vector<AudioCodec> no_codecs;
4565
4566 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4567 << "Please don't change shared test data!";
4568 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4569 << "Please don't change shared test data!";
4570 // Alter iLBC send codec to have zero channels, to test that that is handled
4571 // properly.
4572 send_codecs[1].channels = 0;
4573
4574 // Alther iLBC receive codec to be lowercase, to test that case conversions
4575 // are handled properly.
4576 recv_codecs[2].name = "ilbc";
4577
4578 // Test proper merge
4579 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004580 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4581 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4582 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004583
4584 // Test empty send codecs list
4585 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004586 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4587 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4588 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004589
4590 // Test empty recv codecs list
4591 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004592 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4593 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4594 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004595
4596 // Test all empty codec lists
4597 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004598 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4599 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4600 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004601}
4602
4603namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004604// Compare the two vectors of codecs ignoring the payload type.
4605template <class Codec>
4606bool CodecsMatch(const std::vector<Codec>& codecs1,
4607 const std::vector<Codec>& codecs2) {
4608 if (codecs1.size() != codecs2.size()) {
4609 return false;
4610 }
4611
4612 for (size_t i = 0; i < codecs1.size(); ++i) {
4613 if (!codecs1[i].Matches(codecs2[i])) {
4614 return false;
4615 }
4616 }
4617 return true;
4618}
4619
Steve Anton4e70a722017-11-28 14:57:10 -08004620void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004621 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004622 UniqueRandomIdGenerator ssrc_generator;
4623 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004624 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4625 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4626 const std::vector<AudioCodec> sendrecv_codecs =
4627 MAKE_VECTOR(kAudioCodecsAnswer);
4628 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004629
4630 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004631 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4632 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004633
Steve Anton4e70a722017-11-28 14:57:10 -08004634 if (direction == RtpTransceiverDirection::kSendRecv ||
4635 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004636 AttachSenderToMediaDescriptionOptions(
4637 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004638 }
ossu075af922016-06-14 03:29:38 -07004639
Steve Anton6fe1fba2018-12-11 10:15:23 -08004640 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004641 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004642 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004643
4644 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004645 // that the codecs put in are right. This happens when we neither want to
4646 // send nor receive audio. The checks are still in place if at some point
4647 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004648 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004649 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004650 // sendrecv and inactive should both present lists as if the channel was
4651 // to be used for sending and receiving. Inactive essentially means it
4652 // might eventually be used anything, but we don't know more at this
4653 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004654 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004655 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004656 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004657 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004658 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004659 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004660 }
4661 }
4662}
4663
4664static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004665 AudioCodec(0, "codec0", 16000, -1, 1),
4666 AudioCodec(1, "codec1", 8000, 13300, 1),
4667 AudioCodec(2, "codec2", 8000, 64000, 1),
4668 AudioCodec(3, "codec3", 8000, 64000, 1),
4669 AudioCodec(4, "codec4", 8000, 0, 2),
4670 AudioCodec(5, "codec5", 32000, 0, 1),
4671 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004672
zhihuang1c378ed2017-08-17 14:10:50 -07004673/* The codecs groups below are chosen as per the matrix below. The objective
4674 * is to have different sets of codecs in the inputs, to get unique sets of
4675 * codecs after negotiation, depending on offer and answer communication
4676 * directions. One-way directions in the offer should either result in the
4677 * opposite direction in the answer, or an inactive answer. Regardless, the
4678 * choice of codecs should be as if the answer contained the opposite
4679 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004680 *
4681 * | Offer | Answer | Result
4682 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4683 * 0 | x - - | - x - | x - - - -
4684 * 1 | x x x | - x - | x - - x -
4685 * 2 | - x - | x - - | - x - - -
4686 * 3 | x x x | x - - | - x x - -
4687 * 4 | - x - | x x x | - x - - -
4688 * 5 | x - - | x x x | x - - - -
4689 * 6 | x x x | x x x | x x x x x
4690 */
4691// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004692static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4693static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004694// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4695// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004696static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4697static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004698// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004699static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4700static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4701static const int kResultSendrecv_SendCodecs[] = {3, 6};
4702static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4703static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004704
4705template <typename T, int IDXS>
4706std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4707 std::vector<T> out;
4708 out.reserve(IDXS);
4709 for (int idx : indices)
4710 out.push_back(array[idx]);
4711
4712 return out;
4713}
4714
Steve Anton4e70a722017-11-28 14:57:10 -08004715void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4716 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004717 bool add_legacy_stream) {
4718 TransportDescriptionFactory offer_tdf;
4719 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004720 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4721 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4722 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004723 offer_factory.set_audio_codecs(
4724 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4725 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4726 answer_factory.set_audio_codecs(
4727 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4728 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4729
ossu075af922016-06-14 03:29:38 -07004730 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004731 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4732 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004733
Steve Anton4e70a722017-11-28 14:57:10 -08004734 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004735 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4736 kAudioTrack1, {kMediaStream1}, 1,
4737 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004738 }
4739
Steve Anton6fe1fba2018-12-11 10:15:23 -08004740 std::unique_ptr<SessionDescription> offer =
4741 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004742 ASSERT_TRUE(offer.get() != NULL);
4743
4744 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004745 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4746 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004747
Steve Anton4e70a722017-11-28 14:57:10 -08004748 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004749 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4750 kAudioTrack1, {kMediaStream1}, 1,
4751 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004752 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004753 std::unique_ptr<SessionDescription> answer =
4754 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004755 const ContentInfo* ac = answer->GetContentByName("audio");
4756
zhihuang1c378ed2017-08-17 14:10:50 -07004757 // If the factory didn't add any audio content to the answer, we cannot
4758 // check that the codecs put in are right. This happens when we neither want
4759 // to send nor receive audio. The checks are still in place if at some point
4760 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004761 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004762 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4763 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004764
ossu075af922016-06-14 03:29:38 -07004765 std::vector<AudioCodec> target_codecs;
4766 // For offers with sendrecv or inactive, we should never reply with more
4767 // codecs than offered, with these codec sets.
4768 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004769 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004770 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4771 kResultSendrecv_SendrecvCodecs);
4772 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004773 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004774 target_codecs =
4775 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004776 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004777 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004778 target_codecs =
4779 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004780 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004781 case RtpTransceiverDirection::kSendRecv:
4782 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004783 target_codecs =
4784 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004785 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004786 target_codecs =
4787 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004788 } else {
4789 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4790 kResultSendrecv_SendrecvCodecs);
4791 }
4792 break;
Markus Handell45c104b2020-03-11 10:51:13 +01004793 default:
4794 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004795 }
4796
zhihuang1c378ed2017-08-17 14:10:50 -07004797 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004798 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004799 bool first = true;
4800 os << "{";
4801 for (const auto& c : codecs) {
4802 os << (first ? " " : ", ") << c.id;
4803 first = false;
4804 }
4805 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004806 return os.Release();
ossu075af922016-06-14 03:29:38 -07004807 };
4808
4809 EXPECT_TRUE(acd->codecs() == target_codecs)
4810 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004811 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4812 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004813 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004814 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4815 << "; got: "
4816 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004817 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004818 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004819 << "Only inactive offers are allowed to not generate any audio "
4820 "content";
ossu075af922016-06-14 03:29:38 -07004821 }
4822}
brandtr03d5fb12016-11-22 03:37:59 -08004823
4824} // namespace
ossu075af922016-06-14 03:29:38 -07004825
4826class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004827 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004828
4829TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004830 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004831}
4832
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004833INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4834 AudioCodecsOfferTest,
4835 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4836 RtpTransceiverDirection::kRecvOnly,
4837 RtpTransceiverDirection::kSendRecv,
4838 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004839
4840class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004841 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4842 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004843 bool>> {};
ossu075af922016-06-14 03:29:38 -07004844
4845TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004846 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4847 ::testing::get<1>(GetParam()),
4848 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004849}
4850
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004851INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004852 MediaSessionDescriptionFactoryTest,
4853 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004854 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4855 RtpTransceiverDirection::kRecvOnly,
4856 RtpTransceiverDirection::kSendRecv,
4857 RtpTransceiverDirection::kInactive),
4858 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4859 RtpTransceiverDirection::kRecvOnly,
4860 RtpTransceiverDirection::kSendRecv,
4861 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004862 ::testing::Bool()));