blob: ffc4a6f430ed14764c89578851cd40fb8759bf02 [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 Bonadei92ea95e2017-09-15 06:47:31 +020021#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020023#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "p2p/base/p2p_constants.h"
25#include "p2p/base/transport_description.h"
26#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "pc/rtp_media_utils.h"
28#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "rtc_base/message_digest.h"
33#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020034#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080035#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080036#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
Yves Gerey665174f2018-06-19 15:03:05 +020038#define ASSERT_CRYPTO(cd, s, cs) \
39 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080040 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041
42typedef std::vector<cricket::Candidate> Candidates;
43
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080044using cricket::AudioCodec;
45using cricket::AudioContentDescription;
46using cricket::ContentInfo;
47using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080048using cricket::GetFirstAudioContent;
49using cricket::GetFirstAudioContentDescription;
50using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020051using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080052using cricket::GetFirstVideoContent;
53using cricket::GetFirstVideoContentDescription;
54using cricket::kAutoBandwidth;
55using cricket::MEDIA_TYPE_AUDIO;
56using cricket::MEDIA_TYPE_DATA;
57using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070059using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080060using cricket::MediaProtocolType;
61using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062using cricket::MediaSessionOptions;
63using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080064using cricket::RidDescription;
65using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020066using cricket::RtpDataCodec;
67using cricket::RtpDataContentDescription;
68using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080069using cricket::SEC_DISABLED;
70using cricket::SEC_ENABLED;
71using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080073using cricket::SimulcastDescription;
74using cricket::SimulcastLayer;
75using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076using cricket::SsrcGroup;
77using cricket::StreamParams;
78using cricket::StreamParamsVec;
79using cricket::TransportDescription;
80using cricket::TransportDescriptionFactory;
81using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080083using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070084using rtc::CS_AEAD_AES_128_GCM;
85using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080086using rtc::CS_AES_CM_128_HMAC_SHA1_32;
87using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080088using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020089using ::testing::Contains;
90using ::testing::Each;
Danil Chapovalov5f999a72020-02-20 16:39:05 +010091using ::testing::ElementsAre;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020092using ::testing::ElementsAreArray;
93using ::testing::Eq;
94using ::testing::Field;
95using ::testing::IsEmpty;
96using ::testing::IsFalse;
97using ::testing::Ne;
98using ::testing::Not;
99using ::testing::Pointwise;
100using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700101using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800102using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
104static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700105 AudioCodec(103, "ISAC", 16000, -1, 1),
106 AudioCodec(102, "iLBC", 8000, 13300, 1),
107 AudioCodec(0, "PCMU", 8000, 64000, 1),
108 AudioCodec(8, "PCMA", 8000, 64000, 1),
109 AudioCodec(117, "red", 8000, 0, 1),
110 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
112static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200113 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700114 AudioCodec(0, "PCMU", 8000, 64000, 1),
115 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116};
117
118static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700119 AudioCodec(102, "iLBC", 8000, 13300, 1),
120 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121};
122
perkj26752742016-10-24 01:21:16 -0700123static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
124 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125
zhihuang1c378ed2017-08-17 14:10:50 -0700126static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
127 VideoCodec(96, "H264-SVC")};
128
perkj26752742016-10-24 01:21:16 -0700129static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
130 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
perkj26752742016-10-24 01:21:16 -0700132static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200134static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
135 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200137static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
138 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200140static const RtpDataCodec kDataCodecsAnswer[] = {
141 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142
isheriff6f8d6862016-05-26 11:24:55 -0700143static const RtpExtension kAudioRtpExtension1[] = {
144 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
145 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146};
147
jbauch5869f502017-06-29 12:31:36 -0700148static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
149 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
150 RtpExtension("http://google.com/testing/audio_something", 10),
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
152};
153
isheriff6f8d6862016-05-26 11:24:55 -0700154static const RtpExtension kAudioRtpExtension2[] = {
155 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
156 RtpExtension("http://google.com/testing/audio_something_else", 8),
157 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000158};
159
isheriff6f8d6862016-05-26 11:24:55 -0700160static const RtpExtension kAudioRtpExtension3[] = {
161 RtpExtension("http://google.com/testing/audio_something", 2),
162 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700163};
164
jbauch5869f502017-06-29 12:31:36 -0700165static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
166 RtpExtension("http://google.com/testing/audio_something", 2),
167 // Use RTP extension that supports encryption.
168 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
169};
170
171static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
172 RtpExtension("http://google.com/testing/audio_something", 2),
173 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
175};
176
isheriff6f8d6862016-05-26 11:24:55 -0700177static const RtpExtension kAudioRtpExtensionAnswer[] = {
178 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179};
180
jbauch5869f502017-06-29 12:31:36 -0700181static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
182 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
183};
184
isheriff6f8d6862016-05-26 11:24:55 -0700185static const RtpExtension kVideoRtpExtension1[] = {
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
187 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188};
189
jbauch5869f502017-06-29 12:31:36 -0700190static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
192 RtpExtension("http://google.com/testing/video_something", 13),
193 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
194};
195
isheriff6f8d6862016-05-26 11:24:55 -0700196static const RtpExtension kVideoRtpExtension2[] = {
197 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
198 RtpExtension("http://google.com/testing/video_something_else", 14),
199 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200};
201
isheriff6f8d6862016-05-26 11:24:55 -0700202static const RtpExtension kVideoRtpExtension3[] = {
203 RtpExtension("http://google.com/testing/video_something", 4),
204 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700205};
206
jbauch5869f502017-06-29 12:31:36 -0700207static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
208 RtpExtension("http://google.com/testing/video_something", 4),
209 // Use RTP extension that supports encryption.
210 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
211};
212
isheriff6f8d6862016-05-26 11:24:55 -0700213static const RtpExtension kVideoRtpExtensionAnswer[] = {
214 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215};
216
jbauch5869f502017-06-29 12:31:36 -0700217static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
218 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
219};
220
Johannes Kronce8e8672019-02-22 13:06:44 +0100221static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
222 RtpExtension("http://www.ietf.org/id/"
223 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
224 1),
225};
226
227static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
228 RtpExtension("http://www.ietf.org/id/"
229 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
230 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100231 RtpExtension(
232 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
233 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100234};
235
236static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100237 RtpExtension(
238 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
239 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100240};
241
Markus Handellc1cbf6b2020-02-17 20:03:57 +0100242static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
243 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
244 "generic-frame-descriptor-00",
245 3),
246};
247
Peter Boström0c4e06b2015-10-07 12:23:21 +0200248static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
249static const uint32_t kSimSsrc[] = {10, 20, 30};
250static const uint32_t kFec1Ssrc[] = {10, 11};
251static const uint32_t kFec2Ssrc[] = {20, 21};
252static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253
254static const char kMediaStream1[] = "stream_1";
255static const char kMediaStream2[] = "stream_2";
256static const char kVideoTrack1[] = "video_1";
257static const char kVideoTrack2[] = "video_2";
258static const char kAudioTrack1[] = "audio_1";
259static const char kAudioTrack2[] = "audio_2";
260static const char kAudioTrack3[] = "audio_3";
261static const char kDataTrack1[] = "data_1";
262static const char kDataTrack2[] = "data_2";
263static const char kDataTrack3[] = "data_3";
264
zhihuangcf5b37c2016-05-05 11:44:35 -0700265static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
266 "RTP/SAVPF"};
267static const char* kMediaProtocolsDtls[] = {
268 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
269 "UDP/TLS/RTP/SAVP"};
270
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700271// SRTP cipher name negotiated by the tests. This must be updated if the
272// default changes.
273static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
274static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
275
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800276// These constants are used to make the code using "AddMediaDescriptionOptions"
277// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700278static constexpr bool kStopped = true;
279static constexpr bool kActive = false;
280
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000281static bool IsMediaContentOfType(const ContentInfo* content,
282 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800283 RTC_DCHECK(content);
284 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000285}
286
Steve Anton4e70a722017-11-28 14:57:10 -0800287static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800288 RTC_DCHECK(content);
289 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000290}
291
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000292static void AddRtxCodec(const VideoCodec& rtx_codec,
293 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800294 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000295 codecs->push_back(rtx_codec);
296}
297
298template <class T>
299static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
300 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100301 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000302 for (const auto& codec : codecs) {
303 codec_names.push_back(codec.name);
304 }
305 return codec_names;
306}
307
zhihuang1c378ed2017-08-17 14:10:50 -0700308// This is used for test only. MIDs are not the identification of the
309// MediaDescriptionOptions since some end points may not support MID and the SDP
310// may not contain 'mid'.
311std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
312 const std::string& mid,
313 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800314 return absl::c_find_if(
315 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700316 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
317}
318
319std::vector<MediaDescriptionOptions>::const_iterator
320FindFirstMediaDescriptionByMid(const std::string& mid,
321 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800322 return absl::c_find_if(
323 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700324 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700325}
326
327// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800328static void AddMediaDescriptionOptions(MediaType type,
329 const std::string& mid,
330 RtpTransceiverDirection direction,
331 bool stopped,
332 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800333 opts->media_description_options.push_back(
334 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700335}
336
Steve Anton4e70a722017-11-28 14:57:10 -0800337static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700338 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800339 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
340 opts);
341 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
342 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700343}
344
345static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800346 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700347 MediaSessionOptions* opts) {
348 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800349 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700350}
351
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800352static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700353 const std::string& mid,
354 MediaType type,
355 const std::string& track_id,
356 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800357 const std::vector<RidDescription>& rids,
358 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700359 int num_sim_layer,
360 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700361 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
362 switch (type) {
363 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700364 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700365 break;
366 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800367 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
368 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700369 break;
370 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700371 RTC_CHECK(stream_ids.size() == 1U);
372 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700373 break;
374 default:
375 RTC_NOTREACHED();
376 }
377}
378
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800379static void AttachSenderToMediaDescriptionOptions(
380 const std::string& mid,
381 MediaType type,
382 const std::string& track_id,
383 const std::vector<std::string>& stream_ids,
384 int num_sim_layer,
385 MediaSessionOptions* session_options) {
386 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
387 SimulcastLayerList(), num_sim_layer,
388 session_options);
389}
390
zhihuang1c378ed2017-08-17 14:10:50 -0700391static void DetachSenderFromMediaSection(const std::string& mid,
392 const std::string& track_id,
393 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700394 std::vector<cricket::SenderOptions>& sender_options_list =
395 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
396 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800397 absl::c_find_if(sender_options_list,
398 [track_id](const cricket::SenderOptions& sender_options) {
399 return sender_options.track_id == track_id;
400 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700401 RTC_DCHECK(sender_it != sender_options_list.end());
402 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700403}
404
405// Helper function used to create a default MediaSessionOptions for Plan B SDP.
406// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
407static MediaSessionOptions CreatePlanBMediaSessionOptions() {
408 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800409 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
410 RtpTransceiverDirection::kRecvOnly, kActive,
411 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700412 return session_options;
413}
414
415// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
416// was designed for Plan B SDP, where only one audio "m=" section and one video
417// "m=" section could be generated, and ordering couldn't be controlled. Many of
418// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200419class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800421 MediaSessionDescriptionFactoryTest()
422 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700423 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
424 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +0200425 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
426 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200427 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700428 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
429 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +0200430 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
431 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200432 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200433 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700434 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200435 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700436 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437 }
438
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000439 // Create a video StreamParamsVec object with:
440 // - one video stream with 3 simulcast streams and FEC,
441 StreamParamsVec CreateComplexVideoStreamParamsVec() {
442 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
443 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
444 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
445 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
446
447 std::vector<SsrcGroup> ssrc_groups;
448 ssrc_groups.push_back(sim_group);
449 ssrc_groups.push_back(fec_group1);
450 ssrc_groups.push_back(fec_group2);
451 ssrc_groups.push_back(fec_group3);
452
453 StreamParams simulcast_params;
454 simulcast_params.id = kVideoTrack1;
455 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
456 simulcast_params.ssrc_groups = ssrc_groups;
457 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800458 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000459
460 StreamParamsVec video_streams;
461 video_streams.push_back(simulcast_params);
462
463 return video_streams;
464 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465
466 bool CompareCryptoParams(const CryptoParamsVec& c1,
467 const CryptoParamsVec& c2) {
468 if (c1.size() != c2.size())
469 return false;
470 for (size_t i = 0; i < c1.size(); ++i)
471 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
472 c1[i].key_params != c2[i].key_params ||
473 c1[i].session_params != c2[i].session_params)
474 return false;
475 return true;
476 }
477
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700478 // Returns true if the transport info contains "renomination" as an
479 // ICE option.
480 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800481 return absl::c_linear_search(transport_info->description.transport_options,
482 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700483 }
484
zhihuang1c378ed2017-08-17 14:10:50 -0700485 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700486 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000487 bool has_current_desc) {
488 const std::string current_audio_ufrag = "current_audio_ufrag";
489 const std::string current_audio_pwd = "current_audio_pwd";
490 const std::string current_video_ufrag = "current_video_ufrag";
491 const std::string current_video_pwd = "current_video_pwd";
492 const std::string current_data_ufrag = "current_data_ufrag";
493 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800494 std::unique_ptr<SessionDescription> current_desc;
495 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200497 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800498 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200499 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800500 TransportDescription(current_audio_ufrag, current_audio_pwd)));
501 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200502 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800503 TransportDescription(current_video_ufrag, current_video_pwd)));
504 current_desc->AddTransportInfo(TransportInfo(
505 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 }
507 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800508 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 } else {
kwiberg31022942016-03-11 14:18:21 -0800510 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800511 offer = f1_.CreateOffer(options, NULL);
512 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513 }
514 ASSERT_TRUE(desc.get() != NULL);
515 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000516 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 EXPECT_TRUE(ti_audio != NULL);
518 if (has_current_desc) {
519 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
520 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
521 } else {
522 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
523 ti_audio->description.ice_ufrag.size());
524 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
525 ti_audio->description.ice_pwd.size());
526 }
zhihuang1c378ed2017-08-17 14:10:50 -0700527 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700528 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700529 EXPECT_EQ(
530 media_desc_options_it->transport_options.enable_ice_renomination,
531 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700532 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
533 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534
535 } else {
536 EXPECT_TRUE(ti_audio == NULL);
537 }
538 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000539 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700541 auto media_desc_options_it =
542 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 if (options.bundle_enabled) {
544 EXPECT_EQ(ti_audio->description.ice_ufrag,
545 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200546 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700547 EXPECT_EQ(ti_audio->description.opaque_parameters,
548 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 } else {
550 if (has_current_desc) {
551 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
552 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
553 } else {
554 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
555 ti_video->description.ice_ufrag.size());
556 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
557 ti_video->description.ice_pwd.size());
558 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700559 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
560 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 }
zhihuang1c378ed2017-08-17 14:10:50 -0700562 EXPECT_EQ(
563 media_desc_options_it->transport_options.enable_ice_renomination,
564 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 } else {
566 EXPECT_TRUE(ti_video == NULL);
567 }
568 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
569 if (options.has_data()) {
570 EXPECT_TRUE(ti_data != NULL);
571 if (options.bundle_enabled) {
572 EXPECT_EQ(ti_audio->description.ice_ufrag,
573 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200574 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 } else {
576 if (has_current_desc) {
577 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
578 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
579 } else {
580 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
581 ti_data->description.ice_ufrag.size());
582 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
583 ti_data->description.ice_pwd.size());
584 }
585 }
zhihuang1c378ed2017-08-17 14:10:50 -0700586 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700587 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700588 EXPECT_EQ(
589 media_desc_options_it->transport_options.enable_ice_renomination,
590 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700591
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700593 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 }
595 }
596
597 void TestCryptoWithBundle(bool offer) {
598 f1_.set_secure(SEC_ENABLED);
599 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800600 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
601 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
602 &options);
kwiberg31022942016-03-11 14:18:21 -0800603 std::unique_ptr<SessionDescription> ref_desc;
604 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 if (offer) {
606 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800607 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800609 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610 } else {
611 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800612 ref_desc = f1_.CreateOffer(options, NULL);
613 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800615 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800617 desc->GetContentDescriptionByName("audio");
618 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800620 desc->GetContentDescriptionByName("video");
621 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
623 video_media_desc->cryptos()));
624 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800625 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 audio_media_desc->cryptos()[0].cipher_suite);
627
628 // Verify the selected crypto is one from the reference audio
629 // media content.
630 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800631 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 bool found = false;
633 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
634 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200635 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 found = true;
637 break;
638 }
639 }
640 EXPECT_TRUE(found);
641 }
642
643 // This test that the audio and video media direction is set to
644 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700645 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800647 RtpTransceiverDirection direction_in_offer,
648 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700649 MediaSessionOptions offer_opts;
650 AddAudioVideoSections(direction_in_offer, &offer_opts);
651
Steve Anton6fe1fba2018-12-11 10:15:23 -0800652 std::unique_ptr<SessionDescription> offer =
653 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700655 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700657 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659
zhihuang1c378ed2017-08-17 14:10:50 -0700660 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800661 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800662 std::unique_ptr<SessionDescription> answer =
663 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 const AudioContentDescription* acd_answer =
665 GetFirstAudioContentDescription(answer.get());
666 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
667 const VideoContentDescription* vcd_answer =
668 GetFirstVideoContentDescription(answer.get());
669 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
670 }
671
672 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800673 RTC_DCHECK(content);
674 RTC_CHECK(content->media_description());
675 const cricket::AudioContentDescription* audio_desc =
676 content->media_description()->as_audio();
677 RTC_CHECK(audio_desc);
678 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
679 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800681 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000682 }
683 return true;
684 }
685
jbauchcb560652016-08-04 05:20:32 -0700686 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
687 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800688 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700689 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700690
jbauchcb560652016-08-04 05:20:32 -0700691 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800692 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700693 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700694
jbauchcb560652016-08-04 05:20:32 -0700695 f1_.set_secure(SEC_ENABLED);
696 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800697 std::unique_ptr<SessionDescription> offer =
698 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700699 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800700 std::unique_ptr<SessionDescription> answer =
701 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700702 const ContentInfo* ac = answer->GetContentByName("audio");
703 const ContentInfo* vc = answer->GetContentByName("video");
704 ASSERT_TRUE(ac != NULL);
705 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800706 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
707 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800708 const AudioContentDescription* acd = ac->media_description()->as_audio();
709 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700710 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800711 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700712 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700713 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700714 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
715 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700716 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700717 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700718 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700719 }
720 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800721 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200722 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
723 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700724 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700725 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700726 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700727 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700728 }
Steve Antone38a5a12018-11-21 16:05:15 -0800729 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700730 }
731
Johannes Kronce8e8672019-02-22 13:06:44 +0100732 void TestTransportSequenceNumberNegotiation(
733 const cricket::RtpHeaderExtensions& local,
734 const cricket::RtpHeaderExtensions& offered,
735 const cricket::RtpHeaderExtensions& expectedAnswer) {
736 MediaSessionOptions opts;
737 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
738 f1_.set_audio_rtp_header_extensions(offered);
739 f1_.set_video_rtp_header_extensions(offered);
740 f2_.set_audio_rtp_header_extensions(local);
741 f2_.set_video_rtp_header_extensions(local);
742
743 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
744 ASSERT_TRUE(offer.get() != NULL);
745 std::unique_ptr<SessionDescription> answer =
746 f2_.CreateAnswer(offer.get(), opts, NULL);
747
748 EXPECT_EQ(
749 expectedAnswer,
750 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
751 EXPECT_EQ(
752 expectedAnswer,
753 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
754 }
755
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000756 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800757 UniqueRandomIdGenerator ssrc_generator1;
758 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 MediaSessionDescriptionFactory f1_;
760 MediaSessionDescriptionFactory f2_;
761 TransportDescriptionFactory tdf1_;
762 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763};
764
765// Create a typical audio offer, and ensure it matches what we expect.
766TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
767 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800768 std::unique_ptr<SessionDescription> offer =
769 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 ASSERT_TRUE(offer.get() != NULL);
771 const ContentInfo* ac = offer->GetContentByName("audio");
772 const ContentInfo* vc = offer->GetContentByName("video");
773 ASSERT_TRUE(ac != NULL);
774 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800775 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800776 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700778 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700779 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000780 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
781 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700782 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800783 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000784}
785
786// Create a typical video offer, and ensure it matches what we expect.
787TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
788 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800789 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800791 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792 ASSERT_TRUE(offer.get() != NULL);
793 const ContentInfo* ac = offer->GetContentByName("audio");
794 const ContentInfo* vc = offer->GetContentByName("video");
795 ASSERT_TRUE(ac != NULL);
796 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800797 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
798 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800799 const AudioContentDescription* acd = ac->media_description()->as_audio();
800 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700802 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700803 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
805 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700806 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800807 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +0200809 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700810 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
812 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700813 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800814 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815}
816
817// Test creating an offer with bundle where the Codecs have the same dynamic
818// RTP playlod type. The test verifies that the offer don't contain the
819// duplicate RTP payload types.
820TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron3e983682020-03-29 22:17:00 +0200821 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700822 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200823 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000824 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
825 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
826
827 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800828 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
829 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800831 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832 const VideoContentDescription* vcd =
833 GetFirstVideoContentDescription(offer.get());
834 const AudioContentDescription* acd =
835 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200836 const RtpDataContentDescription* dcd =
837 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 ASSERT_TRUE(NULL != vcd);
839 ASSERT_TRUE(NULL != acd);
840 ASSERT_TRUE(NULL != dcd);
841 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
842 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
843 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
844 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
845 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
846 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
847}
848
zhihuang1c378ed2017-08-17 14:10:50 -0700849// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850// after an audio only session has been negotiated.
851TEST_F(MediaSessionDescriptionFactoryTest,
852 TestCreateUpdatedVideoOfferWithBundle) {
853 f1_.set_secure(SEC_ENABLED);
854 f2_.set_secure(SEC_ENABLED);
855 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800856 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
857 RtpTransceiverDirection::kRecvOnly, kActive,
858 &opts);
859 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
860 RtpTransceiverDirection::kInactive, kStopped,
861 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 opts.data_channel_type = cricket::DCT_NONE;
863 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800864 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
865 std::unique_ptr<SessionDescription> answer =
866 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867
868 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800869 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
870 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
871 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800873 std::unique_ptr<SessionDescription> updated_offer(
874 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000875
876 const AudioContentDescription* acd =
877 GetFirstAudioContentDescription(updated_offer.get());
878 const VideoContentDescription* vcd =
879 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200880 const RtpDataContentDescription* dcd =
881 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882 EXPECT_TRUE(NULL != vcd);
883 EXPECT_TRUE(NULL != acd);
884 EXPECT_TRUE(NULL != dcd);
885
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700886 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800887 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700888 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800889 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700890 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800891 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892}
deadbeef44f08192015-12-15 16:20:09 -0800893
wu@webrtc.org78187522013-10-07 23:32:02 +0000894// Create a RTP data offer, and ensure it matches what we expect.
895TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800897 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
898 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800900 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 ASSERT_TRUE(offer.get() != NULL);
902 const ContentInfo* ac = offer->GetContentByName("audio");
903 const ContentInfo* dc = offer->GetContentByName("data");
904 ASSERT_TRUE(ac != NULL);
905 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800906 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
907 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800908 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200909 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000910 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700911 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700912 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000913 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
914 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700915 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800916 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000917 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200918 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700919 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000920 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200921 dcd->bandwidth()); // default bandwidth (auto)
922 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700923 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800924 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000925}
926
wu@webrtc.org78187522013-10-07 23:32:02 +0000927// Create an SCTP data offer with bundle without error.
928TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
929 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000930 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800931 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000932 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800933 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000934 EXPECT_TRUE(offer.get() != NULL);
935 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000936 auto dcd = GetFirstSctpDataContentDescription(offer.get());
937 ASSERT_TRUE(dcd);
938 // Since this transport is insecure, the protocol should be "SCTP".
939 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
940}
941
942// Create an SCTP data offer with bundle without error.
943TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
944 MediaSessionOptions opts;
945 opts.bundle_enabled = true;
946 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
947 f1_.set_secure(SEC_ENABLED);
948 tdf1_.set_secure(SEC_ENABLED);
949 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
950 EXPECT_TRUE(offer.get() != NULL);
951 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
952 auto dcd = GetFirstSctpDataContentDescription(offer.get());
953 ASSERT_TRUE(dcd);
954 // The protocol should now be "UDP/DTLS/SCTP"
955 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000956}
957
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000958// Test creating an sctp data channel from an already generated offer.
959TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
960 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000961 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800962 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000963 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800964 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000965 ASSERT_TRUE(offer1.get() != NULL);
966 const ContentInfo* data = offer1->GetContentByName("data");
967 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800968 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000969
970 // Now set data_channel_type to 'none' (default) and make sure that the
971 // datachannel type that gets generated from the previous offer, is of the
972 // same type.
973 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800974 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000975 f1_.CreateOffer(opts, offer1.get()));
976 data = offer2->GetContentByName("data");
977 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800978 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000979}
980
Steve Anton2bed3972019-01-04 17:04:30 -0800981// Test that if BUNDLE is enabled and all media sections are rejected then the
982// BUNDLE group is not present in the re-offer.
983TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
984 MediaSessionOptions opts;
985 opts.bundle_enabled = true;
986 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
987 RtpTransceiverDirection::kSendRecv, kActive,
988 &opts);
989 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
990
991 opts.media_description_options[0].stopped = true;
992 std::unique_ptr<SessionDescription> reoffer =
993 f1_.CreateOffer(opts, offer.get());
994
995 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
996}
997
998// Test that if BUNDLE is enabled and the remote re-offer does not include a
999// BUNDLE group since all media sections are rejected, then the re-answer also
1000// does not include a BUNDLE group.
1001TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
1002 MediaSessionOptions opts;
1003 opts.bundle_enabled = true;
1004 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1005 RtpTransceiverDirection::kSendRecv, kActive,
1006 &opts);
1007 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1008 std::unique_ptr<SessionDescription> answer =
1009 f2_.CreateAnswer(offer.get(), opts, nullptr);
1010
1011 opts.media_description_options[0].stopped = true;
1012 std::unique_ptr<SessionDescription> reoffer =
1013 f1_.CreateOffer(opts, offer.get());
1014 std::unique_ptr<SessionDescription> reanswer =
1015 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1016
1017 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1018}
1019
1020// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1021// was rejected then the new offerer-tagged media section is the non-rejected
1022// media section.
1023TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1024 MediaSessionOptions opts;
1025 opts.bundle_enabled = true;
1026 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1027 RtpTransceiverDirection::kSendRecv, kActive,
1028 &opts);
1029 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1030
1031 // Reject the audio m= section and add a video m= section.
1032 opts.media_description_options[0].stopped = true;
1033 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1034 RtpTransceiverDirection::kSendRecv, kActive,
1035 &opts);
1036 std::unique_ptr<SessionDescription> reoffer =
1037 f1_.CreateOffer(opts, offer.get());
1038
1039 const cricket::ContentGroup* bundle_group =
1040 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1041 ASSERT_TRUE(bundle_group);
1042 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1043 EXPECT_TRUE(bundle_group->HasContentName("video"));
1044}
1045
1046// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1047// was rejected and a new media section is added, then the re-answer BUNDLE
1048// group will contain only the non-rejected media section.
1049TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1050 MediaSessionOptions opts;
1051 opts.bundle_enabled = true;
1052 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1053 RtpTransceiverDirection::kSendRecv, kActive,
1054 &opts);
1055 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1056 std::unique_ptr<SessionDescription> answer =
1057 f2_.CreateAnswer(offer.get(), opts, nullptr);
1058
1059 // Reject the audio m= section and add a video m= section.
1060 opts.media_description_options[0].stopped = true;
1061 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1062 RtpTransceiverDirection::kSendRecv, kActive,
1063 &opts);
1064 std::unique_ptr<SessionDescription> reoffer =
1065 f1_.CreateOffer(opts, offer.get());
1066 std::unique_ptr<SessionDescription> reanswer =
1067 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1068
1069 const cricket::ContentGroup* bundle_group =
1070 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1071 ASSERT_TRUE(bundle_group);
1072 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1073 EXPECT_TRUE(bundle_group->HasContentName("video"));
1074}
1075
1076// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1077// and there is still a non-rejected media section that was in the initial
1078// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1079// media section.
1080TEST_F(MediaSessionDescriptionFactoryTest,
1081 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1082 MediaSessionOptions opts;
1083 opts.bundle_enabled = true;
1084 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1085 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1086 std::unique_ptr<SessionDescription> answer =
1087 f2_.CreateAnswer(offer.get(), opts, nullptr);
1088
1089 // Reject the audio m= section.
1090 opts.media_description_options[0].stopped = true;
1091 std::unique_ptr<SessionDescription> reoffer =
1092 f1_.CreateOffer(opts, offer.get());
1093
1094 const TransportDescription* offer_tagged =
1095 offer->GetTransportDescriptionByName("audio");
1096 ASSERT_TRUE(offer_tagged);
1097 const TransportDescription* reoffer_tagged =
1098 reoffer->GetTransportDescriptionByName("video");
1099 ASSERT_TRUE(reoffer_tagged);
1100 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1101 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1102}
1103
1104// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1105// and there is still a non-rejected media section that was in the initial
1106// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1107// media section.
1108TEST_F(MediaSessionDescriptionFactoryTest,
1109 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1110 MediaSessionOptions opts;
1111 opts.bundle_enabled = true;
1112 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1113 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1114 std::unique_ptr<SessionDescription> answer =
1115 f2_.CreateAnswer(offer.get(), opts, nullptr);
1116
1117 // Reject the audio m= section.
1118 opts.media_description_options[0].stopped = true;
1119 std::unique_ptr<SessionDescription> reoffer =
1120 f1_.CreateOffer(opts, offer.get());
1121 std::unique_ptr<SessionDescription> reanswer =
1122 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1123
1124 const TransportDescription* answer_tagged =
1125 answer->GetTransportDescriptionByName("audio");
1126 ASSERT_TRUE(answer_tagged);
1127 const TransportDescription* reanswer_tagged =
1128 reanswer->GetTransportDescriptionByName("video");
1129 ASSERT_TRUE(reanswer_tagged);
1130 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1131 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1132}
1133
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134// Create an audio, video offer without legacy StreamParams.
1135TEST_F(MediaSessionDescriptionFactoryTest,
1136 TestCreateOfferWithoutLegacyStreams) {
1137 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001138 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001139 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140 ASSERT_TRUE(offer.get() != NULL);
1141 const ContentInfo* ac = offer->GetContentByName("audio");
1142 const ContentInfo* vc = offer->GetContentByName("video");
1143 ASSERT_TRUE(ac != NULL);
1144 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001145 const AudioContentDescription* acd = ac->media_description()->as_audio();
1146 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001147
Yves Gerey665174f2018-06-19 15:03:05 +02001148 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1149 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001150}
1151
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001152// Creates an audio+video sendonly offer.
1153TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001154 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001155 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001156 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1157 {kMediaStream1}, 1, &opts);
1158 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1159 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001160
Steve Anton6fe1fba2018-12-11 10:15:23 -08001161 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001162 ASSERT_TRUE(offer.get() != NULL);
1163 EXPECT_EQ(2u, offer->contents().size());
1164 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1165 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1166
Steve Anton4e70a722017-11-28 14:57:10 -08001167 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1168 GetMediaDirection(&offer->contents()[0]));
1169 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1170 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001171}
1172
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001173// Verifies that the order of the media contents in the current
1174// SessionDescription is preserved in the new SessionDescription.
1175TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1176 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001177 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001178
kwiberg31022942016-03-11 14:18:21 -08001179 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001180 ASSERT_TRUE(offer1.get() != NULL);
1181 EXPECT_EQ(1u, offer1->contents().size());
1182 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1183
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001184 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1185 RtpTransceiverDirection::kRecvOnly, kActive,
1186 &opts);
kwiberg31022942016-03-11 14:18:21 -08001187 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001188 f1_.CreateOffer(opts, offer1.get()));
1189 ASSERT_TRUE(offer2.get() != NULL);
1190 EXPECT_EQ(2u, offer2->contents().size());
1191 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1192 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1193
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001194 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1195 RtpTransceiverDirection::kRecvOnly, kActive,
1196 &opts);
kwiberg31022942016-03-11 14:18:21 -08001197 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001198 f1_.CreateOffer(opts, offer2.get()));
1199 ASSERT_TRUE(offer3.get() != NULL);
1200 EXPECT_EQ(3u, offer3->contents().size());
1201 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1202 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1203 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001204}
1205
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206// Create a typical audio answer, and ensure it matches what we expect.
1207TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1208 f1_.set_secure(SEC_ENABLED);
1209 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001210 std::unique_ptr<SessionDescription> offer =
1211 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001213 std::unique_ptr<SessionDescription> answer =
1214 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001215 const ContentInfo* ac = answer->GetContentByName("audio");
1216 const ContentInfo* vc = answer->GetContentByName("video");
1217 ASSERT_TRUE(ac != NULL);
1218 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001219 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001220 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001222 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001223 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1225 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001226 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001227 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228}
1229
jbauchcb560652016-08-04 05:20:32 -07001230// Create a typical audio answer with GCM ciphers enabled, and ensure it
1231// matches what we expect.
1232TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1233 f1_.set_secure(SEC_ENABLED);
1234 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001235 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001236 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001237 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001238 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001239 std::unique_ptr<SessionDescription> answer =
1240 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001241 const ContentInfo* ac = answer->GetContentByName("audio");
1242 const ContentInfo* vc = answer->GetContentByName("video");
1243 ASSERT_TRUE(ac != NULL);
1244 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001245 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001246 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001247 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001248 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001249 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001250 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1251 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001252 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001253 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001254}
1255
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256// Create a typical video answer, and ensure it matches what we expect.
1257TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1258 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001259 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 f1_.set_secure(SEC_ENABLED);
1261 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001262 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001264 std::unique_ptr<SessionDescription> answer =
1265 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266 const ContentInfo* ac = answer->GetContentByName("audio");
1267 const ContentInfo* vc = answer->GetContentByName("video");
1268 ASSERT_TRUE(ac != NULL);
1269 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001270 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1271 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001272 const AudioContentDescription* acd = ac->media_description()->as_audio();
1273 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001275 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001277 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001279 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001281 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001282 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1283 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001284 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001285 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286}
1287
jbauchcb560652016-08-04 05:20:32 -07001288// Create a typical video answer with GCM ciphers enabled, and ensure it
1289// matches what we expect.
1290TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1291 TestVideoGcmCipher(true, true);
1292}
1293
1294// Create a typical video answer with GCM ciphers enabled for the offer only,
1295// and ensure it matches what we expect.
1296TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1297 TestVideoGcmCipher(true, false);
1298}
1299
1300// Create a typical video answer with GCM ciphers enabled for the answer only,
1301// and ensure it matches what we expect.
1302TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1303 TestVideoGcmCipher(false, true);
1304}
1305
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001306TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001307 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001308 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 f1_.set_secure(SEC_ENABLED);
1310 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001311 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001313 std::unique_ptr<SessionDescription> answer =
1314 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001315 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001316 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001318 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001319 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1320 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001321 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001322 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001324 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001325 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001326 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001327 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001328 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001329 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001330 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001331 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001332 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001333 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001334 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001335}
1336
jbauchcb560652016-08-04 05:20:32 -07001337TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001338 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001339 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001340 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001341 f1_.set_secure(SEC_ENABLED);
1342 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001343 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001344 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001345 std::unique_ptr<SessionDescription> answer =
1346 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001347 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001348 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001349 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001350 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001351 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1352 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001353 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001354 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001355 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001356 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001357 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001358 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001359 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001360 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001361 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001362 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001363 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001364 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001365 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001366 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001367}
1368
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001369// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1370// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001371TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1372 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001373 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001374 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001375 ASSERT_TRUE(offer.get() != NULL);
1376 ContentInfo* dc_offer = offer->GetContentByName("data");
1377 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001378 SctpDataContentDescription* dcd_offer =
1379 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001380 EXPECT_TRUE(dcd_offer->use_sctpmap());
1381
Steve Anton6fe1fba2018-12-11 10:15:23 -08001382 std::unique_ptr<SessionDescription> answer =
1383 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001384 const ContentInfo* dc_answer = answer->GetContentByName("data");
1385 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001386 const SctpDataContentDescription* dcd_answer =
1387 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001388 EXPECT_TRUE(dcd_answer->use_sctpmap());
1389}
1390
1391// The answer's use_sctpmap flag should match the offer's.
1392TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1393 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001394 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001395 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001396 ASSERT_TRUE(offer.get() != NULL);
1397 ContentInfo* dc_offer = offer->GetContentByName("data");
1398 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001399 SctpDataContentDescription* dcd_offer =
1400 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001401 dcd_offer->set_use_sctpmap(false);
1402
Steve Anton6fe1fba2018-12-11 10:15:23 -08001403 std::unique_ptr<SessionDescription> answer =
1404 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001405 const ContentInfo* dc_answer = answer->GetContentByName("data");
1406 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001407 const SctpDataContentDescription* dcd_answer =
1408 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001409 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001410}
1411
deadbeef8b7e9ad2017-05-25 09:38:55 -07001412// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1413// and "TCP/DTLS/SCTP" offers.
1414TEST_F(MediaSessionDescriptionFactoryTest,
1415 TestCreateDataAnswerToDifferentOfferedProtos) {
1416 // Need to enable DTLS offer/answer generation (disabled by default in this
1417 // test).
1418 f1_.set_secure(SEC_ENABLED);
1419 f2_.set_secure(SEC_ENABLED);
1420 tdf1_.set_secure(SEC_ENABLED);
1421 tdf2_.set_secure(SEC_ENABLED);
1422
1423 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001424 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001425 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001426 ASSERT_TRUE(offer.get() != nullptr);
1427 ContentInfo* dc_offer = offer->GetContentByName("data");
1428 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001429 SctpDataContentDescription* dcd_offer =
1430 dc_offer->media_description()->as_sctp();
1431 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001432
1433 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1434 "TCP/DTLS/SCTP"};
1435 for (const std::string& proto : protos) {
1436 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001437 std::unique_ptr<SessionDescription> answer =
1438 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001439 const ContentInfo* dc_answer = answer->GetContentByName("data");
1440 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001441 const SctpDataContentDescription* dcd_answer =
1442 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001443 EXPECT_FALSE(dc_answer->rejected);
1444 EXPECT_EQ(proto, dcd_answer->protocol());
1445 }
1446}
1447
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001448TEST_F(MediaSessionDescriptionFactoryTest,
1449 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1450 // Need to enable DTLS offer/answer generation (disabled by default in this
1451 // test).
1452 f1_.set_secure(SEC_ENABLED);
1453 f2_.set_secure(SEC_ENABLED);
1454 tdf1_.set_secure(SEC_ENABLED);
1455 tdf2_.set_secure(SEC_ENABLED);
1456
1457 MediaSessionOptions opts;
1458 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1459 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1460 ASSERT_TRUE(offer.get() != nullptr);
1461 ContentInfo* dc_offer = offer->GetContentByName("data");
1462 ASSERT_TRUE(dc_offer != nullptr);
1463 SctpDataContentDescription* dcd_offer =
1464 dc_offer->media_description()->as_sctp();
1465 ASSERT_TRUE(dcd_offer);
1466 dcd_offer->set_max_message_size(1234);
1467 std::unique_ptr<SessionDescription> answer =
1468 f2_.CreateAnswer(offer.get(), opts, nullptr);
1469 const ContentInfo* dc_answer = answer->GetContentByName("data");
1470 ASSERT_TRUE(dc_answer != nullptr);
1471 const SctpDataContentDescription* dcd_answer =
1472 dc_answer->media_description()->as_sctp();
1473 EXPECT_FALSE(dc_answer->rejected);
1474 EXPECT_EQ(1234, dcd_answer->max_message_size());
1475}
1476
1477TEST_F(MediaSessionDescriptionFactoryTest,
1478 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1479 // Need to enable DTLS offer/answer generation (disabled by default in this
1480 // test).
1481 f1_.set_secure(SEC_ENABLED);
1482 f2_.set_secure(SEC_ENABLED);
1483 tdf1_.set_secure(SEC_ENABLED);
1484 tdf2_.set_secure(SEC_ENABLED);
1485
1486 MediaSessionOptions opts;
1487 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1488 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1489 ASSERT_TRUE(offer.get() != nullptr);
1490 ContentInfo* dc_offer = offer->GetContentByName("data");
1491 ASSERT_TRUE(dc_offer != nullptr);
1492 SctpDataContentDescription* dcd_offer =
1493 dc_offer->media_description()->as_sctp();
1494 ASSERT_TRUE(dcd_offer);
1495 dcd_offer->set_max_message_size(0);
1496 std::unique_ptr<SessionDescription> answer =
1497 f2_.CreateAnswer(offer.get(), opts, nullptr);
1498 const ContentInfo* dc_answer = answer->GetContentByName("data");
1499 ASSERT_TRUE(dc_answer != nullptr);
1500 const SctpDataContentDescription* dcd_answer =
1501 dc_answer->media_description()->as_sctp();
1502 EXPECT_FALSE(dc_answer->rejected);
1503 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1504}
1505
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001506// Verifies that the order of the media contents in the offer is preserved in
1507// the answer.
1508TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1509 MediaSessionOptions opts;
1510
1511 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001512 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001513 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001514 ASSERT_TRUE(offer1.get() != NULL);
1515
1516 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001517 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1518 RtpTransceiverDirection::kRecvOnly, kActive,
1519 &opts);
kwiberg31022942016-03-11 14:18:21 -08001520 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001521 f1_.CreateOffer(opts, offer1.get()));
1522 ASSERT_TRUE(offer2.get() != NULL);
1523
1524 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001525 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1526 RtpTransceiverDirection::kRecvOnly, kActive,
1527 &opts);
kwiberg31022942016-03-11 14:18:21 -08001528 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001529 f1_.CreateOffer(opts, offer2.get()));
1530 ASSERT_TRUE(offer3.get() != NULL);
1531
Steve Anton6fe1fba2018-12-11 10:15:23 -08001532 std::unique_ptr<SessionDescription> answer =
1533 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001534 ASSERT_TRUE(answer.get() != NULL);
1535 EXPECT_EQ(3u, answer->contents().size());
1536 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1537 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1538 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1539}
1540
ossu075af922016-06-14 03:29:38 -07001541// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1542// answerer settings.
1543
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001544// This test that the media direction is set to send/receive in an answer if
1545// the offer is send receive.
1546TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001547 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1548 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549}
1550
1551// This test that the media direction is set to receive only in an answer if
1552// the offer is send only.
1553TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001554 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1555 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001556}
1557
1558// This test that the media direction is set to send only in an answer if
1559// the offer is recv only.
1560TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001561 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1562 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563}
1564
1565// This test that the media direction is set to inactive in an answer if
1566// the offer is inactive.
1567TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001568 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1569 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001570}
1571
1572// Test that a data content with an unknown protocol is rejected in an answer.
1573TEST_F(MediaSessionDescriptionFactoryTest,
1574 CreateDataAnswerToOfferWithUnknownProtocol) {
1575 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001576 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001577 f1_.set_secure(SEC_ENABLED);
1578 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001579 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001580 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001581 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001582 RtpDataContentDescription* dcd_offer =
1583 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001584 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001585 // Offer must be acceptable as an RTP protocol in order to be set.
1586 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001587 dcd_offer->set_protocol(protocol);
1588
Steve Anton6fe1fba2018-12-11 10:15:23 -08001589 std::unique_ptr<SessionDescription> answer =
1590 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001591
1592 const ContentInfo* dc_answer = answer->GetContentByName("data");
1593 ASSERT_TRUE(dc_answer != NULL);
1594 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001595 const RtpDataContentDescription* dcd_answer =
1596 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001597 ASSERT_TRUE(dcd_answer != NULL);
1598 EXPECT_EQ(protocol, dcd_answer->protocol());
1599}
1600
1601// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1602TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001603 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604 f1_.set_secure(SEC_DISABLED);
1605 f2_.set_secure(SEC_DISABLED);
1606 tdf1_.set_secure(SEC_DISABLED);
1607 tdf2_.set_secure(SEC_DISABLED);
1608
Steve Anton6fe1fba2018-12-11 10:15:23 -08001609 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001610 const AudioContentDescription* offer_acd =
1611 GetFirstAudioContentDescription(offer.get());
1612 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001613 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001614
Steve Anton6fe1fba2018-12-11 10:15:23 -08001615 std::unique_ptr<SessionDescription> answer =
1616 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001617
1618 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1619 ASSERT_TRUE(ac_answer != NULL);
1620 EXPECT_FALSE(ac_answer->rejected);
1621
1622 const AudioContentDescription* answer_acd =
1623 GetFirstAudioContentDescription(answer.get());
1624 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001625 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626}
1627
1628// Create a video offer and answer and ensure the RTP header extensions
1629// matches what we expect.
1630TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1631 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001632 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1634 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1635 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1636 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1637
Steve Anton6fe1fba2018-12-11 10:15:23 -08001638 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001640 std::unique_ptr<SessionDescription> answer =
1641 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001642
Yves Gerey665174f2018-06-19 15:03:05 +02001643 EXPECT_EQ(
1644 MAKE_VECTOR(kAudioRtpExtension1),
1645 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1646 EXPECT_EQ(
1647 MAKE_VECTOR(kVideoRtpExtension1),
1648 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1649 EXPECT_EQ(
1650 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1651 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1652 EXPECT_EQ(
1653 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1654 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001655}
1656
Johannes Kronce8e8672019-02-22 13:06:44 +01001657// Create a audio/video offer and answer and ensure that the
1658// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1659// supported and should take precedence even though not listed among locally
1660// supported extensions.
1661TEST_F(MediaSessionDescriptionFactoryTest,
1662 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1663 TestTransportSequenceNumberNegotiation(
1664 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1665 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1666 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1667}
1668TEST_F(MediaSessionDescriptionFactoryTest,
1669 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1670 TestTransportSequenceNumberNegotiation(
1671 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1672 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1673 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1674}
1675TEST_F(MediaSessionDescriptionFactoryTest,
1676 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1677 TestTransportSequenceNumberNegotiation(
1678 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1679 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1680 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1681}
1682
jbauch5869f502017-06-29 12:31:36 -07001683TEST_F(MediaSessionDescriptionFactoryTest,
Markus Handellc1cbf6b2020-02-17 20:03:57 +01001684 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1685 MediaSessionOptions opts;
1686 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1687
1688 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1689 f1_.set_audio_rtp_header_extensions(offered);
1690 f1_.set_video_rtp_header_extensions(offered);
1691 const auto local = MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01);
1692 f2_.set_audio_rtp_header_extensions(local);
1693 f2_.set_video_rtp_header_extensions(local);
1694 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1695 std::unique_ptr<SessionDescription> answer =
1696 f2_.CreateAnswer(offer.get(), opts, nullptr);
1697 EXPECT_THAT(
1698 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1699 ElementsAreArray(offered));
1700 EXPECT_THAT(
1701 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1702 ElementsAreArray(offered));
1703}
1704
1705TEST_F(MediaSessionDescriptionFactoryTest,
1706 TestNegotiateFrameDescriptorWhenExposedLocally) {
1707 MediaSessionOptions opts;
1708 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1709
1710 const auto offered = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1711 f1_.set_audio_rtp_header_extensions(offered);
1712 f1_.set_video_rtp_header_extensions(offered);
1713 const auto local = MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00);
1714 f2_.set_audio_rtp_header_extensions(local);
1715 f2_.set_video_rtp_header_extensions(local);
1716 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1717 std::unique_ptr<SessionDescription> answer =
1718 f2_.CreateAnswer(offer.get(), opts, nullptr);
1719 EXPECT_THAT(
1720 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1721 ElementsAreArray(offered));
1722 EXPECT_THAT(
1723 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1724 ElementsAreArray(offered));
1725}
1726
1727TEST_F(MediaSessionDescriptionFactoryTest,
Danil Chapovalov5f999a72020-02-20 16:39:05 +01001728 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1729 MediaSessionOptions opts;
1730 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1731
1732 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1733 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1734 f1_.set_video_rtp_header_extensions({offer_dd});
1735 f2_.set_video_rtp_header_extensions({local_tsn});
1736 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1737 std::unique_ptr<SessionDescription> answer =
1738 f2_.CreateAnswer(offer.get(), opts, nullptr);
1739 EXPECT_THAT(
1740 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1741 ElementsAre(offer_dd));
1742}
1743
1744TEST_F(MediaSessionDescriptionFactoryTest,
1745 NegotiateDependencyDescriptorWhenExposedLocally) {
1746 MediaSessionOptions opts;
1747 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1748
1749 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1750 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
1751 f1_.set_video_rtp_header_extensions({offer_dd});
1752 f2_.set_video_rtp_header_extensions({local_dd});
1753 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1754 std::unique_ptr<SessionDescription> answer =
1755 f2_.CreateAnswer(offer.get(), opts, nullptr);
1756 EXPECT_THAT(
1757 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1758 ElementsAre(offer_dd));
1759}
1760
1761TEST_F(MediaSessionDescriptionFactoryTest,
Minyue Li430e4a02020-03-10 10:59:37 +01001762 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1763 MediaSessionOptions opts;
1764 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1765
1766 const cricket::RtpHeaderExtensions offered_extensions = {
1767 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1768 const cricket::RtpHeaderExtensions local_extensions = {
1769 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
1770 f1_.set_video_rtp_header_extensions(offered_extensions);
1771 f1_.set_audio_rtp_header_extensions(offered_extensions);
1772 f2_.set_video_rtp_header_extensions(local_extensions);
1773 f2_.set_audio_rtp_header_extensions(local_extensions);
1774
1775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1776 std::unique_ptr<SessionDescription> answer =
1777 f2_.CreateAnswer(offer.get(), opts, nullptr);
1778 EXPECT_THAT(
1779 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1780 ElementsAreArray(offered_extensions));
1781 EXPECT_THAT(
1782 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1783 ElementsAreArray(offered_extensions));
1784}
1785
1786TEST_F(MediaSessionDescriptionFactoryTest,
1787 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1788 MediaSessionOptions opts;
1789 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1790
1791 const cricket::RtpHeaderExtensions offered_extensions = {
1792 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1793 const cricket::RtpHeaderExtensions local_extensions = {
1794 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
1795 f1_.set_video_rtp_header_extensions(offered_extensions);
1796 f1_.set_audio_rtp_header_extensions(offered_extensions);
1797 f2_.set_video_rtp_header_extensions(local_extensions);
1798 f2_.set_audio_rtp_header_extensions(local_extensions);
1799
1800 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1801 std::unique_ptr<SessionDescription> answer =
1802 f2_.CreateAnswer(offer.get(), opts, nullptr);
1803 EXPECT_THAT(
1804 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1805 ElementsAreArray(offered_extensions));
1806 EXPECT_THAT(
1807 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1808 ElementsAreArray(offered_extensions));
1809}
1810
1811TEST_F(MediaSessionDescriptionFactoryTest,
1812 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1813 MediaSessionOptions opts;
1814 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1815
1816 const cricket::RtpHeaderExtensions offered_extensions = {
1817 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1818 const cricket::RtpHeaderExtensions local_extensions = {
1819 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
1820 f1_.set_video_rtp_header_extensions(offered_extensions);
1821 f1_.set_audio_rtp_header_extensions(offered_extensions);
1822 f2_.set_video_rtp_header_extensions(local_extensions);
1823 f2_.set_audio_rtp_header_extensions(local_extensions);
1824
1825 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1826 std::unique_ptr<SessionDescription> answer =
1827 f2_.CreateAnswer(offer.get(), opts, nullptr);
1828 EXPECT_THAT(
1829 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1830 IsEmpty());
1831 EXPECT_THAT(
1832 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1833 IsEmpty());
1834}
1835
1836TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001837 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001838 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001839 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001840
1841 f1_.set_enable_encrypted_rtp_header_extensions(true);
1842 f2_.set_enable_encrypted_rtp_header_extensions(true);
1843
Yves Gerey665174f2018-06-19 15:03:05 +02001844 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1845 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1846 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1847 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001848
Steve Anton6fe1fba2018-12-11 10:15:23 -08001849 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001850 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001851 std::unique_ptr<SessionDescription> answer =
1852 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001853
Yves Gerey665174f2018-06-19 15:03:05 +02001854 EXPECT_EQ(
1855 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1856 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1857 EXPECT_EQ(
1858 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1859 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1860 EXPECT_EQ(
1861 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1862 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1863 EXPECT_EQ(
1864 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1865 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001866}
1867
1868TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001869 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001870 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001871 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001872
1873 f1_.set_enable_encrypted_rtp_header_extensions(true);
1874
Yves Gerey665174f2018-06-19 15:03:05 +02001875 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1876 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1877 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1878 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001879
Steve Anton6fe1fba2018-12-11 10:15:23 -08001880 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001881 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001882 std::unique_ptr<SessionDescription> answer =
1883 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001884
Yves Gerey665174f2018-06-19 15:03:05 +02001885 EXPECT_EQ(
1886 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1887 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1888 EXPECT_EQ(
1889 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1890 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1891 EXPECT_EQ(
1892 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1893 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1894 EXPECT_EQ(
1895 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1896 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001897}
1898
1899TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001900 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001901 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001902 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001903
1904 f2_.set_enable_encrypted_rtp_header_extensions(true);
1905
Yves Gerey665174f2018-06-19 15:03:05 +02001906 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1907 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1908 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1909 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001910
Steve Anton6fe1fba2018-12-11 10:15:23 -08001911 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001912 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001913 std::unique_ptr<SessionDescription> answer =
1914 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001915
Yves Gerey665174f2018-06-19 15:03:05 +02001916 EXPECT_EQ(
1917 MAKE_VECTOR(kAudioRtpExtension1),
1918 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1919 EXPECT_EQ(
1920 MAKE_VECTOR(kVideoRtpExtension1),
1921 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1922 EXPECT_EQ(
1923 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1924 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1925 EXPECT_EQ(
1926 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1927 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001928}
1929
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001930// Create an audio, video, data answer without legacy StreamParams.
1931TEST_F(MediaSessionDescriptionFactoryTest,
1932 TestCreateAnswerWithoutLegacyStreams) {
1933 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001934 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1935 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001936 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001937 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001938 std::unique_ptr<SessionDescription> answer =
1939 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001940 const ContentInfo* ac = answer->GetContentByName("audio");
1941 const ContentInfo* vc = answer->GetContentByName("video");
1942 const ContentInfo* dc = answer->GetContentByName("data");
1943 ASSERT_TRUE(ac != NULL);
1944 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001945 const AudioContentDescription* acd = ac->media_description()->as_audio();
1946 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001947 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001948
1949 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1950 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1951 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1952}
1953
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001954// Create a typical video answer, and ensure it matches what we expect.
1955TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1956 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001957 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1958 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1959 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001960
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001961 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001962 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1963 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1964 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965
kwiberg31022942016-03-11 14:18:21 -08001966 std::unique_ptr<SessionDescription> offer;
1967 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001968
1969 offer_opts.rtcp_mux_enabled = true;
1970 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001971 offer = f1_.CreateOffer(offer_opts, NULL);
1972 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001973 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1974 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001975 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1977 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001978 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001979 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1980 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001981 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001982 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1983 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001984 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001985
1986 offer_opts.rtcp_mux_enabled = true;
1987 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001988 offer = f1_.CreateOffer(offer_opts, NULL);
1989 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1991 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001992 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001993 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1994 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001995 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001996 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1997 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001998 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2000 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002001 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002002
2003 offer_opts.rtcp_mux_enabled = false;
2004 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002005 offer = f1_.CreateOffer(offer_opts, NULL);
2006 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002007 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2008 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002009 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2011 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002012 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002013 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2014 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002015 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002016 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2017 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002018 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002019
2020 offer_opts.rtcp_mux_enabled = false;
2021 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002022 offer = f1_.CreateOffer(offer_opts, NULL);
2023 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002024 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2025 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002026 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002027 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2028 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002029 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002030 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2031 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002032 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002033 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2034 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002035 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002036}
2037
2038// Create an audio-only answer to a video offer.
2039TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2040 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002041 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2042 RtpTransceiverDirection::kRecvOnly, kActive,
2043 &opts);
2044 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2045 RtpTransceiverDirection::kRecvOnly, kActive,
2046 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002047 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002048 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002049
2050 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002051 std::unique_ptr<SessionDescription> answer =
2052 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002053 const ContentInfo* ac = answer->GetContentByName("audio");
2054 const ContentInfo* vc = answer->GetContentByName("video");
2055 ASSERT_TRUE(ac != NULL);
2056 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002057 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058 EXPECT_TRUE(vc->rejected);
2059}
2060
2061// Create an audio-only answer to an offer with data.
2062TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002063 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002064 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002065 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2066 RtpTransceiverDirection::kRecvOnly, kActive,
2067 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002068 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002069 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07002070
2071 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002072 std::unique_ptr<SessionDescription> answer =
2073 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002074 const ContentInfo* ac = answer->GetContentByName("audio");
2075 const ContentInfo* dc = answer->GetContentByName("data");
2076 ASSERT_TRUE(ac != NULL);
2077 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002078 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002079 EXPECT_TRUE(dc->rejected);
2080}
2081
2082// Create an answer that rejects the contents which are rejected in the offer.
2083TEST_F(MediaSessionDescriptionFactoryTest,
2084 CreateAnswerToOfferWithRejectedMedia) {
2085 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002086 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2087 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002088 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002089 ASSERT_TRUE(offer.get() != NULL);
2090 ContentInfo* ac = offer->GetContentByName("audio");
2091 ContentInfo* vc = offer->GetContentByName("video");
2092 ContentInfo* dc = offer->GetContentByName("data");
2093 ASSERT_TRUE(ac != NULL);
2094 ASSERT_TRUE(vc != NULL);
2095 ASSERT_TRUE(dc != NULL);
2096 ac->rejected = true;
2097 vc->rejected = true;
2098 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002099 std::unique_ptr<SessionDescription> answer =
2100 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002101 ac = answer->GetContentByName("audio");
2102 vc = answer->GetContentByName("video");
2103 dc = answer->GetContentByName("data");
2104 ASSERT_TRUE(ac != NULL);
2105 ASSERT_TRUE(vc != NULL);
2106 ASSERT_TRUE(dc != NULL);
2107 EXPECT_TRUE(ac->rejected);
2108 EXPECT_TRUE(vc->rejected);
2109 EXPECT_TRUE(dc->rejected);
2110}
2111
Johannes Kron0854eb62018-10-10 22:33:20 +02002112TEST_F(MediaSessionDescriptionFactoryTest,
2113 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
2114 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08002115 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002116 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002117 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02002118 ASSERT_TRUE(offer.get() != NULL);
2119 std::unique_ptr<SessionDescription> answer_no_support(
2120 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002121 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002122
2123 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02002124 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02002125 ASSERT_TRUE(offer.get() != NULL);
2126 std::unique_ptr<SessionDescription> answer_support(
2127 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02002128 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02002129}
2130
2131TEST_F(MediaSessionDescriptionFactoryTest,
2132 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
2133 MediaSessionOptions opts;
2134 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002135 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02002136 MediaContentDescription* video_offer =
2137 offer->GetContentDescriptionByName("video");
2138 ASSERT_TRUE(video_offer);
2139 MediaContentDescription* audio_offer =
2140 offer->GetContentDescriptionByName("audio");
2141 ASSERT_TRUE(audio_offer);
2142
2143 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002144 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2145 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02002146
2147 ASSERT_TRUE(offer.get() != NULL);
2148 std::unique_ptr<SessionDescription> answer_no_support(
2149 f2_.CreateAnswer(offer.get(), opts, NULL));
2150 MediaContentDescription* video_answer =
2151 answer_no_support->GetContentDescriptionByName("video");
2152 MediaContentDescription* audio_answer =
2153 answer_no_support->GetContentDescriptionByName("audio");
2154 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002155 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002156 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02002157 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002158
2159 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002160 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2161 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002162 ASSERT_TRUE(offer.get() != NULL);
2163 std::unique_ptr<SessionDescription> answer_support(
2164 f2_.CreateAnswer(offer.get(), opts, NULL));
2165 video_answer = answer_support->GetContentDescriptionByName("video");
2166 audio_answer = answer_support->GetContentDescriptionByName("audio");
2167 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002168 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002169 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002170 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002171}
2172
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002173// Create an audio and video offer with:
2174// - one video track
2175// - two audio tracks
2176// - two data tracks
2177// and ensure it matches what we expect. Also updates the initial offer by
2178// adding a new video track and replaces one of the audio tracks.
2179TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2180 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002181 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002182 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2183 {kMediaStream1}, 1, &opts);
2184 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2185 {kMediaStream1}, 1, &opts);
2186 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2187 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002188
Steve Anton4e70a722017-11-28 14:57:10 -08002189 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002190 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2191 {kMediaStream1}, 1, &opts);
2192 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2193 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002194
2195 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002196 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197
2198 ASSERT_TRUE(offer.get() != NULL);
2199 const ContentInfo* ac = offer->GetContentByName("audio");
2200 const ContentInfo* vc = offer->GetContentByName("video");
2201 const ContentInfo* dc = offer->GetContentByName("data");
2202 ASSERT_TRUE(ac != NULL);
2203 ASSERT_TRUE(vc != NULL);
2204 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002205 const AudioContentDescription* acd = ac->media_description()->as_audio();
2206 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002207 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002208 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002209 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002210
2211 const StreamParamsVec& audio_streams = acd->streams();
2212 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002213 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002214 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2215 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2216 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2217 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2218 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2219 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2220
2221 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2222 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002223 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002224
2225 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron3e983682020-03-29 22:17:00 +02002226 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002227 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002228
2229 const StreamParamsVec& video_streams = vcd->streams();
2230 ASSERT_EQ(1U, video_streams.size());
2231 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2232 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2233 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2234 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2235
2236 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002237 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002238 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239
2240 const StreamParamsVec& data_streams = dcd->streams();
2241 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002242 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002243 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2244 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2245 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2246 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2247 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2248 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2249
2250 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002251 dcd->bandwidth()); // default bandwidth (auto)
2252 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002253 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002254
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002255 // Update the offer. Add a new video track that is not synched to the
2256 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002257 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2258 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002259 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002260 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2261 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002262 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002263 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2264 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002265 std::unique_ptr<SessionDescription> updated_offer(
2266 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002267
2268 ASSERT_TRUE(updated_offer.get() != NULL);
2269 ac = updated_offer->GetContentByName("audio");
2270 vc = updated_offer->GetContentByName("video");
2271 dc = updated_offer->GetContentByName("data");
2272 ASSERT_TRUE(ac != NULL);
2273 ASSERT_TRUE(vc != NULL);
2274 ASSERT_TRUE(dc != NULL);
2275 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002276 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002277 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002278 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002279 const RtpDataContentDescription* updated_dcd =
2280 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002281
2282 EXPECT_EQ(acd->type(), updated_acd->type());
2283 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2284 EXPECT_EQ(vcd->type(), updated_vcd->type());
2285 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2286 EXPECT_EQ(dcd->type(), updated_dcd->type());
2287 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002288 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002289 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002290 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002291 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002292 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002293 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2294
2295 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2296 ASSERT_EQ(2U, updated_audio_streams.size());
2297 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2298 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2299 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2300 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2301 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2302
2303 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2304 ASSERT_EQ(2U, updated_video_streams.size());
2305 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2306 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002307 // All the media streams in one PeerConnection share one RTCP CNAME.
2308 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002309
2310 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2311 ASSERT_EQ(2U, updated_data_streams.size());
2312 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2313 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2314 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2315 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2316 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002317 // The stream correctly got the CNAME from the MediaSessionOptions.
2318 // The Expected RTCP CNAME is the default one as we are using the default
2319 // MediaSessionOptions.
2320 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002321}
2322
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002323// Create an offer with simulcast video stream.
2324TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2325 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002326 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2327 RtpTransceiverDirection::kRecvOnly, kActive,
2328 &opts);
2329 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2330 RtpTransceiverDirection::kSendRecv, kActive,
2331 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002332 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002333 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2334 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002335 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002336
2337 ASSERT_TRUE(offer.get() != NULL);
2338 const ContentInfo* vc = offer->GetContentByName("video");
2339 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002340 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002341
2342 const StreamParamsVec& video_streams = vcd->streams();
2343 ASSERT_EQ(1U, video_streams.size());
2344 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2345 const SsrcGroup* sim_ssrc_group =
2346 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2347 ASSERT_TRUE(sim_ssrc_group != NULL);
2348 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2349}
2350
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002351MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2352 const RidDescription& rid1 = ::testing::get<0>(arg);
2353 const RidDescription& rid2 = ::testing::get<1>(arg);
2354 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2355}
2356
2357static void CheckSimulcastInSessionDescription(
2358 const SessionDescription* description,
2359 const std::string& content_name,
2360 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002361 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002362 ASSERT_NE(description, nullptr);
2363 const ContentInfo* content = description->GetContentByName(content_name);
2364 ASSERT_NE(content, nullptr);
2365 const MediaContentDescription* cd = content->media_description();
2366 ASSERT_NE(cd, nullptr);
2367 const StreamParamsVec& streams = cd->streams();
2368 ASSERT_THAT(streams, SizeIs(1));
2369 const StreamParams& stream = streams[0];
2370 ASSERT_THAT(stream.ssrcs, IsEmpty());
2371 EXPECT_TRUE(stream.has_rids());
2372 const std::vector<RidDescription> rids = stream.rids();
2373
2374 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2375
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002376 EXPECT_TRUE(cd->HasSimulcast());
2377 const SimulcastDescription& simulcast = cd->simulcast_description();
2378 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2379 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2380
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002381 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002382}
2383
2384// Create an offer with spec-compliant simulcast video stream.
2385TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2386 MediaSessionOptions opts;
2387 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2388 RtpTransceiverDirection::kSendRecv, kActive,
2389 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002390 std::vector<RidDescription> send_rids;
2391 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2392 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2393 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2394 SimulcastLayerList simulcast_layers;
2395 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2396 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2397 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2398 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2399 {kMediaStream1}, send_rids,
2400 simulcast_layers, 0, &opts);
2401 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2402
2403 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002404 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002405}
2406
2407// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2408// In this scenario, RIDs do not need to be negotiated (there is only one).
2409TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2410 MediaSessionOptions opts;
2411 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2412 RtpTransceiverDirection::kSendRecv, kActive,
2413 &opts);
2414 RidDescription rid("f", RidDirection::kSend);
2415 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2416 {kMediaStream1}, {rid},
2417 SimulcastLayerList(), 0, &opts);
2418 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2419
2420 ASSERT_NE(offer.get(), nullptr);
2421 const ContentInfo* content = offer->GetContentByName("video");
2422 ASSERT_NE(content, nullptr);
2423 const MediaContentDescription* cd = content->media_description();
2424 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002425 const StreamParamsVec& streams = cd->streams();
2426 ASSERT_THAT(streams, SizeIs(1));
2427 const StreamParams& stream = streams[0];
2428 ASSERT_THAT(stream.ssrcs, IsEmpty());
2429 EXPECT_FALSE(stream.has_rids());
2430 EXPECT_FALSE(cd->HasSimulcast());
2431}
2432
2433// Create an answer with spec-compliant simulcast video stream.
2434// In this scenario, the SFU is the caller requesting that we send Simulcast.
2435TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2436 MediaSessionOptions offer_opts;
2437 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2438 RtpTransceiverDirection::kSendRecv, kActive,
2439 &offer_opts);
2440 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2441 {kMediaStream1}, 1, &offer_opts);
2442 std::unique_ptr<SessionDescription> offer =
2443 f1_.CreateOffer(offer_opts, nullptr);
2444
2445 MediaSessionOptions answer_opts;
2446 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2447 RtpTransceiverDirection::kSendRecv, kActive,
2448 &answer_opts);
2449
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002450 std::vector<RidDescription> rid_descriptions{
2451 RidDescription("f", RidDirection::kSend),
2452 RidDescription("h", RidDirection::kSend),
2453 RidDescription("q", RidDirection::kSend),
2454 };
2455 SimulcastLayerList simulcast_layers;
2456 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2457 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2458 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2459 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2460 {kMediaStream1}, rid_descriptions,
2461 simulcast_layers, 0, &answer_opts);
2462 std::unique_ptr<SessionDescription> answer =
2463 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2464
2465 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002466 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002467}
2468
2469// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2470// In this scenario, RIDs do not need to be negotiated (there is only one).
2471// Note that RID Direction is not the same as the transceiver direction.
2472TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2473 MediaSessionOptions offer_opts;
2474 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2475 RtpTransceiverDirection::kSendRecv, kActive,
2476 &offer_opts);
2477 RidDescription rid_offer("f", RidDirection::kSend);
2478 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2479 {kMediaStream1}, {rid_offer},
2480 SimulcastLayerList(), 0, &offer_opts);
2481 std::unique_ptr<SessionDescription> offer =
2482 f1_.CreateOffer(offer_opts, nullptr);
2483
2484 MediaSessionOptions answer_opts;
2485 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2486 RtpTransceiverDirection::kSendRecv, kActive,
2487 &answer_opts);
2488
2489 RidDescription rid_answer("f", RidDirection::kReceive);
2490 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2491 {kMediaStream1}, {rid_answer},
2492 SimulcastLayerList(), 0, &answer_opts);
2493 std::unique_ptr<SessionDescription> answer =
2494 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2495
2496 ASSERT_NE(answer.get(), nullptr);
2497 const ContentInfo* content = offer->GetContentByName("video");
2498 ASSERT_NE(content, nullptr);
2499 const MediaContentDescription* cd = content->media_description();
2500 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002501 const StreamParamsVec& streams = cd->streams();
2502 ASSERT_THAT(streams, SizeIs(1));
2503 const StreamParams& stream = streams[0];
2504 ASSERT_THAT(stream.ssrcs, IsEmpty());
2505 EXPECT_FALSE(stream.has_rids());
2506 EXPECT_FALSE(cd->HasSimulcast());
2507}
2508
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002509// Create an audio and video answer to a standard video offer with:
2510// - one video track
2511// - two audio tracks
2512// - two data tracks
2513// and ensure it matches what we expect. Also updates the initial answer by
2514// adding a new video track and removes one of the audio tracks.
2515TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2516 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002517 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2518 RtpTransceiverDirection::kRecvOnly, kActive,
2519 &offer_opts);
2520 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2521 RtpTransceiverDirection::kRecvOnly, kActive,
2522 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002523 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002524 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2525 RtpTransceiverDirection::kRecvOnly, kActive,
2526 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002527 f1_.set_secure(SEC_ENABLED);
2528 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002529 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530
zhihuang1c378ed2017-08-17 14:10:50 -07002531 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002532 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2533 RtpTransceiverDirection::kSendRecv, kActive,
2534 &answer_opts);
2535 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2536 RtpTransceiverDirection::kSendRecv, kActive,
2537 &answer_opts);
2538 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2539 {kMediaStream1}, 1, &answer_opts);
2540 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2541 {kMediaStream1}, 1, &answer_opts);
2542 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2543 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002544
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002545 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2546 RtpTransceiverDirection::kSendRecv, kActive,
2547 &answer_opts);
2548 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2549 {kMediaStream1}, 1, &answer_opts);
2550 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2551 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002552 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002553
Steve Anton6fe1fba2018-12-11 10:15:23 -08002554 std::unique_ptr<SessionDescription> answer =
2555 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002556
2557 ASSERT_TRUE(answer.get() != NULL);
2558 const ContentInfo* ac = answer->GetContentByName("audio");
2559 const ContentInfo* vc = answer->GetContentByName("video");
2560 const ContentInfo* dc = answer->GetContentByName("data");
2561 ASSERT_TRUE(ac != NULL);
2562 ASSERT_TRUE(vc != NULL);
2563 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002564 const AudioContentDescription* acd = ac->media_description()->as_audio();
2565 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002566 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002567 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2568 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2569 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002570
2571 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002572 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002573
2574 const StreamParamsVec& audio_streams = acd->streams();
2575 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002576 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002577 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2578 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2579 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2580 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2581 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2582 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2583
2584 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2585 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2586
2587 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002588 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002589
2590 const StreamParamsVec& video_streams = vcd->streams();
2591 ASSERT_EQ(1U, video_streams.size());
2592 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2593 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2594 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2595 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2596
2597 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002598 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002599
2600 const StreamParamsVec& data_streams = dcd->streams();
2601 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002602 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002603 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2604 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2605 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2606 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2607 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2608 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2609
2610 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002611 dcd->bandwidth()); // default bandwidth (auto)
2612 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002613
2614 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002615 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002616 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2617 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002618 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2619 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002620 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002621 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002622
2623 ASSERT_TRUE(updated_answer.get() != NULL);
2624 ac = updated_answer->GetContentByName("audio");
2625 vc = updated_answer->GetContentByName("video");
2626 dc = updated_answer->GetContentByName("data");
2627 ASSERT_TRUE(ac != NULL);
2628 ASSERT_TRUE(vc != NULL);
2629 ASSERT_TRUE(dc != NULL);
2630 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002631 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002632 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002633 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002634 const RtpDataContentDescription* updated_dcd =
2635 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002636
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002637 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002638 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002639 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002640 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002641 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2643
2644 EXPECT_EQ(acd->type(), updated_acd->type());
2645 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2646 EXPECT_EQ(vcd->type(), updated_vcd->type());
2647 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2648 EXPECT_EQ(dcd->type(), updated_dcd->type());
2649 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2650
2651 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2652 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002653 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002654
2655 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2656 ASSERT_EQ(2U, updated_video_streams.size());
2657 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2658 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002659 // All media streams in one PeerConnection share one CNAME.
2660 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661
2662 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2663 ASSERT_EQ(1U, updated_data_streams.size());
2664 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2665}
2666
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002667// Create an updated offer after creating an answer to the original offer and
2668// verify that the codecs that were part of the original answer are not changed
2669// in the updated offer.
2670TEST_F(MediaSessionDescriptionFactoryTest,
2671 RespondentCreatesOfferAfterCreatingAnswer) {
2672 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002673 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002674
Steve Anton6fe1fba2018-12-11 10:15:23 -08002675 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2676 std::unique_ptr<SessionDescription> answer =
2677 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002678
2679 const AudioContentDescription* acd =
2680 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002681 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002682
2683 const VideoContentDescription* vcd =
2684 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002685 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686
kwiberg31022942016-03-11 14:18:21 -08002687 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002688 f2_.CreateOffer(opts, answer.get()));
2689
2690 // The expected audio codecs are the common audio codecs from the first
2691 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2692 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002693 // TODO(wu): |updated_offer| should not include the codec
2694 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002695 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002696 kAudioCodecsAnswer[0],
2697 kAudioCodecsAnswer[1],
2698 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002699 };
2700
2701 // The expected video codecs are the common video codecs from the first
2702 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2703 // preference order.
2704 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002705 kVideoCodecsAnswer[0],
2706 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707 };
2708
2709 const AudioContentDescription* updated_acd =
2710 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002711 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002712
2713 const VideoContentDescription* updated_vcd =
2714 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002715 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716}
2717
Steve Anton5c72e712018-12-10 14:25:30 -08002718// Test that a reoffer does not reuse audio codecs from a previous media section
2719// that is being recycled.
2720TEST_F(MediaSessionDescriptionFactoryTest,
2721 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002722 f1_.set_video_codecs({}, {});
2723 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002724
2725 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002726 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2727 RtpTransceiverDirection::kSendRecv, kActive,
2728 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002729 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2730 std::unique_ptr<SessionDescription> answer =
2731 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002732
2733 // Recycle the media section by changing its mid.
2734 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002735 std::unique_ptr<SessionDescription> reoffer =
2736 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002737
2738 // Expect that the results of the first negotiation are ignored. If the m=
2739 // section was not recycled the payload types would match the initial offerer.
2740 const AudioContentDescription* acd =
2741 GetFirstAudioContentDescription(reoffer.get());
2742 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2743}
2744
2745// Test that a reoffer does not reuse video codecs from a previous media section
2746// that is being recycled.
2747TEST_F(MediaSessionDescriptionFactoryTest,
2748 ReOfferDoesNotReUseRecycledVideoCodecs) {
2749 f1_.set_audio_codecs({}, {});
2750 f2_.set_audio_codecs({}, {});
2751
2752 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002753 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2754 RtpTransceiverDirection::kSendRecv, kActive,
2755 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002756 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2757 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002758
2759 // Recycle the media section by changing its mid.
2760 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002761 std::unique_ptr<SessionDescription> reoffer =
2762 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002763
2764 // Expect that the results of the first negotiation are ignored. If the m=
2765 // section was not recycled the payload types would match the initial offerer.
2766 const VideoContentDescription* vcd =
2767 GetFirstVideoContentDescription(reoffer.get());
2768 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2769}
2770
2771// Test that a reanswer does not reuse audio codecs from a previous media
2772// section that is being recycled.
2773TEST_F(MediaSessionDescriptionFactoryTest,
2774 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron3e983682020-03-29 22:17:00 +02002775 f1_.set_video_codecs({}, {});
2776 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002777
2778 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2779 // second offer/answer is forward (|f1_| as offerer).
2780 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002781 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2782 RtpTransceiverDirection::kSendRecv, kActive,
2783 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002784 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2785 std::unique_ptr<SessionDescription> answer =
2786 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002787
2788 // Recycle the media section by changing its mid.
2789 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002790 std::unique_ptr<SessionDescription> reoffer =
2791 f1_.CreateOffer(opts, answer.get());
2792 std::unique_ptr<SessionDescription> reanswer =
2793 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002794
2795 // Expect that the results of the first negotiation are ignored. If the m=
2796 // section was not recycled the payload types would match the initial offerer.
2797 const AudioContentDescription* acd =
2798 GetFirstAudioContentDescription(reanswer.get());
2799 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2800}
2801
2802// Test that a reanswer does not reuse video codecs from a previous media
2803// section that is being recycled.
2804TEST_F(MediaSessionDescriptionFactoryTest,
2805 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2806 f1_.set_audio_codecs({}, {});
2807 f2_.set_audio_codecs({}, {});
2808
2809 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2810 // second offer/answer is forward (|f1_| as offerer).
2811 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002812 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2813 RtpTransceiverDirection::kSendRecv, kActive,
2814 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002815 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2816 std::unique_ptr<SessionDescription> answer =
2817 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002818
2819 // Recycle the media section by changing its mid.
2820 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002821 std::unique_ptr<SessionDescription> reoffer =
2822 f1_.CreateOffer(opts, answer.get());
2823 std::unique_ptr<SessionDescription> reanswer =
2824 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002825
2826 // Expect that the results of the first negotiation are ignored. If the m=
2827 // section was not recycled the payload types would match the initial offerer.
2828 const VideoContentDescription* vcd =
2829 GetFirstVideoContentDescription(reanswer.get());
2830 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2831}
2832
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002833// Create an updated offer after creating an answer to the original offer and
2834// verify that the codecs that were part of the original answer are not changed
2835// in the updated offer. In this test Rtx is enabled.
2836TEST_F(MediaSessionDescriptionFactoryTest,
2837 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2838 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002839 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2840 RtpTransceiverDirection::kRecvOnly, kActive,
2841 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002842 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002843 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002844 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002845 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002846
2847 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002848 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002849 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002850 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002851
Steve Anton6fe1fba2018-12-11 10:15:23 -08002852 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002853 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002854 std::unique_ptr<SessionDescription> answer =
2855 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002856
2857 const VideoContentDescription* vcd =
2858 GetFirstVideoContentDescription(answer.get());
2859
2860 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002861 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2862 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002863
2864 EXPECT_EQ(expected_codecs, vcd->codecs());
2865
deadbeef67cf2c12016-04-13 10:07:16 -07002866 // Now, make sure we get same result (except for the order) if |f2_| creates
2867 // an updated offer even though the default payload types between |f1_| and
2868 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002869 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002870 f2_.CreateOffer(opts, answer.get()));
2871 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002872 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002873 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2874
2875 const VideoContentDescription* updated_vcd =
2876 GetFirstVideoContentDescription(updated_answer.get());
2877
2878 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2879}
2880
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002881// Regression test for:
2882// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2883// Existing codecs should always appear before new codecs in re-offers. But
2884// under a specific set of circumstances, the existing RTX codec was ending up
2885// added to the end of the list.
2886TEST_F(MediaSessionDescriptionFactoryTest,
2887 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2888 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002889 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2890 RtpTransceiverDirection::kRecvOnly, kActive,
2891 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002892 // We specifically choose different preferred payload types for VP8 to
2893 // trigger the issue.
2894 cricket::VideoCodec vp8_offerer(100, "VP8");
2895 cricket::VideoCodec vp8_offerer_rtx =
2896 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2897 cricket::VideoCodec vp8_answerer(110, "VP8");
2898 cricket::VideoCodec vp8_answerer_rtx =
2899 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2900 cricket::VideoCodec vp9(120, "VP9");
2901 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2902
2903 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2904 // We also specifically cause the answerer to prefer VP9, such that if it
2905 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2906 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2907 vp8_answerer_rtx};
2908
Johannes Kron3e983682020-03-29 22:17:00 +02002909 f1_.set_video_codecs(f1_codecs, f1_codecs);
2910 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002911 std::vector<AudioCodec> audio_codecs;
2912 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2913 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2914
2915 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002916 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002917 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002918 std::unique_ptr<SessionDescription> answer =
2919 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002920
2921 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2922 // But if the bug is triggered, RTX for VP8 ends up last.
2923 std::unique_ptr<SessionDescription> updated_offer(
2924 f2_.CreateOffer(opts, answer.get()));
2925
2926 const VideoContentDescription* vcd =
2927 GetFirstVideoContentDescription(updated_offer.get());
2928 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2929 ASSERT_EQ(4u, codecs.size());
2930 EXPECT_EQ(vp8_offerer, codecs[0]);
2931 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2932 EXPECT_EQ(vp9, codecs[2]);
2933 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002934}
2935
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002936// Create an updated offer that adds video after creating an audio only answer
2937// to the original offer. This test verifies that if a video codec and the RTX
2938// codec have the same default payload type as an audio codec that is already in
2939// use, the added codecs payload types are changed.
2940TEST_F(MediaSessionDescriptionFactoryTest,
2941 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2942 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002943 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002944 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002945 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002946
2947 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002948 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2949 RtpTransceiverDirection::kRecvOnly, kActive,
2950 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002951
Steve Anton6fe1fba2018-12-11 10:15:23 -08002952 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2953 std::unique_ptr<SessionDescription> answer =
2954 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002955
2956 const AudioContentDescription* acd =
2957 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002958 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002959
2960 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2961 // reference be the same as an audio codec that was negotiated in the
2962 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002963 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002964 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002965
2966 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2967 int used_pl_type = acd->codecs()[0].id;
2968 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002969 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02002970 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002971
kwiberg31022942016-03-11 14:18:21 -08002972 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002973 f2_.CreateOffer(opts, answer.get()));
2974 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002975 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002976 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2977
2978 const AudioContentDescription* updated_acd =
2979 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002980 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002981
2982 const VideoContentDescription* updated_vcd =
2983 GetFirstVideoContentDescription(updated_answer.get());
2984
2985 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002986 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002987 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002988 EXPECT_NE(used_pl_type, new_h264_pl_type);
2989 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002990 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002991 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2992 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2993}
2994
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002995// Create an updated offer with RTX after creating an answer to an offer
2996// without RTX, and with different default payload types.
2997// Verify that the added RTX codec references the correct payload type.
2998TEST_F(MediaSessionDescriptionFactoryTest,
2999 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3000 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003001 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003002
3003 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3004 // This creates rtx for H264 with the payload type |f2_| uses.
3005 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003006 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003007
Steve Anton6fe1fba2018-12-11 10:15:23 -08003008 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003009 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003010 std::unique_ptr<SessionDescription> answer =
3011 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003012
3013 const VideoContentDescription* vcd =
3014 GetFirstVideoContentDescription(answer.get());
3015
3016 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3017 EXPECT_EQ(expected_codecs, vcd->codecs());
3018
3019 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
3020 // updated offer, even though the default payload types are different from
3021 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08003022 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003023 f2_.CreateOffer(opts, answer.get()));
3024 ASSERT_TRUE(updated_offer);
3025
3026 const VideoContentDescription* updated_vcd =
3027 GetFirstVideoContentDescription(updated_offer.get());
3028
3029 // New offer should attempt to add H263, and RTX for H264.
3030 expected_codecs.push_back(kVideoCodecs2[1]);
3031 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3032 &expected_codecs);
3033 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3034}
3035
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003036// Test that RTX is ignored when there is no associated payload type parameter.
3037TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3038 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003039 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3040 RtpTransceiverDirection::kRecvOnly, kActive,
3041 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003042 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003043 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07003044 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003045 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003046
3047 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003048 // This creates RTX for H264 with the payload type |f2_| uses.
3049 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003050 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003051
Steve Anton6fe1fba2018-12-11 10:15:23 -08003052 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003053 ASSERT_TRUE(offer.get() != NULL);
3054 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3055 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3056 // is possible to test that that RTX is dropped when
3057 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08003058 MediaContentDescription* media_desc =
3059 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3060 ASSERT_TRUE(media_desc);
3061 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003062 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07003063 for (VideoCodec& codec : codecs) {
3064 if (codec.name.find(cricket::kRtxCodecName) == 0) {
3065 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003066 }
3067 }
3068 desc->set_codecs(codecs);
3069
Steve Anton6fe1fba2018-12-11 10:15:23 -08003070 std::unique_ptr<SessionDescription> answer =
3071 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003072
Steve Anton64b626b2019-01-28 17:25:26 -08003073 EXPECT_THAT(
3074 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3075 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003076}
3077
3078// Test that RTX will be filtered out in the answer if its associated payload
3079// type doesn't match the local value.
3080TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3081 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003082 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3083 RtpTransceiverDirection::kRecvOnly, kActive,
3084 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003085 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3086 // This creates RTX for H264 in sender.
3087 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003088 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003089
3090 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3091 // This creates RTX for H263 in receiver.
3092 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003093 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003094
Steve Anton6fe1fba2018-12-11 10:15:23 -08003095 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003096 ASSERT_TRUE(offer.get() != NULL);
3097 // Associated payload type doesn't match, therefore, RTX codec is removed in
3098 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003099 std::unique_ptr<SessionDescription> answer =
3100 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003101
Steve Anton64b626b2019-01-28 17:25:26 -08003102 EXPECT_THAT(
3103 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3104 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003105}
3106
3107// Test that when multiple RTX codecs are offered, only the matched RTX codec
3108// is added in the answer, and the unsupported RTX codec is filtered out.
3109TEST_F(MediaSessionDescriptionFactoryTest,
3110 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3111 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003112 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3113 RtpTransceiverDirection::kRecvOnly, kActive,
3114 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003115 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3116 // This creates RTX for H264-SVC in sender.
3117 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003118 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003119
3120 // This creates RTX for H264 in sender.
3121 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003122 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003123
3124 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3125 // This creates RTX for H264 in receiver.
3126 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003127 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003128
3129 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3130 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003131 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003132 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003133 std::unique_ptr<SessionDescription> answer =
3134 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003135 const VideoContentDescription* vcd =
3136 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003137 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3138 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3139 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003140
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00003141 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003142}
3143
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003144// Test that after one RTX codec has been negotiated, a new offer can attempt
3145// to add another.
3146TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3147 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003148 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3149 RtpTransceiverDirection::kRecvOnly, kActive,
3150 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003151 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3152 // This creates RTX for H264 for the offerer.
3153 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003154 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003155
Steve Anton6fe1fba2018-12-11 10:15:23 -08003156 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003157 ASSERT_TRUE(offer);
3158 const VideoContentDescription* vcd =
3159 GetFirstVideoContentDescription(offer.get());
3160
3161 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3162 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3163 &expected_codecs);
3164 EXPECT_EQ(expected_codecs, vcd->codecs());
3165
3166 // Now, attempt to add RTX for H264-SVC.
3167 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003168 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003169
kwiberg31022942016-03-11 14:18:21 -08003170 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003171 f1_.CreateOffer(opts, offer.get()));
3172 ASSERT_TRUE(updated_offer);
3173 vcd = GetFirstVideoContentDescription(updated_offer.get());
3174
3175 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3176 &expected_codecs);
3177 EXPECT_EQ(expected_codecs, vcd->codecs());
3178}
3179
Noah Richards2e7a0982015-05-18 14:02:54 -07003180// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3181// generated for each simulcast ssrc and correctly grouped.
3182TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3183 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003184 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3185 RtpTransceiverDirection::kSendRecv, kActive,
3186 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003187 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003188 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3189 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003190
3191 // Use a single real codec, and then add RTX for it.
3192 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003193 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003194 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron3e983682020-03-29 22:17:00 +02003195 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003196
3197 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3198 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003199 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003200 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003201 MediaContentDescription* media_desc =
3202 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3203 ASSERT_TRUE(media_desc);
3204 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003205 const StreamParamsVec& streams = desc->streams();
3206 // Single stream.
3207 ASSERT_EQ(1u, streams.size());
3208 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3209 EXPECT_EQ(6u, streams[0].ssrcs.size());
3210 // And should have a SIM group for the simulcast.
3211 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3212 // And a FID group for RTX.
3213 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003214 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003215 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3216 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003217 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003218 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3219 EXPECT_EQ(3u, fid_ssrcs.size());
3220}
3221
brandtr03d5fb12016-11-22 03:37:59 -08003222// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3223// together with a FEC-FR grouping.
3224TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3225 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003226 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3227 RtpTransceiverDirection::kSendRecv, kActive,
3228 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003229 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003230 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3231 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003232
3233 // Use a single real codec, and then add FlexFEC for it.
3234 std::vector<VideoCodec> f1_codecs;
3235 f1_codecs.push_back(VideoCodec(97, "H264"));
3236 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003237 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003238
3239 // Ensure that the offer has a single FlexFEC ssrc and that
3240 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003241 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003242 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003243 MediaContentDescription* media_desc =
3244 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3245 ASSERT_TRUE(media_desc);
3246 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003247 const StreamParamsVec& streams = desc->streams();
3248 // Single stream.
3249 ASSERT_EQ(1u, streams.size());
3250 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3251 EXPECT_EQ(2u, streams[0].ssrcs.size());
3252 // And should have a FEC-FR group for FlexFEC.
3253 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3254 std::vector<uint32_t> primary_ssrcs;
3255 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3256 ASSERT_EQ(1u, primary_ssrcs.size());
3257 uint32_t flexfec_ssrc;
3258 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3259 EXPECT_NE(flexfec_ssrc, 0u);
3260}
3261
3262// Test that FlexFEC is disabled for simulcast.
3263// TODO(brandtr): Remove this test when we support simulcast, either through
3264// multiple FlexfecSenders, or through multistream protection.
3265TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3266 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003267 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3268 RtpTransceiverDirection::kSendRecv, kActive,
3269 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003270 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003271 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3272 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003273
3274 // Use a single real codec, and then add FlexFEC for it.
3275 std::vector<VideoCodec> f1_codecs;
3276 f1_codecs.push_back(VideoCodec(97, "H264"));
3277 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron3e983682020-03-29 22:17:00 +02003278 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003279
3280 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3281 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003282 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003283 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003284 MediaContentDescription* media_desc =
3285 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3286 ASSERT_TRUE(media_desc);
3287 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003288 const StreamParamsVec& streams = desc->streams();
3289 // Single stream.
3290 ASSERT_EQ(1u, streams.size());
3291 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3292 EXPECT_EQ(3u, streams[0].ssrcs.size());
3293 // And should have a SIM group for the simulcast.
3294 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3295 // And not a FEC-FR group for FlexFEC.
3296 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3297 std::vector<uint32_t> primary_ssrcs;
3298 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3299 EXPECT_EQ(3u, primary_ssrcs.size());
3300 for (uint32_t primary_ssrc : primary_ssrcs) {
3301 uint32_t flexfec_ssrc;
3302 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3303 }
3304}
3305
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003306// Create an updated offer after creating an answer to the original offer and
3307// verify that the RTP header extensions that were part of the original answer
3308// are not changed in the updated offer.
3309TEST_F(MediaSessionDescriptionFactoryTest,
3310 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3311 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003312 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003313
3314 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3315 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3316 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3317 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3318
Steve Anton6fe1fba2018-12-11 10:15:23 -08003319 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3320 std::unique_ptr<SessionDescription> answer =
3321 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003322
Yves Gerey665174f2018-06-19 15:03:05 +02003323 EXPECT_EQ(
3324 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3325 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3326 EXPECT_EQ(
3327 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3328 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003329
kwiberg31022942016-03-11 14:18:21 -08003330 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003331 f2_.CreateOffer(opts, answer.get()));
3332
3333 // The expected RTP header extensions in the new offer are the resulting
3334 // extensions from the first offer/answer exchange plus the extensions only
3335 // |f2_| offer.
3336 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003337 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003338 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003339 kAudioRtpExtensionAnswer[0],
3340 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003341 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003342 };
3343
3344 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003345 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003346 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003347 kVideoRtpExtensionAnswer[0],
3348 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003349 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003350 };
3351
3352 const AudioContentDescription* updated_acd =
3353 GetFirstAudioContentDescription(updated_offer.get());
3354 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3355 updated_acd->rtp_header_extensions());
3356
3357 const VideoContentDescription* updated_vcd =
3358 GetFirstVideoContentDescription(updated_offer.get());
3359 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3360 updated_vcd->rtp_header_extensions());
3361}
3362
deadbeefa5b273a2015-08-20 17:30:13 -07003363// Verify that if the same RTP extension URI is used for audio and video, the
3364// same ID is used. Also verify that the ID isn't changed when creating an
3365// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003366TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003367 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003368 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003369
3370 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3371 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3372
Steve Anton6fe1fba2018-12-11 10:15:23 -08003373 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003374
3375 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3376 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003377 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003378 kVideoRtpExtension3[0],
3379 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003380 };
3381
Yves Gerey665174f2018-06-19 15:03:05 +02003382 EXPECT_EQ(
3383 MAKE_VECTOR(kAudioRtpExtension3),
3384 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3385 EXPECT_EQ(
3386 MAKE_VECTOR(kExpectedVideoRtpExtension),
3387 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003388
3389 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003390 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003391 f1_.CreateOffer(opts, offer.get()));
3392
3393 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003394 GetFirstAudioContentDescription(updated_offer.get())
3395 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003396 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003397 GetFirstVideoContentDescription(updated_offer.get())
3398 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003399}
3400
jbauch5869f502017-06-29 12:31:36 -07003401// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3402TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3403 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003404 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003405
3406 f1_.set_enable_encrypted_rtp_header_extensions(true);
3407 f2_.set_enable_encrypted_rtp_header_extensions(true);
3408
3409 f1_.set_audio_rtp_header_extensions(
3410 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3411 f1_.set_video_rtp_header_extensions(
3412 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3413
Steve Anton6fe1fba2018-12-11 10:15:23 -08003414 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003415
3416 // The extensions that are shared between audio and video should use the same
3417 // id.
3418 const RtpExtension kExpectedVideoRtpExtension[] = {
3419 kVideoRtpExtension3ForEncryption[0],
3420 kAudioRtpExtension3ForEncryptionOffer[1],
3421 kAudioRtpExtension3ForEncryptionOffer[2],
3422 };
3423
Yves Gerey665174f2018-06-19 15:03:05 +02003424 EXPECT_EQ(
3425 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3426 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3427 EXPECT_EQ(
3428 MAKE_VECTOR(kExpectedVideoRtpExtension),
3429 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003430
3431 // Nothing should change when creating a new offer
3432 std::unique_ptr<SessionDescription> updated_offer(
3433 f1_.CreateOffer(opts, offer.get()));
3434
3435 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003436 GetFirstAudioContentDescription(updated_offer.get())
3437 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003438 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003439 GetFirstVideoContentDescription(updated_offer.get())
3440 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003441}
3442
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003443TEST(MediaSessionDescription, CopySessionDescription) {
3444 SessionDescription source;
3445 cricket::ContentGroup group(cricket::CN_AUDIO);
3446 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003447 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003448 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003449 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3450 acd->AddLegacyStream(1);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003451 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
Harald Alvestrand1716d392019-06-03 20:35:45 +02003452 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003453 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003454 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3455 vcd->AddLegacyStream(2);
Harald Alvestrand0fb07f82020-02-27 20:21:37 +01003456 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003457
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003458 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003459 ASSERT_TRUE(copy.get() != NULL);
3460 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3461 const ContentInfo* ac = copy->GetContentByName("audio");
3462 const ContentInfo* vc = copy->GetContentByName("video");
3463 ASSERT_TRUE(ac != NULL);
3464 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003465 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003466 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003467 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3468 EXPECT_EQ(1u, acd->first_ssrc());
3469
Steve Anton5adfafd2017-12-20 16:34:00 -08003470 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003471 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003472 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3473 EXPECT_EQ(2u, vcd->first_ssrc());
3474}
3475
3476// The below TestTransportInfoXXX tests create different offers/answers, and
3477// ensure the TransportInfo in the SessionDescription matches what we expect.
3478TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3479 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003480 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3481 RtpTransceiverDirection::kRecvOnly, kActive,
3482 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003483 TestTransportInfo(true, options, false);
3484}
3485
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003486TEST_F(MediaSessionDescriptionFactoryTest,
3487 TestTransportInfoOfferIceRenomination) {
3488 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003489 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3490 RtpTransceiverDirection::kRecvOnly, kActive,
3491 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003492 options.media_description_options[0]
3493 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003494 TestTransportInfo(true, options, false);
3495}
3496
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003497TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3498 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003499 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3500 RtpTransceiverDirection::kRecvOnly, kActive,
3501 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003502 TestTransportInfo(true, options, true);
3503}
3504
3505TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3506 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003507 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3508 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3509 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003510 TestTransportInfo(true, options, false);
3511}
3512
3513TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003514 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003515 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003516 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3517 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3518 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003519 TestTransportInfo(true, options, true);
3520}
3521
3522TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3523 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003524 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3525 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3526 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003527 options.bundle_enabled = true;
3528 TestTransportInfo(true, options, false);
3529}
3530
3531TEST_F(MediaSessionDescriptionFactoryTest,
3532 TestTransportInfoOfferBundleCurrent) {
3533 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003534 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3535 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3536 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003537 options.bundle_enabled = true;
3538 TestTransportInfo(true, options, true);
3539}
3540
3541TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3542 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003543 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3544 RtpTransceiverDirection::kRecvOnly, kActive,
3545 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003546 TestTransportInfo(false, options, false);
3547}
3548
3549TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003550 TestTransportInfoAnswerIceRenomination) {
3551 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003552 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3553 RtpTransceiverDirection::kRecvOnly, kActive,
3554 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003555 options.media_description_options[0]
3556 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003557 TestTransportInfo(false, options, false);
3558}
3559
3560TEST_F(MediaSessionDescriptionFactoryTest,
3561 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003562 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003563 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3564 RtpTransceiverDirection::kRecvOnly, kActive,
3565 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003566 TestTransportInfo(false, options, true);
3567}
3568
3569TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3570 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003571 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3572 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3573 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003574 TestTransportInfo(false, options, false);
3575}
3576
3577TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003578 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003579 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003580 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3581 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3582 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003583 TestTransportInfo(false, options, true);
3584}
3585
3586TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3587 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003588 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3589 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3590 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003591 options.bundle_enabled = true;
3592 TestTransportInfo(false, options, false);
3593}
3594
3595TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003596 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003597 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003598 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3599 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3600 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003601 options.bundle_enabled = true;
3602 TestTransportInfo(false, options, true);
3603}
3604
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003605TEST_F(MediaSessionDescriptionFactoryTest,
3606 TestTransportInfoOfferBundlesTransportOptions) {
3607 MediaSessionOptions options;
3608 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3609
3610 cricket::OpaqueTransportParameters audio_params;
3611 audio_params.protocol = "audio-transport";
3612 audio_params.parameters = "audio-params";
3613 FindFirstMediaDescriptionByMid("audio", &options)
3614 ->transport_options.opaque_parameters = audio_params;
3615
3616 cricket::OpaqueTransportParameters video_params;
3617 video_params.protocol = "video-transport";
3618 video_params.parameters = "video-params";
3619 FindFirstMediaDescriptionByMid("video", &options)
3620 ->transport_options.opaque_parameters = video_params;
3621
3622 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3623}
3624
3625TEST_F(MediaSessionDescriptionFactoryTest,
3626 TestTransportInfoAnswerBundlesTransportOptions) {
3627 MediaSessionOptions options;
3628 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3629
3630 cricket::OpaqueTransportParameters audio_params;
3631 audio_params.protocol = "audio-transport";
3632 audio_params.parameters = "audio-params";
3633 FindFirstMediaDescriptionByMid("audio", &options)
3634 ->transport_options.opaque_parameters = audio_params;
3635
3636 cricket::OpaqueTransportParameters video_params;
3637 video_params.protocol = "video-transport";
3638 video_params.parameters = "video-params";
3639 FindFirstMediaDescriptionByMid("video", &options)
3640 ->transport_options.opaque_parameters = video_params;
3641
3642 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3643}
3644
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003645TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3646 MediaSessionOptions options;
3647 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3648 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3649 &options);
3650
3651 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3652 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3653 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3654
3655 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3656
3657 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3658 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3659 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3660}
3661
3662TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3663 MediaSessionOptions options;
3664 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3665 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3666 &options);
3667
3668 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3669 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3670 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3671
3672 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3673 std::unique_ptr<SessionDescription> answer =
3674 f1_.CreateAnswer(offer.get(), options, nullptr);
3675
3676 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3677 "foo");
3678 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3679 "bar");
3680 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3681}
3682
3683TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3684 MediaSessionOptions options;
3685 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3686 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3687 &options);
3688
3689 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3690
3691 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3692 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3693 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3694
3695 std::unique_ptr<SessionDescription> answer =
3696 f1_.CreateAnswer(offer.get(), options, nullptr);
3697
3698 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3699 absl::nullopt);
3700 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3701 absl::nullopt);
3702 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3703 absl::nullopt);
3704}
3705
3706TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3707 MediaSessionOptions options;
3708 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3709 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3710 &options);
3711
3712 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3713 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3714 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3715
3716 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3717
3718 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3719 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3720 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3721
3722 std::unique_ptr<SessionDescription> answer =
3723 f1_.CreateAnswer(offer.get(), options, nullptr);
3724
3725 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3726 absl::nullopt);
3727 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3728 absl::nullopt);
3729 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3730 absl::nullopt);
3731}
3732
3733TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3734 MediaSessionOptions options;
3735 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3736 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3737 &options);
3738
3739 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3740 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3741 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3742
3743 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3744
3745 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3746 absl::nullopt;
3747 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3748 absl::nullopt;
3749 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3750 absl::nullopt;
3751
3752 std::unique_ptr<SessionDescription> answer =
3753 f1_.CreateAnswer(offer.get(), options, nullptr);
3754
3755 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3756 absl::nullopt);
3757 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3758 absl::nullopt);
3759 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3760 absl::nullopt);
3761}
3762
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003763// Create an offer with bundle enabled and verify the crypto parameters are
3764// the common set of the available cryptos.
3765TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3766 TestCryptoWithBundle(true);
3767}
3768
3769// Create an answer with bundle enabled and verify the crypto parameters are
3770// the common set of the available cryptos.
3771TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3772 TestCryptoWithBundle(false);
3773}
3774
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003775// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3776// DTLS is not enabled locally.
3777TEST_F(MediaSessionDescriptionFactoryTest,
3778 TestOfferDtlsSavpfWithoutDtlsFailed) {
3779 f1_.set_secure(SEC_ENABLED);
3780 f2_.set_secure(SEC_ENABLED);
3781 tdf1_.set_secure(SEC_DISABLED);
3782 tdf2_.set_secure(SEC_DISABLED);
3783
Steve Anton6fe1fba2018-12-11 10:15:23 -08003784 std::unique_ptr<SessionDescription> offer =
3785 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003786 ASSERT_TRUE(offer.get() != NULL);
3787 ContentInfo* offer_content = offer->GetContentByName("audio");
3788 ASSERT_TRUE(offer_content != NULL);
3789 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003790 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003791 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3792
Steve Anton6fe1fba2018-12-11 10:15:23 -08003793 std::unique_ptr<SessionDescription> answer =
3794 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003795 ASSERT_TRUE(answer != NULL);
3796 ContentInfo* answer_content = answer->GetContentByName("audio");
3797 ASSERT_TRUE(answer_content != NULL);
3798
3799 ASSERT_TRUE(answer_content->rejected);
3800}
3801
3802// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3803// UDP/TLS/RTP/SAVPF.
3804TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3805 f1_.set_secure(SEC_ENABLED);
3806 f2_.set_secure(SEC_ENABLED);
3807 tdf1_.set_secure(SEC_ENABLED);
3808 tdf2_.set_secure(SEC_ENABLED);
3809
Steve Anton6fe1fba2018-12-11 10:15:23 -08003810 std::unique_ptr<SessionDescription> offer =
3811 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003812 ASSERT_TRUE(offer.get() != NULL);
3813 ContentInfo* offer_content = offer->GetContentByName("audio");
3814 ASSERT_TRUE(offer_content != NULL);
3815 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003816 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003817 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3818
Steve Anton6fe1fba2018-12-11 10:15:23 -08003819 std::unique_ptr<SessionDescription> answer =
3820 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003821 ASSERT_TRUE(answer != NULL);
3822
3823 const ContentInfo* answer_content = answer->GetContentByName("audio");
3824 ASSERT_TRUE(answer_content != NULL);
3825 ASSERT_FALSE(answer_content->rejected);
3826
3827 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003828 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003829 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003830}
3831
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003832// Test that we include both SDES and DTLS in the offer, but only include SDES
3833// in the answer if DTLS isn't negotiated.
3834TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3835 f1_.set_secure(SEC_ENABLED);
3836 f2_.set_secure(SEC_ENABLED);
3837 tdf1_.set_secure(SEC_ENABLED);
3838 tdf2_.set_secure(SEC_DISABLED);
3839 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003840 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003841 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003842 const cricket::MediaContentDescription* audio_media_desc;
3843 const cricket::MediaContentDescription* video_media_desc;
3844 const cricket::TransportDescription* audio_trans_desc;
3845 const cricket::TransportDescription* video_trans_desc;
3846
3847 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003848 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003849 ASSERT_TRUE(offer.get() != NULL);
3850
Steve Antonb1c1de12017-12-21 15:14:30 -08003851 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003852 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003853 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003854 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003855 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003856 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3857
3858 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3859 ASSERT_TRUE(audio_trans_desc != NULL);
3860 video_trans_desc = offer->GetTransportDescriptionByName("video");
3861 ASSERT_TRUE(video_trans_desc != NULL);
3862 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3863 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3864
3865 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003866 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003867 ASSERT_TRUE(answer.get() != NULL);
3868
Steve Antonb1c1de12017-12-21 15:14:30 -08003869 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003870 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003871 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003872 ASSERT_TRUE(video_media_desc != NULL);
3873 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3874 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3875
3876 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3877 ASSERT_TRUE(audio_trans_desc != NULL);
3878 video_trans_desc = answer->GetTransportDescriptionByName("video");
3879 ASSERT_TRUE(video_trans_desc != NULL);
3880 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3881 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3882
3883 // Enable DTLS; the answer should now only have DTLS support.
3884 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003885 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003886 ASSERT_TRUE(answer.get() != NULL);
3887
Steve Antonb1c1de12017-12-21 15:14:30 -08003888 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003889 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003890 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003891 ASSERT_TRUE(video_media_desc != NULL);
3892 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3893 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003894 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3895 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003896
3897 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3898 ASSERT_TRUE(audio_trans_desc != NULL);
3899 video_trans_desc = answer->GetTransportDescriptionByName("video");
3900 ASSERT_TRUE(video_trans_desc != NULL);
3901 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3902 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003903
3904 // Try creating offer again. DTLS enabled now, crypto's should be empty
3905 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003906 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003907 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003908 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003909 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003910 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003911 ASSERT_TRUE(video_media_desc != NULL);
3912 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3913 EXPECT_TRUE(video_media_desc->cryptos().empty());
3914
3915 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3916 ASSERT_TRUE(audio_trans_desc != NULL);
3917 video_trans_desc = offer->GetTransportDescriptionByName("video");
3918 ASSERT_TRUE(video_trans_desc != NULL);
3919 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3920 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003921}
3922
3923// Test that an answer can't be created if cryptos are required but the offer is
3924// unsecure.
3925TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003926 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003927 f1_.set_secure(SEC_DISABLED);
3928 tdf1_.set_secure(SEC_DISABLED);
3929 f2_.set_secure(SEC_REQUIRED);
3930 tdf1_.set_secure(SEC_ENABLED);
3931
Steve Anton6fe1fba2018-12-11 10:15:23 -08003932 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003933 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003934 std::unique_ptr<SessionDescription> answer =
3935 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003936 EXPECT_TRUE(answer.get() == NULL);
3937}
3938
3939// Test that we accept a DTLS offer without SDES and create an appropriate
3940// answer.
3941TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3942 f1_.set_secure(SEC_DISABLED);
3943 f2_.set_secure(SEC_ENABLED);
3944 tdf1_.set_secure(SEC_ENABLED);
3945 tdf2_.set_secure(SEC_ENABLED);
3946 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003947 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3948 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3949 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003950
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003951 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003952 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003953 ASSERT_TRUE(offer.get() != NULL);
3954
3955 const AudioContentDescription* audio_offer =
3956 GetFirstAudioContentDescription(offer.get());
3957 ASSERT_TRUE(audio_offer->cryptos().empty());
3958 const VideoContentDescription* video_offer =
3959 GetFirstVideoContentDescription(offer.get());
3960 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003961 const RtpDataContentDescription* data_offer =
3962 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003963 ASSERT_TRUE(data_offer->cryptos().empty());
3964
3965 const cricket::TransportDescription* audio_offer_trans_desc =
3966 offer->GetTransportDescriptionByName("audio");
3967 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3968 const cricket::TransportDescription* video_offer_trans_desc =
3969 offer->GetTransportDescriptionByName("video");
3970 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3971 const cricket::TransportDescription* data_offer_trans_desc =
3972 offer->GetTransportDescriptionByName("data");
3973 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3974
3975 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003976 std::unique_ptr<SessionDescription> answer =
3977 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003978 ASSERT_TRUE(answer.get() != NULL);
3979
3980 const cricket::TransportDescription* audio_answer_trans_desc =
3981 answer->GetTransportDescriptionByName("audio");
3982 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3983 const cricket::TransportDescription* video_answer_trans_desc =
3984 answer->GetTransportDescriptionByName("video");
3985 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3986 const cricket::TransportDescription* data_answer_trans_desc =
3987 answer->GetTransportDescriptionByName("data");
3988 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3989}
3990
3991// Verifies if vad_enabled option is set to false, CN codecs are not present in
3992// offer or answer.
3993TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3994 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003995 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003996 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003997 ASSERT_TRUE(offer.get() != NULL);
3998 const ContentInfo* audio_content = offer->GetContentByName("audio");
3999 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
4000
4001 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08004002 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004003 ASSERT_TRUE(offer.get() != NULL);
4004 audio_content = offer->GetContentByName("audio");
4005 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08004006 std::unique_ptr<SessionDescription> answer =
4007 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004008 ASSERT_TRUE(answer.get() != NULL);
4009 audio_content = answer->GetContentByName("audio");
4010 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
4011}
deadbeef44f08192015-12-15 16:20:09 -08004012
zhihuang1c378ed2017-08-17 14:10:50 -07004013// Test that the generated MIDs match the existing offer.
4014TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08004015 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004016 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
4017 RtpTransceiverDirection::kRecvOnly, kActive,
4018 &opts);
4019 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
4020 RtpTransceiverDirection::kRecvOnly, kActive,
4021 &opts);
deadbeef44f08192015-12-15 16:20:09 -08004022 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004023 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
4024 RtpTransceiverDirection::kSendRecv, kActive,
4025 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004026 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004027 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08004028 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08004029 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07004030
deadbeef44f08192015-12-15 16:20:09 -08004031 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
4032 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
4033 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
4034 ASSERT_TRUE(audio_content != nullptr);
4035 ASSERT_TRUE(video_content != nullptr);
4036 ASSERT_TRUE(data_content != nullptr);
4037 EXPECT_EQ("audio_modified", audio_content->name);
4038 EXPECT_EQ("video_modified", video_content->name);
4039 EXPECT_EQ("data_modified", data_content->name);
4040}
zhihuangcf5b37c2016-05-05 11:44:35 -07004041
zhihuang1c378ed2017-08-17 14:10:50 -07004042// The following tests verify that the unified plan SDP is supported.
4043// Test that we can create an offer with multiple media sections of same media
4044// type.
4045TEST_F(MediaSessionDescriptionFactoryTest,
4046 CreateOfferWithMultipleAVMediaSections) {
4047 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004048 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4049 RtpTransceiverDirection::kSendRecv, kActive,
4050 &opts);
4051 AttachSenderToMediaDescriptionOptions(
4052 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004053
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004054 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4055 RtpTransceiverDirection::kSendRecv, kActive,
4056 &opts);
4057 AttachSenderToMediaDescriptionOptions(
4058 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004059
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004060 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4061 RtpTransceiverDirection::kSendRecv, kActive,
4062 &opts);
4063 AttachSenderToMediaDescriptionOptions(
4064 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004065
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004066 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4067 RtpTransceiverDirection::kSendRecv, kActive,
4068 &opts);
4069 AttachSenderToMediaDescriptionOptions(
4070 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004071 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004072 ASSERT_TRUE(offer);
4073
4074 ASSERT_EQ(4u, offer->contents().size());
4075 EXPECT_FALSE(offer->contents()[0].rejected);
4076 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004077 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004078 ASSERT_EQ(1u, acd->streams().size());
4079 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004080 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004081
4082 EXPECT_FALSE(offer->contents()[1].rejected);
4083 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004084 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004085 ASSERT_EQ(1u, vcd->streams().size());
4086 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004087 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004088
4089 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004090 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004091 ASSERT_EQ(1u, acd->streams().size());
4092 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004093 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004094
4095 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004096 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004097 ASSERT_EQ(1u, vcd->streams().size());
4098 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004099 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004100}
4101
4102// Test that we can create an answer with multiple media sections of same media
4103// type.
4104TEST_F(MediaSessionDescriptionFactoryTest,
4105 CreateAnswerWithMultipleAVMediaSections) {
4106 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004107 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4108 RtpTransceiverDirection::kSendRecv, kActive,
4109 &opts);
4110 AttachSenderToMediaDescriptionOptions(
4111 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004112
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004113 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4114 RtpTransceiverDirection::kSendRecv, kActive,
4115 &opts);
4116 AttachSenderToMediaDescriptionOptions(
4117 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004118
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004119 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4120 RtpTransceiverDirection::kSendRecv, kActive,
4121 &opts);
4122 AttachSenderToMediaDescriptionOptions(
4123 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004124
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004125 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4126 RtpTransceiverDirection::kSendRecv, kActive,
4127 &opts);
4128 AttachSenderToMediaDescriptionOptions(
4129 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004130
Steve Anton6fe1fba2018-12-11 10:15:23 -08004131 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004132 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004133 std::unique_ptr<SessionDescription> answer =
4134 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004135
4136 ASSERT_EQ(4u, answer->contents().size());
4137 EXPECT_FALSE(answer->contents()[0].rejected);
4138 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004139 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004140 ASSERT_EQ(1u, acd->streams().size());
4141 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004142 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004143
4144 EXPECT_FALSE(answer->contents()[1].rejected);
4145 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08004146 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004147 ASSERT_EQ(1u, vcd->streams().size());
4148 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004149 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004150
4151 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004152 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004153 ASSERT_EQ(1u, acd->streams().size());
4154 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004155 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004156
4157 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004158 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004159 ASSERT_EQ(1u, vcd->streams().size());
4160 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004161 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004162}
4163
4164// Test that the media section will be rejected in offer if the corresponding
4165// MediaDescriptionOptions is stopped by the offerer.
4166TEST_F(MediaSessionDescriptionFactoryTest,
4167 CreateOfferWithMediaSectionStoppedByOfferer) {
4168 // Create an offer with two audio sections and one of them is stopped.
4169 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004170 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4171 RtpTransceiverDirection::kSendRecv, kActive,
4172 &offer_opts);
4173 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4174 RtpTransceiverDirection::kInactive, kStopped,
4175 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004176 std::unique_ptr<SessionDescription> offer =
4177 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004178 ASSERT_TRUE(offer);
4179 ASSERT_EQ(2u, offer->contents().size());
4180 EXPECT_FALSE(offer->contents()[0].rejected);
4181 EXPECT_TRUE(offer->contents()[1].rejected);
4182}
4183
4184// Test that the media section will be rejected in answer if the corresponding
4185// MediaDescriptionOptions is stopped by the offerer.
4186TEST_F(MediaSessionDescriptionFactoryTest,
4187 CreateAnswerWithMediaSectionStoppedByOfferer) {
4188 // Create an offer with two audio sections and one of them is stopped.
4189 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004190 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4191 RtpTransceiverDirection::kSendRecv, kActive,
4192 &offer_opts);
4193 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4194 RtpTransceiverDirection::kInactive, kStopped,
4195 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004196 std::unique_ptr<SessionDescription> offer =
4197 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004198 ASSERT_TRUE(offer);
4199 ASSERT_EQ(2u, offer->contents().size());
4200 EXPECT_FALSE(offer->contents()[0].rejected);
4201 EXPECT_TRUE(offer->contents()[1].rejected);
4202
4203 // Create an answer based on the offer.
4204 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004205 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4206 RtpTransceiverDirection::kSendRecv, kActive,
4207 &answer_opts);
4208 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4209 RtpTransceiverDirection::kSendRecv, kActive,
4210 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004211 std::unique_ptr<SessionDescription> answer =
4212 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004213 ASSERT_EQ(2u, answer->contents().size());
4214 EXPECT_FALSE(answer->contents()[0].rejected);
4215 EXPECT_TRUE(answer->contents()[1].rejected);
4216}
4217
4218// Test that the media section will be rejected in answer if the corresponding
4219// MediaDescriptionOptions is stopped by the answerer.
4220TEST_F(MediaSessionDescriptionFactoryTest,
4221 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4222 // Create an offer with two audio sections.
4223 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004224 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4225 RtpTransceiverDirection::kSendRecv, kActive,
4226 &offer_opts);
4227 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4228 RtpTransceiverDirection::kSendRecv, kActive,
4229 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004230 std::unique_ptr<SessionDescription> offer =
4231 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004232 ASSERT_TRUE(offer);
4233 ASSERT_EQ(2u, offer->contents().size());
4234 ASSERT_FALSE(offer->contents()[0].rejected);
4235 ASSERT_FALSE(offer->contents()[1].rejected);
4236
4237 // The answerer rejects one of the audio sections.
4238 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004239 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4240 RtpTransceiverDirection::kSendRecv, kActive,
4241 &answer_opts);
4242 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4243 RtpTransceiverDirection::kInactive, kStopped,
4244 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004245 std::unique_ptr<SessionDescription> answer =
4246 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004247 ASSERT_EQ(2u, answer->contents().size());
4248 EXPECT_FALSE(answer->contents()[0].rejected);
4249 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004250
4251 // The TransportInfo of the rejected m= section is expected to be added in the
4252 // answer.
4253 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004254}
4255
4256// Test the generated media sections has the same order of the
4257// corresponding MediaDescriptionOptions.
4258TEST_F(MediaSessionDescriptionFactoryTest,
4259 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4260 MediaSessionOptions opts;
4261 // This tests put video section first because normally audio comes first by
4262 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004263 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4264 RtpTransceiverDirection::kSendRecv, kActive,
4265 &opts);
4266 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4267 RtpTransceiverDirection::kSendRecv, kActive,
4268 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004269 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004270
4271 ASSERT_TRUE(offer);
4272 ASSERT_EQ(2u, offer->contents().size());
4273 EXPECT_EQ("video", offer->contents()[0].name);
4274 EXPECT_EQ("audio", offer->contents()[1].name);
4275}
4276
4277// Test that different media sections using the same codec have same payload
4278// type.
4279TEST_F(MediaSessionDescriptionFactoryTest,
4280 PayloadTypesSharedByMediaSectionsOfSameType) {
4281 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004282 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4283 RtpTransceiverDirection::kSendRecv, kActive,
4284 &opts);
4285 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4286 RtpTransceiverDirection::kSendRecv, kActive,
4287 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004288 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004289 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004290 ASSERT_TRUE(offer);
4291 ASSERT_EQ(2u, offer->contents().size());
4292 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004293 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004294 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004295 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004296 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4297 ASSERT_EQ(2u, vcd1->codecs().size());
4298 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4299 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4300 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4301 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4302
4303 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004304 std::unique_ptr<SessionDescription> answer =
4305 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004306 ASSERT_TRUE(answer);
4307 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004308 vcd1 = answer->contents()[0].media_description()->as_video();
4309 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004310 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4311 ASSERT_EQ(1u, vcd1->codecs().size());
4312 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4313 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4314}
4315
4316// Test that the codec preference order per media section is respected in
4317// subsequent offer.
4318TEST_F(MediaSessionDescriptionFactoryTest,
4319 CreateOfferRespectsCodecPreferenceOrder) {
4320 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004321 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4322 RtpTransceiverDirection::kSendRecv, kActive,
4323 &opts);
4324 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4325 RtpTransceiverDirection::kSendRecv, kActive,
4326 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004327 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004328 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004329 ASSERT_TRUE(offer);
4330 ASSERT_EQ(2u, offer->contents().size());
4331 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004332 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004333 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004334 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004335 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4336 EXPECT_EQ(video_codecs, vcd1->codecs());
4337 EXPECT_EQ(video_codecs, vcd2->codecs());
4338
4339 // Change the codec preference of the first video section and create a
4340 // follow-up offer.
4341 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4342 vcd1->set_codecs(video_codecs_reverse);
4343 std::unique_ptr<SessionDescription> updated_offer(
4344 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004345 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4346 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004347 // The video codec preference order should be respected.
4348 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4349 EXPECT_EQ(video_codecs, vcd2->codecs());
4350}
4351
4352// Test that the codec preference order per media section is respected in
4353// the answer.
4354TEST_F(MediaSessionDescriptionFactoryTest,
4355 CreateAnswerRespectsCodecPreferenceOrder) {
4356 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004357 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4358 RtpTransceiverDirection::kSendRecv, kActive,
4359 &opts);
4360 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4361 RtpTransceiverDirection::kSendRecv, kActive,
4362 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004363 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004364 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004365 ASSERT_TRUE(offer);
4366 ASSERT_EQ(2u, offer->contents().size());
4367 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004368 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004369 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004370 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004371 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4372 EXPECT_EQ(video_codecs, vcd1->codecs());
4373 EXPECT_EQ(video_codecs, vcd2->codecs());
4374
4375 // Change the codec preference of the first video section and create an
4376 // answer.
4377 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4378 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004379 std::unique_ptr<SessionDescription> answer =
4380 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004381 vcd1 = answer->contents()[0].media_description()->as_video();
4382 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004383 // The video codec preference order should be respected.
4384 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4385 EXPECT_EQ(video_codecs, vcd2->codecs());
4386}
4387
Zhi Huang6f367472017-11-22 13:20:02 -08004388// Test that when creating an answer, the codecs use local parameters instead of
4389// the remote ones.
4390TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4391 const std::string audio_param_name = "audio_param";
4392 const std::string audio_value1 = "audio_v1";
4393 const std::string audio_value2 = "audio_v2";
4394 const std::string video_param_name = "video_param";
4395 const std::string video_value1 = "video_v1";
4396 const std::string video_value2 = "video_v2";
4397
4398 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4399 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4400 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4401 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4402
4403 // Set the parameters for codecs.
4404 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4405 video_codecs1[0].SetParam(video_param_name, video_value1);
4406 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4407 video_codecs2[0].SetParam(video_param_name, video_value2);
4408
4409 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron3e983682020-03-29 22:17:00 +02004410 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004411 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron3e983682020-03-29 22:17:00 +02004412 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004413
4414 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004415 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4416 RtpTransceiverDirection::kSendRecv, kActive,
4417 &opts);
4418 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4419 RtpTransceiverDirection::kSendRecv, kActive,
4420 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004421
Steve Anton6fe1fba2018-12-11 10:15:23 -08004422 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004423 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004424 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4425 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004426 std::string value;
4427 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4428 EXPECT_EQ(audio_value1, value);
4429 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4430 EXPECT_EQ(video_value1, value);
4431
Steve Anton6fe1fba2018-12-11 10:15:23 -08004432 std::unique_ptr<SessionDescription> answer =
4433 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004434 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004435 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4436 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004437 // Use the parameters from the local codecs.
4438 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4439 EXPECT_EQ(audio_value2, value);
4440 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4441 EXPECT_EQ(video_value2, value);
4442}
4443
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004444// Test that matching packetization-mode is part of the criteria for matching
4445// H264 codecs (in addition to profile-level-id). Previously, this was not the
4446// case, so the first H264 codec with the same profile-level-id would match and
4447// the payload type in the answer would be incorrect.
4448// This is a regression test for bugs.webrtc.org/8808
4449TEST_F(MediaSessionDescriptionFactoryTest,
4450 H264MatchCriteriaIncludesPacketizationMode) {
4451 // Create two H264 codecs with the same profile level ID and different
4452 // packetization modes.
4453 VideoCodec h264_pm0(96, "H264");
4454 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4455 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4456 VideoCodec h264_pm1(97, "H264");
4457 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4458 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4459
4460 // Offerer will send both codecs, answerer should choose the one with matching
4461 // packetization mode (and not the first one it sees).
Johannes Kron3e983682020-03-29 22:17:00 +02004462 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4463 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004464
4465 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004466 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4467 RtpTransceiverDirection::kSendRecv, kActive,
4468 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004469
Steve Anton6fe1fba2018-12-11 10:15:23 -08004470 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004471 ASSERT_TRUE(offer);
4472
Steve Anton6fe1fba2018-12-11 10:15:23 -08004473 std::unique_ptr<SessionDescription> answer =
4474 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004475 ASSERT_TRUE(answer);
4476
4477 // Answer should have one negotiated codec with packetization-mode=1 using the
4478 // offered payload type.
4479 ASSERT_EQ(1u, answer->contents().size());
4480 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4481 ASSERT_EQ(1u, answer_vcd->codecs().size());
4482 auto answer_codec = answer_vcd->codecs()[0];
4483 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4484}
4485
zhihuangcf5b37c2016-05-05 11:44:35 -07004486class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4487 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004488 MediaProtocolTest()
4489 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004490 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4491 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron3e983682020-03-29 22:17:00 +02004492 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4493 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004494 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004495 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4496 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron3e983682020-03-29 22:17:00 +02004497 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4498 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004499 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004500 f1_.set_secure(SEC_ENABLED);
4501 f2_.set_secure(SEC_ENABLED);
4502 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004503 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004504 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004505 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004506 tdf1_.set_secure(SEC_ENABLED);
4507 tdf2_.set_secure(SEC_ENABLED);
4508 }
4509
4510 protected:
4511 MediaSessionDescriptionFactory f1_;
4512 MediaSessionDescriptionFactory f2_;
4513 TransportDescriptionFactory tdf1_;
4514 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004515 UniqueRandomIdGenerator ssrc_generator1;
4516 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004517};
4518
4519TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4520 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004521 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004522 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004523 ASSERT_TRUE(offer.get() != nullptr);
4524 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004525 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004526 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004527 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004528 std::unique_ptr<SessionDescription> answer =
4529 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004530 const ContentInfo* ac = answer->GetContentByName("audio");
4531 const ContentInfo* vc = answer->GetContentByName("video");
4532 ASSERT_TRUE(ac != nullptr);
4533 ASSERT_TRUE(vc != nullptr);
4534 EXPECT_FALSE(ac->rejected); // the offer is accepted
4535 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004536 const AudioContentDescription* acd = ac->media_description()->as_audio();
4537 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004538 EXPECT_EQ(GetParam(), acd->protocol());
4539 EXPECT_EQ(GetParam(), vcd->protocol());
4540}
4541
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004542INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4543 MediaProtocolTest,
4544 ::testing::ValuesIn(kMediaProtocols));
4545INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4546 MediaProtocolTest,
4547 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004548
4549TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4550 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004551 UniqueRandomIdGenerator ssrc_generator;
4552 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004553 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4554 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4555
4556 // The merged list of codecs should contain any send codecs that are also
4557 // nominally in the recieve codecs list. Payload types should be picked from
4558 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4559 // (set to 1). This equals what happens when the send codecs are used in an
4560 // offer and the receive codecs are used in the following answer.
4561 const std::vector<AudioCodec> sendrecv_codecs =
4562 MAKE_VECTOR(kAudioCodecsAnswer);
4563 const std::vector<AudioCodec> no_codecs;
4564
4565 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4566 << "Please don't change shared test data!";
4567 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4568 << "Please don't change shared test data!";
4569 // Alter iLBC send codec to have zero channels, to test that that is handled
4570 // properly.
4571 send_codecs[1].channels = 0;
4572
4573 // Alther iLBC receive codec to be lowercase, to test that case conversions
4574 // are handled properly.
4575 recv_codecs[2].name = "ilbc";
4576
4577 // Test proper merge
4578 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004579 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4580 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4581 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004582
4583 // Test empty send codecs list
4584 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004585 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4586 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4587 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004588
4589 // Test empty recv codecs list
4590 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004591 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4592 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4593 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004594
4595 // Test all empty codec lists
4596 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004597 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4598 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4599 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004600}
4601
4602namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004603// Compare the two vectors of codecs ignoring the payload type.
4604template <class Codec>
4605bool CodecsMatch(const std::vector<Codec>& codecs1,
4606 const std::vector<Codec>& codecs2) {
4607 if (codecs1.size() != codecs2.size()) {
4608 return false;
4609 }
4610
4611 for (size_t i = 0; i < codecs1.size(); ++i) {
4612 if (!codecs1[i].Matches(codecs2[i])) {
4613 return false;
4614 }
4615 }
4616 return true;
4617}
4618
Steve Anton4e70a722017-11-28 14:57:10 -08004619void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004620 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004621 UniqueRandomIdGenerator ssrc_generator;
4622 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004623 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4624 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4625 const std::vector<AudioCodec> sendrecv_codecs =
4626 MAKE_VECTOR(kAudioCodecsAnswer);
4627 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004628
4629 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004630 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4631 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004632
Steve Anton4e70a722017-11-28 14:57:10 -08004633 if (direction == RtpTransceiverDirection::kSendRecv ||
4634 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004635 AttachSenderToMediaDescriptionOptions(
4636 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004637 }
ossu075af922016-06-14 03:29:38 -07004638
Steve Anton6fe1fba2018-12-11 10:15:23 -08004639 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004640 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004641 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004642
4643 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004644 // that the codecs put in are right. This happens when we neither want to
4645 // send nor receive audio. The checks are still in place if at some point
4646 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004647 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004648 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004649 // sendrecv and inactive should both present lists as if the channel was
4650 // to be used for sending and receiving. Inactive essentially means it
4651 // might eventually be used anything, but we don't know more at this
4652 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004653 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004654 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004655 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004656 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004657 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004658 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004659 }
4660 }
4661}
4662
4663static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004664 AudioCodec(0, "codec0", 16000, -1, 1),
4665 AudioCodec(1, "codec1", 8000, 13300, 1),
4666 AudioCodec(2, "codec2", 8000, 64000, 1),
4667 AudioCodec(3, "codec3", 8000, 64000, 1),
4668 AudioCodec(4, "codec4", 8000, 0, 2),
4669 AudioCodec(5, "codec5", 32000, 0, 1),
4670 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004671
zhihuang1c378ed2017-08-17 14:10:50 -07004672/* The codecs groups below are chosen as per the matrix below. The objective
4673 * is to have different sets of codecs in the inputs, to get unique sets of
4674 * codecs after negotiation, depending on offer and answer communication
4675 * directions. One-way directions in the offer should either result in the
4676 * opposite direction in the answer, or an inactive answer. Regardless, the
4677 * choice of codecs should be as if the answer contained the opposite
4678 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004679 *
4680 * | Offer | Answer | Result
4681 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4682 * 0 | x - - | - x - | x - - - -
4683 * 1 | x x x | - x - | x - - x -
4684 * 2 | - x - | x - - | - x - - -
4685 * 3 | x x x | x - - | - x x - -
4686 * 4 | - x - | x x x | - x - - -
4687 * 5 | x - - | x x x | x - - - -
4688 * 6 | x x x | x x x | x x x x x
4689 */
4690// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004691static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4692static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004693// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4694// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004695static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4696static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004697// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004698static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4699static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4700static const int kResultSendrecv_SendCodecs[] = {3, 6};
4701static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4702static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004703
4704template <typename T, int IDXS>
4705std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4706 std::vector<T> out;
4707 out.reserve(IDXS);
4708 for (int idx : indices)
4709 out.push_back(array[idx]);
4710
4711 return out;
4712}
4713
Steve Anton4e70a722017-11-28 14:57:10 -08004714void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4715 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004716 bool add_legacy_stream) {
4717 TransportDescriptionFactory offer_tdf;
4718 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004719 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4720 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4721 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004722 offer_factory.set_audio_codecs(
4723 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4724 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4725 answer_factory.set_audio_codecs(
4726 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4727 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4728
ossu075af922016-06-14 03:29:38 -07004729 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004730 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4731 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004732
Steve Anton4e70a722017-11-28 14:57:10 -08004733 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004734 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4735 kAudioTrack1, {kMediaStream1}, 1,
4736 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004737 }
4738
Steve Anton6fe1fba2018-12-11 10:15:23 -08004739 std::unique_ptr<SessionDescription> offer =
4740 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004741 ASSERT_TRUE(offer.get() != NULL);
4742
4743 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004744 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4745 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004746
Steve Anton4e70a722017-11-28 14:57:10 -08004747 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004748 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4749 kAudioTrack1, {kMediaStream1}, 1,
4750 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004751 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004752 std::unique_ptr<SessionDescription> answer =
4753 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004754 const ContentInfo* ac = answer->GetContentByName("audio");
4755
zhihuang1c378ed2017-08-17 14:10:50 -07004756 // If the factory didn't add any audio content to the answer, we cannot
4757 // check that the codecs put in are right. This happens when we neither want
4758 // to send nor receive audio. The checks are still in place if at some point
4759 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004760 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004761 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4762 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004763
ossu075af922016-06-14 03:29:38 -07004764 std::vector<AudioCodec> target_codecs;
4765 // For offers with sendrecv or inactive, we should never reply with more
4766 // codecs than offered, with these codec sets.
4767 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004768 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004769 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4770 kResultSendrecv_SendrecvCodecs);
4771 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004772 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004773 target_codecs =
4774 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004775 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004776 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004777 target_codecs =
4778 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004779 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004780 case RtpTransceiverDirection::kSendRecv:
4781 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004782 target_codecs =
4783 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004784 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004785 target_codecs =
4786 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004787 } else {
4788 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4789 kResultSendrecv_SendrecvCodecs);
4790 }
4791 break;
Markus Handell45c104b2020-03-11 10:51:13 +01004792 default:
4793 RTC_NOTREACHED();
ossu075af922016-06-14 03:29:38 -07004794 }
4795
zhihuang1c378ed2017-08-17 14:10:50 -07004796 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004797 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004798 bool first = true;
4799 os << "{";
4800 for (const auto& c : codecs) {
4801 os << (first ? " " : ", ") << c.id;
4802 first = false;
4803 }
4804 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004805 return os.Release();
ossu075af922016-06-14 03:29:38 -07004806 };
4807
4808 EXPECT_TRUE(acd->codecs() == target_codecs)
4809 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004810 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4811 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004812 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004813 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4814 << "; got: "
4815 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004816 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004817 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004818 << "Only inactive offers are allowed to not generate any audio "
4819 "content";
ossu075af922016-06-14 03:29:38 -07004820 }
4821}
brandtr03d5fb12016-11-22 03:37:59 -08004822
4823} // namespace
ossu075af922016-06-14 03:29:38 -07004824
4825class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004826 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004827
4828TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004829 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004830}
4831
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004832INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4833 AudioCodecsOfferTest,
4834 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4835 RtpTransceiverDirection::kRecvOnly,
4836 RtpTransceiverDirection::kSendRecv,
4837 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004838
4839class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004840 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4841 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004842 bool>> {};
ossu075af922016-06-14 03:29:38 -07004843
4844TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004845 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4846 ::testing::get<1>(GetParam()),
4847 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004848}
4849
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004850INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004851 MediaSessionDescriptionFactoryTest,
4852 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004853 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4854 RtpTransceiverDirection::kRecvOnly,
4855 RtpTransceiverDirection::kSendRecv,
4856 RtpTransceiverDirection::kInactive),
4857 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4858 RtpTransceiverDirection::kRecvOnly,
4859 RtpTransceiverDirection::kSendRecv,
4860 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004861 ::testing::Bool()));