blob: b14e14c936cd0c2cf825b98a4f942bf73f2c2e23 [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
Amit Hilbuch77938e62018-12-21 09:23:38 -080011#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080012#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000013#include <string>
14#include <vector>
15
Steve Anton64b626b2019-01-28 17:25:26 -080016#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080017#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020020#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "p2p/base/p2p_constants.h"
22#include "p2p/base/transport_description.h"
23#include "p2p/base/transport_info.h"
24#include "pc/media_session.h"
25#include "pc/rtp_media_utils.h"
26#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/message_digest.h"
31#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020032#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080033#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080034#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035
Yves Gerey665174f2018-06-19 15:03:05 +020036#define ASSERT_CRYPTO(cd, s, cs) \
37 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080038 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
40typedef std::vector<cricket::Candidate> Candidates;
41
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080042using cricket::AudioCodec;
43using cricket::AudioContentDescription;
44using cricket::ContentInfo;
45using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080046using cricket::GetFirstAudioContent;
47using cricket::GetFirstAudioContentDescription;
48using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020049using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080050using cricket::GetFirstVideoContent;
51using cricket::GetFirstVideoContentDescription;
52using cricket::kAutoBandwidth;
53using cricket::MEDIA_TYPE_AUDIO;
54using cricket::MEDIA_TYPE_DATA;
55using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070057using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080058using cricket::MediaProtocolType;
59using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::MediaSessionOptions;
61using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080062using cricket::RidDescription;
63using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020064using cricket::RtpDataCodec;
65using cricket::RtpDataContentDescription;
66using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080067using cricket::SEC_DISABLED;
68using cricket::SEC_ENABLED;
69using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080071using cricket::SimulcastDescription;
72using cricket::SimulcastLayer;
73using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074using cricket::SsrcGroup;
75using cricket::StreamParams;
76using cricket::StreamParamsVec;
77using cricket::TransportDescription;
78using cricket::TransportDescriptionFactory;
79using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080081using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070082using rtc::CS_AEAD_AES_128_GCM;
83using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080084using rtc::CS_AES_CM_128_HMAC_SHA1_32;
85using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080086using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020087using ::testing::Contains;
88using ::testing::Each;
89using ::testing::ElementsAreArray;
90using ::testing::Eq;
91using ::testing::Field;
92using ::testing::IsEmpty;
93using ::testing::IsFalse;
94using ::testing::Ne;
95using ::testing::Not;
96using ::testing::Pointwise;
97using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070098using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080099using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100
101static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700102 AudioCodec(103, "ISAC", 16000, -1, 1),
103 AudioCodec(102, "iLBC", 8000, 13300, 1),
104 AudioCodec(0, "PCMU", 8000, 64000, 1),
105 AudioCodec(8, "PCMA", 8000, 64000, 1),
106 AudioCodec(117, "red", 8000, 0, 1),
107 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108
109static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200110 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700111 AudioCodec(0, "PCMU", 8000, 64000, 1),
112 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113};
114
115static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700116 AudioCodec(102, "iLBC", 8000, 13300, 1),
117 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118};
119
perkj26752742016-10-24 01:21:16 -0700120static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
121 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122
zhihuang1c378ed2017-08-17 14:10:50 -0700123static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
124 VideoCodec(96, "H264-SVC")};
125
perkj26752742016-10-24 01:21:16 -0700126static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
127 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128
perkj26752742016-10-24 01:21:16 -0700129static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200131static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
132 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200134static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
135 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200137static const RtpDataCodec kDataCodecsAnswer[] = {
138 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
isheriff6f8d6862016-05-26 11:24:55 -0700140static const RtpExtension kAudioRtpExtension1[] = {
141 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
142 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143};
144
jbauch5869f502017-06-29 12:31:36 -0700145static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
146 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
147 RtpExtension("http://google.com/testing/audio_something", 10),
148 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
149};
150
isheriff6f8d6862016-05-26 11:24:55 -0700151static const RtpExtension kAudioRtpExtension2[] = {
152 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
153 RtpExtension("http://google.com/testing/audio_something_else", 8),
154 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155};
156
isheriff6f8d6862016-05-26 11:24:55 -0700157static const RtpExtension kAudioRtpExtension3[] = {
158 RtpExtension("http://google.com/testing/audio_something", 2),
159 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700160};
161
jbauch5869f502017-06-29 12:31:36 -0700162static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
163 RtpExtension("http://google.com/testing/audio_something", 2),
164 // Use RTP extension that supports encryption.
165 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
166};
167
168static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
169 RtpExtension("http://google.com/testing/audio_something", 2),
170 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
171 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
172};
173
isheriff6f8d6862016-05-26 11:24:55 -0700174static const RtpExtension kAudioRtpExtensionAnswer[] = {
175 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176};
177
jbauch5869f502017-06-29 12:31:36 -0700178static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
179 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
180};
181
isheriff6f8d6862016-05-26 11:24:55 -0700182static const RtpExtension kVideoRtpExtension1[] = {
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
184 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000185};
186
jbauch5869f502017-06-29 12:31:36 -0700187static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
188 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
189 RtpExtension("http://google.com/testing/video_something", 13),
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
191};
192
isheriff6f8d6862016-05-26 11:24:55 -0700193static const RtpExtension kVideoRtpExtension2[] = {
194 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
195 RtpExtension("http://google.com/testing/video_something_else", 14),
196 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197};
198
isheriff6f8d6862016-05-26 11:24:55 -0700199static const RtpExtension kVideoRtpExtension3[] = {
200 RtpExtension("http://google.com/testing/video_something", 4),
201 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700202};
203
jbauch5869f502017-06-29 12:31:36 -0700204static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
205 RtpExtension("http://google.com/testing/video_something", 4),
206 // Use RTP extension that supports encryption.
207 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
208};
209
isheriff6f8d6862016-05-26 11:24:55 -0700210static const RtpExtension kVideoRtpExtensionAnswer[] = {
211 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212};
213
jbauch5869f502017-06-29 12:31:36 -0700214static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
215 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
216};
217
Johannes Kronce8e8672019-02-22 13:06:44 +0100218static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
219 RtpExtension("http://www.ietf.org/id/"
220 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
221 1),
222};
223
224static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
225 RtpExtension("http://www.ietf.org/id/"
226 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
227 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100228 RtpExtension(
229 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
230 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100231};
232
233static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100234 RtpExtension(
235 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
236 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100237};
238
Peter Boström0c4e06b2015-10-07 12:23:21 +0200239static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
240static const uint32_t kSimSsrc[] = {10, 20, 30};
241static const uint32_t kFec1Ssrc[] = {10, 11};
242static const uint32_t kFec2Ssrc[] = {20, 21};
243static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244
245static const char kMediaStream1[] = "stream_1";
246static const char kMediaStream2[] = "stream_2";
247static const char kVideoTrack1[] = "video_1";
248static const char kVideoTrack2[] = "video_2";
249static const char kAudioTrack1[] = "audio_1";
250static const char kAudioTrack2[] = "audio_2";
251static const char kAudioTrack3[] = "audio_3";
252static const char kDataTrack1[] = "data_1";
253static const char kDataTrack2[] = "data_2";
254static const char kDataTrack3[] = "data_3";
255
zhihuangcf5b37c2016-05-05 11:44:35 -0700256static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
257 "RTP/SAVPF"};
258static const char* kMediaProtocolsDtls[] = {
259 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
260 "UDP/TLS/RTP/SAVP"};
261
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700262// SRTP cipher name negotiated by the tests. This must be updated if the
263// default changes.
264static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
265static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
266
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800267// These constants are used to make the code using "AddMediaDescriptionOptions"
268// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700269static constexpr bool kStopped = true;
270static constexpr bool kActive = false;
271
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000272static bool IsMediaContentOfType(const ContentInfo* content,
273 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800274 RTC_DCHECK(content);
275 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000276}
277
Steve Anton4e70a722017-11-28 14:57:10 -0800278static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800279 RTC_DCHECK(content);
280 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000281}
282
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000283static void AddRtxCodec(const VideoCodec& rtx_codec,
284 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800285 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000286 codecs->push_back(rtx_codec);
287}
288
289template <class T>
290static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
291 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100292 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000293 for (const auto& codec : codecs) {
294 codec_names.push_back(codec.name);
295 }
296 return codec_names;
297}
298
zhihuang1c378ed2017-08-17 14:10:50 -0700299// This is used for test only. MIDs are not the identification of the
300// MediaDescriptionOptions since some end points may not support MID and the SDP
301// may not contain 'mid'.
302std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
303 const std::string& mid,
304 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800305 return absl::c_find_if(
306 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700307 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
308}
309
310std::vector<MediaDescriptionOptions>::const_iterator
311FindFirstMediaDescriptionByMid(const std::string& mid,
312 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800313 return absl::c_find_if(
314 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700315 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700316}
317
318// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800319static void AddMediaDescriptionOptions(MediaType type,
320 const std::string& mid,
321 RtpTransceiverDirection direction,
322 bool stopped,
323 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800324 opts->media_description_options.push_back(
325 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700326}
327
Steve Anton4e70a722017-11-28 14:57:10 -0800328static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700329 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800330 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
331 opts);
332 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
333 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700334}
335
336static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800337 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700338 MediaSessionOptions* opts) {
339 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800340 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700341}
342
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800343static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700344 const std::string& mid,
345 MediaType type,
346 const std::string& track_id,
347 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800348 const std::vector<RidDescription>& rids,
349 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700350 int num_sim_layer,
351 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700352 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
353 switch (type) {
354 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700355 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700356 break;
357 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800358 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
359 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700360 break;
361 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700362 RTC_CHECK(stream_ids.size() == 1U);
363 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700364 break;
365 default:
366 RTC_NOTREACHED();
367 }
368}
369
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800370static void AttachSenderToMediaDescriptionOptions(
371 const std::string& mid,
372 MediaType type,
373 const std::string& track_id,
374 const std::vector<std::string>& stream_ids,
375 int num_sim_layer,
376 MediaSessionOptions* session_options) {
377 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
378 SimulcastLayerList(), num_sim_layer,
379 session_options);
380}
381
zhihuang1c378ed2017-08-17 14:10:50 -0700382static void DetachSenderFromMediaSection(const std::string& mid,
383 const std::string& track_id,
384 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700385 std::vector<cricket::SenderOptions>& sender_options_list =
386 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
387 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800388 absl::c_find_if(sender_options_list,
389 [track_id](const cricket::SenderOptions& sender_options) {
390 return sender_options.track_id == track_id;
391 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700392 RTC_DCHECK(sender_it != sender_options_list.end());
393 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700394}
395
396// Helper function used to create a default MediaSessionOptions for Plan B SDP.
397// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
398static MediaSessionOptions CreatePlanBMediaSessionOptions() {
399 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800400 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
401 RtpTransceiverDirection::kRecvOnly, kActive,
402 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700403 return session_options;
404}
405
406// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
407// was designed for Plan B SDP, where only one audio "m=" section and one video
408// "m=" section could be generated, and ordering couldn't be controlled. Many of
409// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200410class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800412 MediaSessionDescriptionFactoryTest()
413 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700414 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
415 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200417 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700418 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
419 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200421 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200422 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700423 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200424 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700425 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426 }
427
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000428 // Create a video StreamParamsVec object with:
429 // - one video stream with 3 simulcast streams and FEC,
430 StreamParamsVec CreateComplexVideoStreamParamsVec() {
431 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
432 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
433 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
434 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
435
436 std::vector<SsrcGroup> ssrc_groups;
437 ssrc_groups.push_back(sim_group);
438 ssrc_groups.push_back(fec_group1);
439 ssrc_groups.push_back(fec_group2);
440 ssrc_groups.push_back(fec_group3);
441
442 StreamParams simulcast_params;
443 simulcast_params.id = kVideoTrack1;
444 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
445 simulcast_params.ssrc_groups = ssrc_groups;
446 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800447 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000448
449 StreamParamsVec video_streams;
450 video_streams.push_back(simulcast_params);
451
452 return video_streams;
453 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454
455 bool CompareCryptoParams(const CryptoParamsVec& c1,
456 const CryptoParamsVec& c2) {
457 if (c1.size() != c2.size())
458 return false;
459 for (size_t i = 0; i < c1.size(); ++i)
460 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
461 c1[i].key_params != c2[i].key_params ||
462 c1[i].session_params != c2[i].session_params)
463 return false;
464 return true;
465 }
466
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700467 // Returns true if the transport info contains "renomination" as an
468 // ICE option.
469 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800470 return absl::c_linear_search(transport_info->description.transport_options,
471 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700472 }
473
zhihuang1c378ed2017-08-17 14:10:50 -0700474 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700475 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000476 bool has_current_desc) {
477 const std::string current_audio_ufrag = "current_audio_ufrag";
478 const std::string current_audio_pwd = "current_audio_pwd";
479 const std::string current_video_ufrag = "current_video_ufrag";
480 const std::string current_video_pwd = "current_video_pwd";
481 const std::string current_data_ufrag = "current_data_ufrag";
482 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800483 std::unique_ptr<SessionDescription> current_desc;
484 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800486 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800487 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200488 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800489 TransportDescription(current_audio_ufrag, current_audio_pwd)));
490 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200491 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800492 TransportDescription(current_video_ufrag, current_video_pwd)));
493 current_desc->AddTransportInfo(TransportInfo(
494 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000495 }
496 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800497 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498 } else {
kwiberg31022942016-03-11 14:18:21 -0800499 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800500 offer = f1_.CreateOffer(options, NULL);
501 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 }
503 ASSERT_TRUE(desc.get() != NULL);
504 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000505 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 EXPECT_TRUE(ti_audio != NULL);
507 if (has_current_desc) {
508 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
509 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
510 } else {
511 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
512 ti_audio->description.ice_ufrag.size());
513 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
514 ti_audio->description.ice_pwd.size());
515 }
zhihuang1c378ed2017-08-17 14:10:50 -0700516 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700517 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700518 EXPECT_EQ(
519 media_desc_options_it->transport_options.enable_ice_renomination,
520 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521
522 } else {
523 EXPECT_TRUE(ti_audio == NULL);
524 }
525 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000526 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000527 EXPECT_TRUE(ti_video != NULL);
528 if (options.bundle_enabled) {
529 EXPECT_EQ(ti_audio->description.ice_ufrag,
530 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200531 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 } else {
533 if (has_current_desc) {
534 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
535 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
536 } else {
537 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
538 ti_video->description.ice_ufrag.size());
539 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
540 ti_video->description.ice_pwd.size());
541 }
542 }
zhihuang1c378ed2017-08-17 14:10:50 -0700543 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700544 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700545 EXPECT_EQ(
546 media_desc_options_it->transport_options.enable_ice_renomination,
547 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 } else {
549 EXPECT_TRUE(ti_video == NULL);
550 }
551 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
552 if (options.has_data()) {
553 EXPECT_TRUE(ti_data != NULL);
554 if (options.bundle_enabled) {
555 EXPECT_EQ(ti_audio->description.ice_ufrag,
556 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200557 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558 } else {
559 if (has_current_desc) {
560 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
561 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
562 } else {
563 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
564 ti_data->description.ice_ufrag.size());
565 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
566 ti_data->description.ice_pwd.size());
567 }
568 }
zhihuang1c378ed2017-08-17 14:10:50 -0700569 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700570 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700571 EXPECT_EQ(
572 media_desc_options_it->transport_options.enable_ice_renomination,
573 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700574
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 } else {
576 EXPECT_TRUE(ti_video == NULL);
577 }
578 }
579
580 void TestCryptoWithBundle(bool offer) {
581 f1_.set_secure(SEC_ENABLED);
582 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800583 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
584 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
585 &options);
kwiberg31022942016-03-11 14:18:21 -0800586 std::unique_ptr<SessionDescription> ref_desc;
587 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 if (offer) {
589 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800590 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800592 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 } else {
594 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800595 ref_desc = f1_.CreateOffer(options, NULL);
596 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800598 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800600 desc->GetContentDescriptionByName("audio");
601 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000602 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800603 desc->GetContentDescriptionByName("video");
604 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
606 video_media_desc->cryptos()));
607 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800608 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609 audio_media_desc->cryptos()[0].cipher_suite);
610
611 // Verify the selected crypto is one from the reference audio
612 // media content.
613 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800614 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 bool found = false;
616 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
617 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200618 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 found = true;
620 break;
621 }
622 }
623 EXPECT_TRUE(found);
624 }
625
626 // This test that the audio and video media direction is set to
627 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700628 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800630 RtpTransceiverDirection direction_in_offer,
631 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700632 MediaSessionOptions offer_opts;
633 AddAudioVideoSections(direction_in_offer, &offer_opts);
634
Steve Anton6fe1fba2018-12-11 10:15:23 -0800635 std::unique_ptr<SessionDescription> offer =
636 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000637 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700638 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700640 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642
zhihuang1c378ed2017-08-17 14:10:50 -0700643 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800644 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800645 std::unique_ptr<SessionDescription> answer =
646 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 const AudioContentDescription* acd_answer =
648 GetFirstAudioContentDescription(answer.get());
649 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
650 const VideoContentDescription* vcd_answer =
651 GetFirstVideoContentDescription(answer.get());
652 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
653 }
654
655 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800656 RTC_DCHECK(content);
657 RTC_CHECK(content->media_description());
658 const cricket::AudioContentDescription* audio_desc =
659 content->media_description()->as_audio();
660 RTC_CHECK(audio_desc);
661 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
662 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800664 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 }
666 return true;
667 }
668
jbauchcb560652016-08-04 05:20:32 -0700669 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
670 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800671 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700672 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700673
jbauchcb560652016-08-04 05:20:32 -0700674 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800675 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700676 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700677
jbauchcb560652016-08-04 05:20:32 -0700678 f1_.set_secure(SEC_ENABLED);
679 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800680 std::unique_ptr<SessionDescription> offer =
681 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700682 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800683 std::unique_ptr<SessionDescription> answer =
684 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700685 const ContentInfo* ac = answer->GetContentByName("audio");
686 const ContentInfo* vc = answer->GetContentByName("video");
687 ASSERT_TRUE(ac != NULL);
688 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800689 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
690 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800691 const AudioContentDescription* acd = ac->media_description()->as_audio();
692 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700693 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800694 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700695 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700696 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700697 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
698 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700699 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700700 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700701 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700702 }
703 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800704 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200705 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
706 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700707 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700708 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700709 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700710 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700711 }
Steve Antone38a5a12018-11-21 16:05:15 -0800712 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700713 }
714
Johannes Kronce8e8672019-02-22 13:06:44 +0100715 void TestTransportSequenceNumberNegotiation(
716 const cricket::RtpHeaderExtensions& local,
717 const cricket::RtpHeaderExtensions& offered,
718 const cricket::RtpHeaderExtensions& expectedAnswer) {
719 MediaSessionOptions opts;
720 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
721 f1_.set_audio_rtp_header_extensions(offered);
722 f1_.set_video_rtp_header_extensions(offered);
723 f2_.set_audio_rtp_header_extensions(local);
724 f2_.set_video_rtp_header_extensions(local);
725
726 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
727 ASSERT_TRUE(offer.get() != NULL);
728 std::unique_ptr<SessionDescription> answer =
729 f2_.CreateAnswer(offer.get(), opts, NULL);
730
731 EXPECT_EQ(
732 expectedAnswer,
733 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
734 EXPECT_EQ(
735 expectedAnswer,
736 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
737 }
738
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800740 UniqueRandomIdGenerator ssrc_generator1;
741 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 MediaSessionDescriptionFactory f1_;
743 MediaSessionDescriptionFactory f2_;
744 TransportDescriptionFactory tdf1_;
745 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746};
747
748// Create a typical audio offer, and ensure it matches what we expect.
749TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
750 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800751 std::unique_ptr<SessionDescription> offer =
752 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753 ASSERT_TRUE(offer.get() != NULL);
754 const ContentInfo* ac = offer->GetContentByName("audio");
755 const ContentInfo* vc = offer->GetContentByName("video");
756 ASSERT_TRUE(ac != NULL);
757 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800758 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800759 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700761 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700762 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
764 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700765 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800766 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767}
768
769// Create a typical video offer, and ensure it matches what we expect.
770TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
771 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800772 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800774 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775 ASSERT_TRUE(offer.get() != NULL);
776 const ContentInfo* ac = offer->GetContentByName("audio");
777 const ContentInfo* vc = offer->GetContentByName("video");
778 ASSERT_TRUE(ac != NULL);
779 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800780 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
781 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800782 const AudioContentDescription* acd = ac->media_description()->as_audio();
783 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000784 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700785 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700786 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
788 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700789 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800790 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
792 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700793 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
795 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700796 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800797 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798}
799
800// Test creating an offer with bundle where the Codecs have the same dynamic
801// RTP playlod type. The test verifies that the offer don't contain the
802// duplicate RTP payload types.
803TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
804 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700805 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200806 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
808 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
809
810 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800811 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
812 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800814 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 const VideoContentDescription* vcd =
816 GetFirstVideoContentDescription(offer.get());
817 const AudioContentDescription* acd =
818 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200819 const RtpDataContentDescription* dcd =
820 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 ASSERT_TRUE(NULL != vcd);
822 ASSERT_TRUE(NULL != acd);
823 ASSERT_TRUE(NULL != dcd);
824 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
825 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
826 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
827 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
828 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
829 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
830}
831
zhihuang1c378ed2017-08-17 14:10:50 -0700832// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833// after an audio only session has been negotiated.
834TEST_F(MediaSessionDescriptionFactoryTest,
835 TestCreateUpdatedVideoOfferWithBundle) {
836 f1_.set_secure(SEC_ENABLED);
837 f2_.set_secure(SEC_ENABLED);
838 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800839 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
840 RtpTransceiverDirection::kRecvOnly, kActive,
841 &opts);
842 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
843 RtpTransceiverDirection::kInactive, kStopped,
844 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 opts.data_channel_type = cricket::DCT_NONE;
846 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800847 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
848 std::unique_ptr<SessionDescription> answer =
849 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850
851 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800852 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
853 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
854 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800856 std::unique_ptr<SessionDescription> updated_offer(
857 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858
859 const AudioContentDescription* acd =
860 GetFirstAudioContentDescription(updated_offer.get());
861 const VideoContentDescription* vcd =
862 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200863 const RtpDataContentDescription* dcd =
864 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 EXPECT_TRUE(NULL != vcd);
866 EXPECT_TRUE(NULL != acd);
867 EXPECT_TRUE(NULL != dcd);
868
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700869 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800870 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700871 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800872 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700873 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800874 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000875}
deadbeef44f08192015-12-15 16:20:09 -0800876
wu@webrtc.org78187522013-10-07 23:32:02 +0000877// Create a RTP data offer, and ensure it matches what we expect.
878TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800880 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
881 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800883 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000884 ASSERT_TRUE(offer.get() != NULL);
885 const ContentInfo* ac = offer->GetContentByName("audio");
886 const ContentInfo* dc = offer->GetContentByName("data");
887 ASSERT_TRUE(ac != NULL);
888 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800889 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
890 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800891 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200892 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700894 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700895 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
897 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700898 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800899 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200901 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700902 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200904 dcd->bandwidth()); // default bandwidth (auto)
905 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700906 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800907 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908}
909
wu@webrtc.org78187522013-10-07 23:32:02 +0000910// Create an SCTP data offer with bundle without error.
911TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
912 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000913 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800914 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000915 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800916 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000917 EXPECT_TRUE(offer.get() != NULL);
918 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000919 auto dcd = GetFirstSctpDataContentDescription(offer.get());
920 ASSERT_TRUE(dcd);
921 // Since this transport is insecure, the protocol should be "SCTP".
922 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
923}
924
925// Create an SCTP data offer with bundle without error.
926TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
927 MediaSessionOptions opts;
928 opts.bundle_enabled = true;
929 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
930 f1_.set_secure(SEC_ENABLED);
931 tdf1_.set_secure(SEC_ENABLED);
932 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
933 EXPECT_TRUE(offer.get() != NULL);
934 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
935 auto dcd = GetFirstSctpDataContentDescription(offer.get());
936 ASSERT_TRUE(dcd);
937 // The protocol should now be "UDP/DTLS/SCTP"
938 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000939}
940
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000941// Test creating an sctp data channel from an already generated offer.
942TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
943 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000944 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800945 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000946 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800947 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000948 ASSERT_TRUE(offer1.get() != NULL);
949 const ContentInfo* data = offer1->GetContentByName("data");
950 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800951 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000952
953 // Now set data_channel_type to 'none' (default) and make sure that the
954 // datachannel type that gets generated from the previous offer, is of the
955 // same type.
956 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800957 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000958 f1_.CreateOffer(opts, offer1.get()));
959 data = offer2->GetContentByName("data");
960 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800961 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000962}
963
Steve Anton2bed3972019-01-04 17:04:30 -0800964// Test that if BUNDLE is enabled and all media sections are rejected then the
965// BUNDLE group is not present in the re-offer.
966TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
967 MediaSessionOptions opts;
968 opts.bundle_enabled = true;
969 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
970 RtpTransceiverDirection::kSendRecv, kActive,
971 &opts);
972 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
973
974 opts.media_description_options[0].stopped = true;
975 std::unique_ptr<SessionDescription> reoffer =
976 f1_.CreateOffer(opts, offer.get());
977
978 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
979}
980
981// Test that if BUNDLE is enabled and the remote re-offer does not include a
982// BUNDLE group since all media sections are rejected, then the re-answer also
983// does not include a BUNDLE group.
984TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
985 MediaSessionOptions opts;
986 opts.bundle_enabled = true;
987 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
988 RtpTransceiverDirection::kSendRecv, kActive,
989 &opts);
990 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
991 std::unique_ptr<SessionDescription> answer =
992 f2_.CreateAnswer(offer.get(), opts, nullptr);
993
994 opts.media_description_options[0].stopped = true;
995 std::unique_ptr<SessionDescription> reoffer =
996 f1_.CreateOffer(opts, offer.get());
997 std::unique_ptr<SessionDescription> reanswer =
998 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
999
1000 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1001}
1002
1003// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1004// was rejected then the new offerer-tagged media section is the non-rejected
1005// media section.
1006TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1007 MediaSessionOptions opts;
1008 opts.bundle_enabled = true;
1009 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1010 RtpTransceiverDirection::kSendRecv, kActive,
1011 &opts);
1012 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1013
1014 // Reject the audio m= section and add a video m= section.
1015 opts.media_description_options[0].stopped = true;
1016 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1017 RtpTransceiverDirection::kSendRecv, kActive,
1018 &opts);
1019 std::unique_ptr<SessionDescription> reoffer =
1020 f1_.CreateOffer(opts, offer.get());
1021
1022 const cricket::ContentGroup* bundle_group =
1023 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1024 ASSERT_TRUE(bundle_group);
1025 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1026 EXPECT_TRUE(bundle_group->HasContentName("video"));
1027}
1028
1029// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1030// was rejected and a new media section is added, then the re-answer BUNDLE
1031// group will contain only the non-rejected media section.
1032TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1033 MediaSessionOptions opts;
1034 opts.bundle_enabled = true;
1035 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1036 RtpTransceiverDirection::kSendRecv, kActive,
1037 &opts);
1038 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1039 std::unique_ptr<SessionDescription> answer =
1040 f2_.CreateAnswer(offer.get(), opts, nullptr);
1041
1042 // Reject the audio m= section and add a video m= section.
1043 opts.media_description_options[0].stopped = true;
1044 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1045 RtpTransceiverDirection::kSendRecv, kActive,
1046 &opts);
1047 std::unique_ptr<SessionDescription> reoffer =
1048 f1_.CreateOffer(opts, offer.get());
1049 std::unique_ptr<SessionDescription> reanswer =
1050 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1051
1052 const cricket::ContentGroup* bundle_group =
1053 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1054 ASSERT_TRUE(bundle_group);
1055 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1056 EXPECT_TRUE(bundle_group->HasContentName("video"));
1057}
1058
1059// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1060// and there is still a non-rejected media section that was in the initial
1061// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1062// media section.
1063TEST_F(MediaSessionDescriptionFactoryTest,
1064 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1065 MediaSessionOptions opts;
1066 opts.bundle_enabled = true;
1067 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1068 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1069 std::unique_ptr<SessionDescription> answer =
1070 f2_.CreateAnswer(offer.get(), opts, nullptr);
1071
1072 // Reject the audio m= section.
1073 opts.media_description_options[0].stopped = true;
1074 std::unique_ptr<SessionDescription> reoffer =
1075 f1_.CreateOffer(opts, offer.get());
1076
1077 const TransportDescription* offer_tagged =
1078 offer->GetTransportDescriptionByName("audio");
1079 ASSERT_TRUE(offer_tagged);
1080 const TransportDescription* reoffer_tagged =
1081 reoffer->GetTransportDescriptionByName("video");
1082 ASSERT_TRUE(reoffer_tagged);
1083 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1084 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1085}
1086
1087// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1088// and there is still a non-rejected media section that was in the initial
1089// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1090// media section.
1091TEST_F(MediaSessionDescriptionFactoryTest,
1092 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1093 MediaSessionOptions opts;
1094 opts.bundle_enabled = true;
1095 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1096 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1097 std::unique_ptr<SessionDescription> answer =
1098 f2_.CreateAnswer(offer.get(), opts, nullptr);
1099
1100 // Reject the audio m= section.
1101 opts.media_description_options[0].stopped = true;
1102 std::unique_ptr<SessionDescription> reoffer =
1103 f1_.CreateOffer(opts, offer.get());
1104 std::unique_ptr<SessionDescription> reanswer =
1105 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1106
1107 const TransportDescription* answer_tagged =
1108 answer->GetTransportDescriptionByName("audio");
1109 ASSERT_TRUE(answer_tagged);
1110 const TransportDescription* reanswer_tagged =
1111 reanswer->GetTransportDescriptionByName("video");
1112 ASSERT_TRUE(reanswer_tagged);
1113 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1114 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1115}
1116
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001117// Create an audio, video offer without legacy StreamParams.
1118TEST_F(MediaSessionDescriptionFactoryTest,
1119 TestCreateOfferWithoutLegacyStreams) {
1120 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001121 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001122 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001123 ASSERT_TRUE(offer.get() != NULL);
1124 const ContentInfo* ac = offer->GetContentByName("audio");
1125 const ContentInfo* vc = offer->GetContentByName("video");
1126 ASSERT_TRUE(ac != NULL);
1127 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001128 const AudioContentDescription* acd = ac->media_description()->as_audio();
1129 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001130
Yves Gerey665174f2018-06-19 15:03:05 +02001131 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1132 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001133}
1134
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001135// Creates an audio+video sendonly offer.
1136TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001137 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001138 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001139 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1140 {kMediaStream1}, 1, &opts);
1141 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1142 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001143
Steve Anton6fe1fba2018-12-11 10:15:23 -08001144 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001145 ASSERT_TRUE(offer.get() != NULL);
1146 EXPECT_EQ(2u, offer->contents().size());
1147 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1148 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1149
Steve Anton4e70a722017-11-28 14:57:10 -08001150 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1151 GetMediaDirection(&offer->contents()[0]));
1152 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1153 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001154}
1155
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001156// Verifies that the order of the media contents in the current
1157// SessionDescription is preserved in the new SessionDescription.
1158TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1159 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001160 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001161
kwiberg31022942016-03-11 14:18:21 -08001162 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001163 ASSERT_TRUE(offer1.get() != NULL);
1164 EXPECT_EQ(1u, offer1->contents().size());
1165 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1166
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001167 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1168 RtpTransceiverDirection::kRecvOnly, kActive,
1169 &opts);
kwiberg31022942016-03-11 14:18:21 -08001170 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001171 f1_.CreateOffer(opts, offer1.get()));
1172 ASSERT_TRUE(offer2.get() != NULL);
1173 EXPECT_EQ(2u, offer2->contents().size());
1174 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1175 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1176
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001177 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1178 RtpTransceiverDirection::kRecvOnly, kActive,
1179 &opts);
kwiberg31022942016-03-11 14:18:21 -08001180 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001181 f1_.CreateOffer(opts, offer2.get()));
1182 ASSERT_TRUE(offer3.get() != NULL);
1183 EXPECT_EQ(3u, offer3->contents().size());
1184 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1185 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1186 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001187}
1188
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189// Create a typical audio answer, and ensure it matches what we expect.
1190TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1191 f1_.set_secure(SEC_ENABLED);
1192 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001193 std::unique_ptr<SessionDescription> offer =
1194 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001196 std::unique_ptr<SessionDescription> answer =
1197 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001198 const ContentInfo* ac = answer->GetContentByName("audio");
1199 const ContentInfo* vc = answer->GetContentByName("video");
1200 ASSERT_TRUE(ac != NULL);
1201 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001202 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001203 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001204 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001205 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001206 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001207 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1208 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001209 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001210 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001211}
1212
jbauchcb560652016-08-04 05:20:32 -07001213// Create a typical audio answer with GCM ciphers enabled, and ensure it
1214// matches what we expect.
1215TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1216 f1_.set_secure(SEC_ENABLED);
1217 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001218 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001219 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001220 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001221 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001222 std::unique_ptr<SessionDescription> answer =
1223 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001224 const ContentInfo* ac = answer->GetContentByName("audio");
1225 const ContentInfo* vc = answer->GetContentByName("video");
1226 ASSERT_TRUE(ac != NULL);
1227 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001228 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001229 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001230 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001231 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001232 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001233 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1234 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001235 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001236 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001237}
1238
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239// Create a typical video answer, and ensure it matches what we expect.
1240TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1241 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001242 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243 f1_.set_secure(SEC_ENABLED);
1244 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001245 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001247 std::unique_ptr<SessionDescription> answer =
1248 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001249 const ContentInfo* ac = answer->GetContentByName("audio");
1250 const ContentInfo* vc = answer->GetContentByName("video");
1251 ASSERT_TRUE(ac != NULL);
1252 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001253 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1254 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001255 const AudioContentDescription* acd = ac->media_description()->as_audio();
1256 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001258 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001260 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001262 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001264 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001265 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1266 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001267 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001268 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269}
1270
jbauchcb560652016-08-04 05:20:32 -07001271// Create a typical video answer with GCM ciphers enabled, and ensure it
1272// matches what we expect.
1273TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1274 TestVideoGcmCipher(true, true);
1275}
1276
1277// Create a typical video answer with GCM ciphers enabled for the offer only,
1278// and ensure it matches what we expect.
1279TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1280 TestVideoGcmCipher(true, false);
1281}
1282
1283// Create a typical video answer with GCM ciphers enabled for the answer only,
1284// and ensure it matches what we expect.
1285TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1286 TestVideoGcmCipher(false, true);
1287}
1288
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001290 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001291 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292 f1_.set_secure(SEC_ENABLED);
1293 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001294 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001296 std::unique_ptr<SessionDescription> answer =
1297 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001299 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001301 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001302 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1303 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001304 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001305 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001306 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001307 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001309 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001311 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001312 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001313 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001314 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001315 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001316 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001317 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318}
1319
jbauchcb560652016-08-04 05:20:32 -07001320TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001321 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001322 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001323 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001324 f1_.set_secure(SEC_ENABLED);
1325 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001326 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001327 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001328 std::unique_ptr<SessionDescription> answer =
1329 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001330 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001331 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001332 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001333 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001334 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1335 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001336 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001337 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001338 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001339 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001340 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001341 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001342 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001343 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001344 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001345 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001346 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001347 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001348 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001349 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001350}
1351
1352// The use_sctpmap flag should be set in a DataContentDescription by default.
1353// The answer's use_sctpmap flag should match the offer's.
1354TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1355 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001356 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001357 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001358 ASSERT_TRUE(offer.get() != NULL);
1359 ContentInfo* dc_offer = offer->GetContentByName("data");
1360 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001361 SctpDataContentDescription* dcd_offer =
1362 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001363 EXPECT_TRUE(dcd_offer->use_sctpmap());
1364
Steve Anton6fe1fba2018-12-11 10:15:23 -08001365 std::unique_ptr<SessionDescription> answer =
1366 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001367 const ContentInfo* dc_answer = answer->GetContentByName("data");
1368 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001369 const SctpDataContentDescription* dcd_answer =
1370 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001371 EXPECT_TRUE(dcd_answer->use_sctpmap());
1372}
1373
1374// The answer's use_sctpmap flag should match the offer's.
1375TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1376 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001377 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001378 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001379 ASSERT_TRUE(offer.get() != NULL);
1380 ContentInfo* dc_offer = offer->GetContentByName("data");
1381 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001382 SctpDataContentDescription* dcd_offer =
1383 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001384 dcd_offer->set_use_sctpmap(false);
1385
Steve Anton6fe1fba2018-12-11 10:15:23 -08001386 std::unique_ptr<SessionDescription> answer =
1387 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001388 const ContentInfo* dc_answer = answer->GetContentByName("data");
1389 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001390 const SctpDataContentDescription* dcd_answer =
1391 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001392 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001393}
1394
deadbeef8b7e9ad2017-05-25 09:38:55 -07001395// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1396// and "TCP/DTLS/SCTP" offers.
1397TEST_F(MediaSessionDescriptionFactoryTest,
1398 TestCreateDataAnswerToDifferentOfferedProtos) {
1399 // Need to enable DTLS offer/answer generation (disabled by default in this
1400 // test).
1401 f1_.set_secure(SEC_ENABLED);
1402 f2_.set_secure(SEC_ENABLED);
1403 tdf1_.set_secure(SEC_ENABLED);
1404 tdf2_.set_secure(SEC_ENABLED);
1405
1406 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001407 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001408 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001409 ASSERT_TRUE(offer.get() != nullptr);
1410 ContentInfo* dc_offer = offer->GetContentByName("data");
1411 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001412 SctpDataContentDescription* dcd_offer =
1413 dc_offer->media_description()->as_sctp();
1414 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001415
1416 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1417 "TCP/DTLS/SCTP"};
1418 for (const std::string& proto : protos) {
1419 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001420 std::unique_ptr<SessionDescription> answer =
1421 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001422 const ContentInfo* dc_answer = answer->GetContentByName("data");
1423 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001424 const SctpDataContentDescription* dcd_answer =
1425 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001426 EXPECT_FALSE(dc_answer->rejected);
1427 EXPECT_EQ(proto, dcd_answer->protocol());
1428 }
1429}
1430
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001431TEST_F(MediaSessionDescriptionFactoryTest,
1432 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1433 // Need to enable DTLS offer/answer generation (disabled by default in this
1434 // test).
1435 f1_.set_secure(SEC_ENABLED);
1436 f2_.set_secure(SEC_ENABLED);
1437 tdf1_.set_secure(SEC_ENABLED);
1438 tdf2_.set_secure(SEC_ENABLED);
1439
1440 MediaSessionOptions opts;
1441 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1442 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1443 ASSERT_TRUE(offer.get() != nullptr);
1444 ContentInfo* dc_offer = offer->GetContentByName("data");
1445 ASSERT_TRUE(dc_offer != nullptr);
1446 SctpDataContentDescription* dcd_offer =
1447 dc_offer->media_description()->as_sctp();
1448 ASSERT_TRUE(dcd_offer);
1449 dcd_offer->set_max_message_size(1234);
1450 std::unique_ptr<SessionDescription> answer =
1451 f2_.CreateAnswer(offer.get(), opts, nullptr);
1452 const ContentInfo* dc_answer = answer->GetContentByName("data");
1453 ASSERT_TRUE(dc_answer != nullptr);
1454 const SctpDataContentDescription* dcd_answer =
1455 dc_answer->media_description()->as_sctp();
1456 EXPECT_FALSE(dc_answer->rejected);
1457 EXPECT_EQ(1234, dcd_answer->max_message_size());
1458}
1459
1460TEST_F(MediaSessionDescriptionFactoryTest,
1461 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1462 // Need to enable DTLS offer/answer generation (disabled by default in this
1463 // test).
1464 f1_.set_secure(SEC_ENABLED);
1465 f2_.set_secure(SEC_ENABLED);
1466 tdf1_.set_secure(SEC_ENABLED);
1467 tdf2_.set_secure(SEC_ENABLED);
1468
1469 MediaSessionOptions opts;
1470 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1471 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1472 ASSERT_TRUE(offer.get() != nullptr);
1473 ContentInfo* dc_offer = offer->GetContentByName("data");
1474 ASSERT_TRUE(dc_offer != nullptr);
1475 SctpDataContentDescription* dcd_offer =
1476 dc_offer->media_description()->as_sctp();
1477 ASSERT_TRUE(dcd_offer);
1478 dcd_offer->set_max_message_size(0);
1479 std::unique_ptr<SessionDescription> answer =
1480 f2_.CreateAnswer(offer.get(), opts, nullptr);
1481 const ContentInfo* dc_answer = answer->GetContentByName("data");
1482 ASSERT_TRUE(dc_answer != nullptr);
1483 const SctpDataContentDescription* dcd_answer =
1484 dc_answer->media_description()->as_sctp();
1485 EXPECT_FALSE(dc_answer->rejected);
1486 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1487}
1488
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001489// Verifies that the order of the media contents in the offer is preserved in
1490// the answer.
1491TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1492 MediaSessionOptions opts;
1493
1494 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001495 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001496 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001497 ASSERT_TRUE(offer1.get() != NULL);
1498
1499 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001500 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1501 RtpTransceiverDirection::kRecvOnly, kActive,
1502 &opts);
kwiberg31022942016-03-11 14:18:21 -08001503 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001504 f1_.CreateOffer(opts, offer1.get()));
1505 ASSERT_TRUE(offer2.get() != NULL);
1506
1507 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001508 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1509 RtpTransceiverDirection::kRecvOnly, kActive,
1510 &opts);
kwiberg31022942016-03-11 14:18:21 -08001511 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001512 f1_.CreateOffer(opts, offer2.get()));
1513 ASSERT_TRUE(offer3.get() != NULL);
1514
Steve Anton6fe1fba2018-12-11 10:15:23 -08001515 std::unique_ptr<SessionDescription> answer =
1516 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001517 ASSERT_TRUE(answer.get() != NULL);
1518 EXPECT_EQ(3u, answer->contents().size());
1519 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1520 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1521 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1522}
1523
ossu075af922016-06-14 03:29:38 -07001524// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1525// answerer settings.
1526
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001527// This test that the media direction is set to send/receive in an answer if
1528// the offer is send receive.
1529TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001530 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1531 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001532}
1533
1534// This test that the media direction is set to receive only in an answer if
1535// the offer is send only.
1536TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001537 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1538 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001539}
1540
1541// This test that the media direction is set to send only in an answer if
1542// the offer is recv only.
1543TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001544 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1545 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001546}
1547
1548// This test that the media direction is set to inactive in an answer if
1549// the offer is inactive.
1550TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001551 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1552 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001553}
1554
1555// Test that a data content with an unknown protocol is rejected in an answer.
1556TEST_F(MediaSessionDescriptionFactoryTest,
1557 CreateDataAnswerToOfferWithUnknownProtocol) {
1558 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001559 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560 f1_.set_secure(SEC_ENABLED);
1561 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001562 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001563 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001564 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001565 RtpDataContentDescription* dcd_offer =
1566 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001567 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001568 // Offer must be acceptable as an RTP protocol in order to be set.
1569 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001570 dcd_offer->set_protocol(protocol);
1571
Steve Anton6fe1fba2018-12-11 10:15:23 -08001572 std::unique_ptr<SessionDescription> answer =
1573 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574
1575 const ContentInfo* dc_answer = answer->GetContentByName("data");
1576 ASSERT_TRUE(dc_answer != NULL);
1577 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001578 const RtpDataContentDescription* dcd_answer =
1579 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001580 ASSERT_TRUE(dcd_answer != NULL);
1581 EXPECT_EQ(protocol, dcd_answer->protocol());
1582}
1583
1584// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1585TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001586 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001587 f1_.set_secure(SEC_DISABLED);
1588 f2_.set_secure(SEC_DISABLED);
1589 tdf1_.set_secure(SEC_DISABLED);
1590 tdf2_.set_secure(SEC_DISABLED);
1591
Steve Anton6fe1fba2018-12-11 10:15:23 -08001592 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001593 const AudioContentDescription* offer_acd =
1594 GetFirstAudioContentDescription(offer.get());
1595 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001596 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001597
Steve Anton6fe1fba2018-12-11 10:15:23 -08001598 std::unique_ptr<SessionDescription> answer =
1599 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001600
1601 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1602 ASSERT_TRUE(ac_answer != NULL);
1603 EXPECT_FALSE(ac_answer->rejected);
1604
1605 const AudioContentDescription* answer_acd =
1606 GetFirstAudioContentDescription(answer.get());
1607 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001608 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001609}
1610
1611// Create a video offer and answer and ensure the RTP header extensions
1612// matches what we expect.
1613TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1614 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001615 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001616 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1617 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1618 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1619 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1620
Steve Anton6fe1fba2018-12-11 10:15:23 -08001621 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001623 std::unique_ptr<SessionDescription> answer =
1624 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001625
Yves Gerey665174f2018-06-19 15:03:05 +02001626 EXPECT_EQ(
1627 MAKE_VECTOR(kAudioRtpExtension1),
1628 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1629 EXPECT_EQ(
1630 MAKE_VECTOR(kVideoRtpExtension1),
1631 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1632 EXPECT_EQ(
1633 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1634 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1635 EXPECT_EQ(
1636 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1637 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001638}
1639
Johannes Kronce8e8672019-02-22 13:06:44 +01001640// Create a audio/video offer and answer and ensure that the
1641// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1642// supported and should take precedence even though not listed among locally
1643// supported extensions.
1644TEST_F(MediaSessionDescriptionFactoryTest,
1645 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1646 TestTransportSequenceNumberNegotiation(
1647 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1648 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1649 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1650}
1651TEST_F(MediaSessionDescriptionFactoryTest,
1652 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1653 TestTransportSequenceNumberNegotiation(
1654 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1655 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1656 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1657}
1658TEST_F(MediaSessionDescriptionFactoryTest,
1659 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1660 TestTransportSequenceNumberNegotiation(
1661 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1662 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1663 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1664}
1665
jbauch5869f502017-06-29 12:31:36 -07001666TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001667 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001668 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001669 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001670
1671 f1_.set_enable_encrypted_rtp_header_extensions(true);
1672 f2_.set_enable_encrypted_rtp_header_extensions(true);
1673
Yves Gerey665174f2018-06-19 15:03:05 +02001674 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1675 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1676 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1677 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001678
Steve Anton6fe1fba2018-12-11 10:15:23 -08001679 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001680 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001681 std::unique_ptr<SessionDescription> answer =
1682 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001683
Yves Gerey665174f2018-06-19 15:03:05 +02001684 EXPECT_EQ(
1685 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1686 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1687 EXPECT_EQ(
1688 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1689 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1690 EXPECT_EQ(
1691 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1692 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1693 EXPECT_EQ(
1694 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1695 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001696}
1697
1698TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001699 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001700 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001701 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001702
1703 f1_.set_enable_encrypted_rtp_header_extensions(true);
1704
Yves Gerey665174f2018-06-19 15:03:05 +02001705 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1706 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1707 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1708 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001709
Steve Anton6fe1fba2018-12-11 10:15:23 -08001710 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001711 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001712 std::unique_ptr<SessionDescription> answer =
1713 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001714
Yves Gerey665174f2018-06-19 15:03:05 +02001715 EXPECT_EQ(
1716 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1717 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1718 EXPECT_EQ(
1719 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1720 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1721 EXPECT_EQ(
1722 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1723 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1724 EXPECT_EQ(
1725 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1726 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001727}
1728
1729TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001730 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001731 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001732 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001733
1734 f2_.set_enable_encrypted_rtp_header_extensions(true);
1735
Yves Gerey665174f2018-06-19 15:03:05 +02001736 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1737 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1738 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1739 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001740
Steve Anton6fe1fba2018-12-11 10:15:23 -08001741 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001742 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001743 std::unique_ptr<SessionDescription> answer =
1744 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001745
Yves Gerey665174f2018-06-19 15:03:05 +02001746 EXPECT_EQ(
1747 MAKE_VECTOR(kAudioRtpExtension1),
1748 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1749 EXPECT_EQ(
1750 MAKE_VECTOR(kVideoRtpExtension1),
1751 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1752 EXPECT_EQ(
1753 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1754 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1755 EXPECT_EQ(
1756 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1757 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001758}
1759
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001760// Create an audio, video, data answer without legacy StreamParams.
1761TEST_F(MediaSessionDescriptionFactoryTest,
1762 TestCreateAnswerWithoutLegacyStreams) {
1763 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001764 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1765 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001766 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001768 std::unique_ptr<SessionDescription> answer =
1769 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001770 const ContentInfo* ac = answer->GetContentByName("audio");
1771 const ContentInfo* vc = answer->GetContentByName("video");
1772 const ContentInfo* dc = answer->GetContentByName("data");
1773 ASSERT_TRUE(ac != NULL);
1774 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001775 const AudioContentDescription* acd = ac->media_description()->as_audio();
1776 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001777 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001778
1779 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1780 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1781 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1782}
1783
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784// Create a typical video answer, and ensure it matches what we expect.
1785TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1786 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001787 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1788 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1789 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001790
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001791 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001792 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1793 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1794 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795
kwiberg31022942016-03-11 14:18:21 -08001796 std::unique_ptr<SessionDescription> offer;
1797 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001798
1799 offer_opts.rtcp_mux_enabled = true;
1800 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001801 offer = f1_.CreateOffer(offer_opts, NULL);
1802 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001803 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1804 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001805 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001806 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1807 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001808 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1810 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001811 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001812 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1813 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001814 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001815
1816 offer_opts.rtcp_mux_enabled = true;
1817 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001818 offer = f1_.CreateOffer(offer_opts, NULL);
1819 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001820 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1821 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001822 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001823 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1824 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001825 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001826 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1827 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001828 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001829 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1830 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001831 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001832
1833 offer_opts.rtcp_mux_enabled = false;
1834 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001835 offer = f1_.CreateOffer(offer_opts, NULL);
1836 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001837 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1838 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001839 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1841 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001842 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001843 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1844 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001845 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001846 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1847 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001848 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001849
1850 offer_opts.rtcp_mux_enabled = false;
1851 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001852 offer = f1_.CreateOffer(offer_opts, NULL);
1853 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001854 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1855 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001856 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001857 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1858 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001859 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001860 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1861 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001862 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001863 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1864 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001865 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001866}
1867
1868// Create an audio-only answer to a video offer.
1869TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1870 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001871 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1872 RtpTransceiverDirection::kRecvOnly, kActive,
1873 &opts);
1874 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1875 RtpTransceiverDirection::kRecvOnly, kActive,
1876 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001877 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001878 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001879
1880 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001881 std::unique_ptr<SessionDescription> answer =
1882 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001883 const ContentInfo* ac = answer->GetContentByName("audio");
1884 const ContentInfo* vc = answer->GetContentByName("video");
1885 ASSERT_TRUE(ac != NULL);
1886 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001887 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001888 EXPECT_TRUE(vc->rejected);
1889}
1890
1891// Create an audio-only answer to an offer with data.
1892TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001893 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001894 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001895 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1896 RtpTransceiverDirection::kRecvOnly, kActive,
1897 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001898 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001899 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001900
1901 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001902 std::unique_ptr<SessionDescription> answer =
1903 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001904 const ContentInfo* ac = answer->GetContentByName("audio");
1905 const ContentInfo* dc = answer->GetContentByName("data");
1906 ASSERT_TRUE(ac != NULL);
1907 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001908 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001909 EXPECT_TRUE(dc->rejected);
1910}
1911
1912// Create an answer that rejects the contents which are rejected in the offer.
1913TEST_F(MediaSessionDescriptionFactoryTest,
1914 CreateAnswerToOfferWithRejectedMedia) {
1915 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001916 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1917 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001918 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919 ASSERT_TRUE(offer.get() != NULL);
1920 ContentInfo* ac = offer->GetContentByName("audio");
1921 ContentInfo* vc = offer->GetContentByName("video");
1922 ContentInfo* dc = offer->GetContentByName("data");
1923 ASSERT_TRUE(ac != NULL);
1924 ASSERT_TRUE(vc != NULL);
1925 ASSERT_TRUE(dc != NULL);
1926 ac->rejected = true;
1927 vc->rejected = true;
1928 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001929 std::unique_ptr<SessionDescription> answer =
1930 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001931 ac = answer->GetContentByName("audio");
1932 vc = answer->GetContentByName("video");
1933 dc = answer->GetContentByName("data");
1934 ASSERT_TRUE(ac != NULL);
1935 ASSERT_TRUE(vc != NULL);
1936 ASSERT_TRUE(dc != NULL);
1937 EXPECT_TRUE(ac->rejected);
1938 EXPECT_TRUE(vc->rejected);
1939 EXPECT_TRUE(dc->rejected);
1940}
1941
Johannes Kron0854eb62018-10-10 22:33:20 +02001942TEST_F(MediaSessionDescriptionFactoryTest,
1943 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1944 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001945 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001946 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001947 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001948 ASSERT_TRUE(offer.get() != NULL);
1949 std::unique_ptr<SessionDescription> answer_no_support(
1950 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001951 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001952
1953 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001954 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001955 ASSERT_TRUE(offer.get() != NULL);
1956 std::unique_ptr<SessionDescription> answer_support(
1957 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001958 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001959}
1960
1961TEST_F(MediaSessionDescriptionFactoryTest,
1962 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1963 MediaSessionOptions opts;
1964 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001965 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001966 MediaContentDescription* video_offer =
1967 offer->GetContentDescriptionByName("video");
1968 ASSERT_TRUE(video_offer);
1969 MediaContentDescription* audio_offer =
1970 offer->GetContentDescriptionByName("audio");
1971 ASSERT_TRUE(audio_offer);
1972
1973 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001974 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1975 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001976
1977 ASSERT_TRUE(offer.get() != NULL);
1978 std::unique_ptr<SessionDescription> answer_no_support(
1979 f2_.CreateAnswer(offer.get(), opts, NULL));
1980 MediaContentDescription* video_answer =
1981 answer_no_support->GetContentDescriptionByName("video");
1982 MediaContentDescription* audio_answer =
1983 answer_no_support->GetContentDescriptionByName("audio");
1984 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001985 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001986 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001987 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001988
1989 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001990 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1991 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001992 ASSERT_TRUE(offer.get() != NULL);
1993 std::unique_ptr<SessionDescription> answer_support(
1994 f2_.CreateAnswer(offer.get(), opts, NULL));
1995 video_answer = answer_support->GetContentDescriptionByName("video");
1996 audio_answer = answer_support->GetContentDescriptionByName("audio");
1997 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001998 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001999 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002000 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002001}
2002
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002003// Create an audio and video offer with:
2004// - one video track
2005// - two audio tracks
2006// - two data tracks
2007// and ensure it matches what we expect. Also updates the initial offer by
2008// adding a new video track and replaces one of the audio tracks.
2009TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2010 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002011 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002012 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2013 {kMediaStream1}, 1, &opts);
2014 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2015 {kMediaStream1}, 1, &opts);
2016 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2017 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002018
Steve Anton4e70a722017-11-28 14:57:10 -08002019 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002020 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2021 {kMediaStream1}, 1, &opts);
2022 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2023 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002024
2025 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002026 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002027
2028 ASSERT_TRUE(offer.get() != NULL);
2029 const ContentInfo* ac = offer->GetContentByName("audio");
2030 const ContentInfo* vc = offer->GetContentByName("video");
2031 const ContentInfo* dc = offer->GetContentByName("data");
2032 ASSERT_TRUE(ac != NULL);
2033 ASSERT_TRUE(vc != NULL);
2034 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002035 const AudioContentDescription* acd = ac->media_description()->as_audio();
2036 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002037 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002039 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002040
2041 const StreamParamsVec& audio_streams = acd->streams();
2042 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002043 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002044 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2045 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2046 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2047 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2048 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2049 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2050
2051 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2052 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002053 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002054
2055 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
2056 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002057 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058
2059 const StreamParamsVec& video_streams = vcd->streams();
2060 ASSERT_EQ(1U, video_streams.size());
2061 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2062 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2063 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2064 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2065
2066 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002067 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002068 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002069
2070 const StreamParamsVec& data_streams = dcd->streams();
2071 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002072 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002073 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2074 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2075 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2076 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2077 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2078 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2079
2080 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002081 dcd->bandwidth()); // default bandwidth (auto)
2082 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002083 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002084
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002085 // Update the offer. Add a new video track that is not synched to the
2086 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002087 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2088 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002089 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002090 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2091 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002092 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002093 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2094 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002095 std::unique_ptr<SessionDescription> updated_offer(
2096 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002097
2098 ASSERT_TRUE(updated_offer.get() != NULL);
2099 ac = updated_offer->GetContentByName("audio");
2100 vc = updated_offer->GetContentByName("video");
2101 dc = updated_offer->GetContentByName("data");
2102 ASSERT_TRUE(ac != NULL);
2103 ASSERT_TRUE(vc != NULL);
2104 ASSERT_TRUE(dc != NULL);
2105 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002106 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002107 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002108 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002109 const RtpDataContentDescription* updated_dcd =
2110 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002111
2112 EXPECT_EQ(acd->type(), updated_acd->type());
2113 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2114 EXPECT_EQ(vcd->type(), updated_vcd->type());
2115 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2116 EXPECT_EQ(dcd->type(), updated_dcd->type());
2117 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002118 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002119 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002120 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002121 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002122 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002123 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2124
2125 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2126 ASSERT_EQ(2U, updated_audio_streams.size());
2127 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2128 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2129 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2130 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2131 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2132
2133 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2134 ASSERT_EQ(2U, updated_video_streams.size());
2135 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2136 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002137 // All the media streams in one PeerConnection share one RTCP CNAME.
2138 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002139
2140 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2141 ASSERT_EQ(2U, updated_data_streams.size());
2142 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2143 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2144 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2145 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2146 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002147 // The stream correctly got the CNAME from the MediaSessionOptions.
2148 // The Expected RTCP CNAME is the default one as we are using the default
2149 // MediaSessionOptions.
2150 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151}
2152
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002153// Create an offer with simulcast video stream.
2154TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2155 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002156 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2157 RtpTransceiverDirection::kRecvOnly, kActive,
2158 &opts);
2159 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2160 RtpTransceiverDirection::kSendRecv, kActive,
2161 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002162 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002163 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2164 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002165 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002166
2167 ASSERT_TRUE(offer.get() != NULL);
2168 const ContentInfo* vc = offer->GetContentByName("video");
2169 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002170 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002171
2172 const StreamParamsVec& video_streams = vcd->streams();
2173 ASSERT_EQ(1U, video_streams.size());
2174 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2175 const SsrcGroup* sim_ssrc_group =
2176 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2177 ASSERT_TRUE(sim_ssrc_group != NULL);
2178 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2179}
2180
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002181MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2182 const RidDescription& rid1 = ::testing::get<0>(arg);
2183 const RidDescription& rid2 = ::testing::get<1>(arg);
2184 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2185}
2186
2187static void CheckSimulcastInSessionDescription(
2188 const SessionDescription* description,
2189 const std::string& content_name,
2190 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002191 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002192 ASSERT_NE(description, nullptr);
2193 const ContentInfo* content = description->GetContentByName(content_name);
2194 ASSERT_NE(content, nullptr);
2195 const MediaContentDescription* cd = content->media_description();
2196 ASSERT_NE(cd, nullptr);
2197 const StreamParamsVec& streams = cd->streams();
2198 ASSERT_THAT(streams, SizeIs(1));
2199 const StreamParams& stream = streams[0];
2200 ASSERT_THAT(stream.ssrcs, IsEmpty());
2201 EXPECT_TRUE(stream.has_rids());
2202 const std::vector<RidDescription> rids = stream.rids();
2203
2204 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2205
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002206 EXPECT_TRUE(cd->HasSimulcast());
2207 const SimulcastDescription& simulcast = cd->simulcast_description();
2208 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2209 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2210
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002211 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002212}
2213
2214// Create an offer with spec-compliant simulcast video stream.
2215TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2216 MediaSessionOptions opts;
2217 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2218 RtpTransceiverDirection::kSendRecv, kActive,
2219 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002220 std::vector<RidDescription> send_rids;
2221 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2222 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2223 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2224 SimulcastLayerList simulcast_layers;
2225 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2226 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2227 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2228 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2229 {kMediaStream1}, send_rids,
2230 simulcast_layers, 0, &opts);
2231 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2232
2233 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002234 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002235}
2236
2237// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2238// In this scenario, RIDs do not need to be negotiated (there is only one).
2239TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2240 MediaSessionOptions opts;
2241 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2242 RtpTransceiverDirection::kSendRecv, kActive,
2243 &opts);
2244 RidDescription rid("f", RidDirection::kSend);
2245 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2246 {kMediaStream1}, {rid},
2247 SimulcastLayerList(), 0, &opts);
2248 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2249
2250 ASSERT_NE(offer.get(), nullptr);
2251 const ContentInfo* content = offer->GetContentByName("video");
2252 ASSERT_NE(content, nullptr);
2253 const MediaContentDescription* cd = content->media_description();
2254 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002255 const StreamParamsVec& streams = cd->streams();
2256 ASSERT_THAT(streams, SizeIs(1));
2257 const StreamParams& stream = streams[0];
2258 ASSERT_THAT(stream.ssrcs, IsEmpty());
2259 EXPECT_FALSE(stream.has_rids());
2260 EXPECT_FALSE(cd->HasSimulcast());
2261}
2262
2263// Create an answer with spec-compliant simulcast video stream.
2264// In this scenario, the SFU is the caller requesting that we send Simulcast.
2265TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2266 MediaSessionOptions offer_opts;
2267 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2268 RtpTransceiverDirection::kSendRecv, kActive,
2269 &offer_opts);
2270 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2271 {kMediaStream1}, 1, &offer_opts);
2272 std::unique_ptr<SessionDescription> offer =
2273 f1_.CreateOffer(offer_opts, nullptr);
2274
2275 MediaSessionOptions answer_opts;
2276 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2277 RtpTransceiverDirection::kSendRecv, kActive,
2278 &answer_opts);
2279
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002280 std::vector<RidDescription> rid_descriptions{
2281 RidDescription("f", RidDirection::kSend),
2282 RidDescription("h", RidDirection::kSend),
2283 RidDescription("q", RidDirection::kSend),
2284 };
2285 SimulcastLayerList simulcast_layers;
2286 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2287 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2288 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2289 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2290 {kMediaStream1}, rid_descriptions,
2291 simulcast_layers, 0, &answer_opts);
2292 std::unique_ptr<SessionDescription> answer =
2293 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2294
2295 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002296 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002297}
2298
2299// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2300// In this scenario, RIDs do not need to be negotiated (there is only one).
2301// Note that RID Direction is not the same as the transceiver direction.
2302TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2303 MediaSessionOptions offer_opts;
2304 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2305 RtpTransceiverDirection::kSendRecv, kActive,
2306 &offer_opts);
2307 RidDescription rid_offer("f", RidDirection::kSend);
2308 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2309 {kMediaStream1}, {rid_offer},
2310 SimulcastLayerList(), 0, &offer_opts);
2311 std::unique_ptr<SessionDescription> offer =
2312 f1_.CreateOffer(offer_opts, nullptr);
2313
2314 MediaSessionOptions answer_opts;
2315 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2316 RtpTransceiverDirection::kSendRecv, kActive,
2317 &answer_opts);
2318
2319 RidDescription rid_answer("f", RidDirection::kReceive);
2320 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2321 {kMediaStream1}, {rid_answer},
2322 SimulcastLayerList(), 0, &answer_opts);
2323 std::unique_ptr<SessionDescription> answer =
2324 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2325
2326 ASSERT_NE(answer.get(), nullptr);
2327 const ContentInfo* content = offer->GetContentByName("video");
2328 ASSERT_NE(content, nullptr);
2329 const MediaContentDescription* cd = content->media_description();
2330 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002331 const StreamParamsVec& streams = cd->streams();
2332 ASSERT_THAT(streams, SizeIs(1));
2333 const StreamParams& stream = streams[0];
2334 ASSERT_THAT(stream.ssrcs, IsEmpty());
2335 EXPECT_FALSE(stream.has_rids());
2336 EXPECT_FALSE(cd->HasSimulcast());
2337}
2338
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002339// Create an audio and video answer to a standard video offer with:
2340// - one video track
2341// - two audio tracks
2342// - two data tracks
2343// and ensure it matches what we expect. Also updates the initial answer by
2344// adding a new video track and removes one of the audio tracks.
2345TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2346 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002347 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2348 RtpTransceiverDirection::kRecvOnly, kActive,
2349 &offer_opts);
2350 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2351 RtpTransceiverDirection::kRecvOnly, kActive,
2352 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002353 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002354 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2355 RtpTransceiverDirection::kRecvOnly, kActive,
2356 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002357 f1_.set_secure(SEC_ENABLED);
2358 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002359 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360
zhihuang1c378ed2017-08-17 14:10:50 -07002361 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002362 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2363 RtpTransceiverDirection::kSendRecv, kActive,
2364 &answer_opts);
2365 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2366 RtpTransceiverDirection::kSendRecv, kActive,
2367 &answer_opts);
2368 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2369 {kMediaStream1}, 1, &answer_opts);
2370 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2371 {kMediaStream1}, 1, &answer_opts);
2372 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2373 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002374
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002375 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2376 RtpTransceiverDirection::kSendRecv, kActive,
2377 &answer_opts);
2378 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2379 {kMediaStream1}, 1, &answer_opts);
2380 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2381 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002382 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383
Steve Anton6fe1fba2018-12-11 10:15:23 -08002384 std::unique_ptr<SessionDescription> answer =
2385 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002386
2387 ASSERT_TRUE(answer.get() != NULL);
2388 const ContentInfo* ac = answer->GetContentByName("audio");
2389 const ContentInfo* vc = answer->GetContentByName("video");
2390 const ContentInfo* dc = answer->GetContentByName("data");
2391 ASSERT_TRUE(ac != NULL);
2392 ASSERT_TRUE(vc != NULL);
2393 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002394 const AudioContentDescription* acd = ac->media_description()->as_audio();
2395 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002396 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002397 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2398 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2399 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002400
2401 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002402 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002403
2404 const StreamParamsVec& audio_streams = acd->streams();
2405 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002406 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002407 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2408 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2409 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2410 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2411 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2412 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2413
2414 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2415 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2416
2417 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002418 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002419
2420 const StreamParamsVec& video_streams = vcd->streams();
2421 ASSERT_EQ(1U, video_streams.size());
2422 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2423 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2424 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2425 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2426
2427 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002428 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002429
2430 const StreamParamsVec& data_streams = dcd->streams();
2431 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002432 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002433 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2434 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2435 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2436 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2437 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2438 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2439
2440 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002441 dcd->bandwidth()); // default bandwidth (auto)
2442 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002443
2444 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002445 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002446 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2447 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002448 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2449 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002450 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002451 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002452
2453 ASSERT_TRUE(updated_answer.get() != NULL);
2454 ac = updated_answer->GetContentByName("audio");
2455 vc = updated_answer->GetContentByName("video");
2456 dc = updated_answer->GetContentByName("data");
2457 ASSERT_TRUE(ac != NULL);
2458 ASSERT_TRUE(vc != NULL);
2459 ASSERT_TRUE(dc != NULL);
2460 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002461 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002462 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002463 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002464 const RtpDataContentDescription* updated_dcd =
2465 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002466
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002467 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002468 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002469 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002470 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002471 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002472 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2473
2474 EXPECT_EQ(acd->type(), updated_acd->type());
2475 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2476 EXPECT_EQ(vcd->type(), updated_vcd->type());
2477 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2478 EXPECT_EQ(dcd->type(), updated_dcd->type());
2479 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2480
2481 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2482 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002483 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002484
2485 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2486 ASSERT_EQ(2U, updated_video_streams.size());
2487 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2488 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002489 // All media streams in one PeerConnection share one CNAME.
2490 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002491
2492 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2493 ASSERT_EQ(1U, updated_data_streams.size());
2494 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2495}
2496
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002497// Create an updated offer after creating an answer to the original offer and
2498// verify that the codecs that were part of the original answer are not changed
2499// in the updated offer.
2500TEST_F(MediaSessionDescriptionFactoryTest,
2501 RespondentCreatesOfferAfterCreatingAnswer) {
2502 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002503 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002504
Steve Anton6fe1fba2018-12-11 10:15:23 -08002505 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2506 std::unique_ptr<SessionDescription> answer =
2507 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002508
2509 const AudioContentDescription* acd =
2510 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002511 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002512
2513 const VideoContentDescription* vcd =
2514 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002515 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002516
kwiberg31022942016-03-11 14:18:21 -08002517 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002518 f2_.CreateOffer(opts, answer.get()));
2519
2520 // The expected audio codecs are the common audio codecs from the first
2521 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2522 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002523 // TODO(wu): |updated_offer| should not include the codec
2524 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002525 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002526 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002527 };
2528
2529 // The expected video codecs are the common video codecs from the first
2530 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2531 // preference order.
2532 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002533 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002534 };
2535
2536 const AudioContentDescription* updated_acd =
2537 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002538 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002539
2540 const VideoContentDescription* updated_vcd =
2541 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002542 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002543}
2544
Steve Anton5c72e712018-12-10 14:25:30 -08002545// Test that a reoffer does not reuse audio codecs from a previous media section
2546// that is being recycled.
2547TEST_F(MediaSessionDescriptionFactoryTest,
2548 ReOfferDoesNotReUseRecycledAudioCodecs) {
2549 f1_.set_video_codecs({});
2550 f2_.set_video_codecs({});
2551
2552 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002553 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2554 RtpTransceiverDirection::kSendRecv, kActive,
2555 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002556 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2557 std::unique_ptr<SessionDescription> answer =
2558 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002559
2560 // Recycle the media section by changing its mid.
2561 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002562 std::unique_ptr<SessionDescription> reoffer =
2563 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002564
2565 // Expect that the results of the first negotiation are ignored. If the m=
2566 // section was not recycled the payload types would match the initial offerer.
2567 const AudioContentDescription* acd =
2568 GetFirstAudioContentDescription(reoffer.get());
2569 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2570}
2571
2572// Test that a reoffer does not reuse video codecs from a previous media section
2573// that is being recycled.
2574TEST_F(MediaSessionDescriptionFactoryTest,
2575 ReOfferDoesNotReUseRecycledVideoCodecs) {
2576 f1_.set_audio_codecs({}, {});
2577 f2_.set_audio_codecs({}, {});
2578
2579 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002580 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2581 RtpTransceiverDirection::kSendRecv, kActive,
2582 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002583 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2584 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002585
2586 // Recycle the media section by changing its mid.
2587 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002588 std::unique_ptr<SessionDescription> reoffer =
2589 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002590
2591 // Expect that the results of the first negotiation are ignored. If the m=
2592 // section was not recycled the payload types would match the initial offerer.
2593 const VideoContentDescription* vcd =
2594 GetFirstVideoContentDescription(reoffer.get());
2595 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2596}
2597
2598// Test that a reanswer does not reuse audio codecs from a previous media
2599// section that is being recycled.
2600TEST_F(MediaSessionDescriptionFactoryTest,
2601 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2602 f1_.set_video_codecs({});
2603 f2_.set_video_codecs({});
2604
2605 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2606 // second offer/answer is forward (|f1_| as offerer).
2607 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002608 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2609 RtpTransceiverDirection::kSendRecv, kActive,
2610 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002611 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2612 std::unique_ptr<SessionDescription> answer =
2613 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002614
2615 // Recycle the media section by changing its mid.
2616 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002617 std::unique_ptr<SessionDescription> reoffer =
2618 f1_.CreateOffer(opts, answer.get());
2619 std::unique_ptr<SessionDescription> reanswer =
2620 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002621
2622 // Expect that the results of the first negotiation are ignored. If the m=
2623 // section was not recycled the payload types would match the initial offerer.
2624 const AudioContentDescription* acd =
2625 GetFirstAudioContentDescription(reanswer.get());
2626 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2627}
2628
2629// Test that a reanswer does not reuse video codecs from a previous media
2630// section that is being recycled.
2631TEST_F(MediaSessionDescriptionFactoryTest,
2632 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2633 f1_.set_audio_codecs({}, {});
2634 f2_.set_audio_codecs({}, {});
2635
2636 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2637 // second offer/answer is forward (|f1_| as offerer).
2638 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002639 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2640 RtpTransceiverDirection::kSendRecv, kActive,
2641 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002642 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2643 std::unique_ptr<SessionDescription> answer =
2644 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002645
2646 // Recycle the media section by changing its mid.
2647 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002648 std::unique_ptr<SessionDescription> reoffer =
2649 f1_.CreateOffer(opts, answer.get());
2650 std::unique_ptr<SessionDescription> reanswer =
2651 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002652
2653 // Expect that the results of the first negotiation are ignored. If the m=
2654 // section was not recycled the payload types would match the initial offerer.
2655 const VideoContentDescription* vcd =
2656 GetFirstVideoContentDescription(reanswer.get());
2657 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2658}
2659
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002660// Create an updated offer after creating an answer to the original offer and
2661// verify that the codecs that were part of the original answer are not changed
2662// in the updated offer. In this test Rtx is enabled.
2663TEST_F(MediaSessionDescriptionFactoryTest,
2664 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2665 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002666 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2667 RtpTransceiverDirection::kRecvOnly, kActive,
2668 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002669 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002671 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002672 f1_.set_video_codecs(f1_codecs);
2673
2674 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002675 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002676 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002677 f2_.set_video_codecs(f2_codecs);
2678
Steve Anton6fe1fba2018-12-11 10:15:23 -08002679 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002681 std::unique_ptr<SessionDescription> answer =
2682 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002683
2684 const VideoContentDescription* vcd =
2685 GetFirstVideoContentDescription(answer.get());
2686
2687 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002688 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2689 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002690
2691 EXPECT_EQ(expected_codecs, vcd->codecs());
2692
deadbeef67cf2c12016-04-13 10:07:16 -07002693 // Now, make sure we get same result (except for the order) if |f2_| creates
2694 // an updated offer even though the default payload types between |f1_| and
2695 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002696 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002697 f2_.CreateOffer(opts, answer.get()));
2698 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002699 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002700 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2701
2702 const VideoContentDescription* updated_vcd =
2703 GetFirstVideoContentDescription(updated_answer.get());
2704
2705 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2706}
2707
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002708// Regression test for:
2709// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2710// Existing codecs should always appear before new codecs in re-offers. But
2711// under a specific set of circumstances, the existing RTX codec was ending up
2712// added to the end of the list.
2713TEST_F(MediaSessionDescriptionFactoryTest,
2714 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2715 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002716 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2717 RtpTransceiverDirection::kRecvOnly, kActive,
2718 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002719 // We specifically choose different preferred payload types for VP8 to
2720 // trigger the issue.
2721 cricket::VideoCodec vp8_offerer(100, "VP8");
2722 cricket::VideoCodec vp8_offerer_rtx =
2723 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2724 cricket::VideoCodec vp8_answerer(110, "VP8");
2725 cricket::VideoCodec vp8_answerer_rtx =
2726 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2727 cricket::VideoCodec vp9(120, "VP9");
2728 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2729
2730 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2731 // We also specifically cause the answerer to prefer VP9, such that if it
2732 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2733 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2734 vp8_answerer_rtx};
2735
2736 f1_.set_video_codecs(f1_codecs);
2737 f2_.set_video_codecs(f2_codecs);
2738 std::vector<AudioCodec> audio_codecs;
2739 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2740 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2741
2742 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002743 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002744 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002745 std::unique_ptr<SessionDescription> answer =
2746 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002747
2748 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2749 // But if the bug is triggered, RTX for VP8 ends up last.
2750 std::unique_ptr<SessionDescription> updated_offer(
2751 f2_.CreateOffer(opts, answer.get()));
2752
2753 const VideoContentDescription* vcd =
2754 GetFirstVideoContentDescription(updated_offer.get());
2755 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2756 ASSERT_EQ(4u, codecs.size());
2757 EXPECT_EQ(vp8_offerer, codecs[0]);
2758 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2759 EXPECT_EQ(vp9, codecs[2]);
2760 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002761}
2762
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002763// Create an updated offer that adds video after creating an audio only answer
2764// to the original offer. This test verifies that if a video codec and the RTX
2765// codec have the same default payload type as an audio codec that is already in
2766// use, the added codecs payload types are changed.
2767TEST_F(MediaSessionDescriptionFactoryTest,
2768 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2769 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002770 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002771 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002772 f1_.set_video_codecs(f1_codecs);
2773
2774 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002775 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2776 RtpTransceiverDirection::kRecvOnly, kActive,
2777 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002778
Steve Anton6fe1fba2018-12-11 10:15:23 -08002779 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2780 std::unique_ptr<SessionDescription> answer =
2781 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002782
2783 const AudioContentDescription* acd =
2784 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002785 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786
2787 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2788 // reference be the same as an audio codec that was negotiated in the
2789 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002790 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002791 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002792
2793 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2794 int used_pl_type = acd->codecs()[0].id;
2795 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002796 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002797 f2_.set_video_codecs(f2_codecs);
2798
kwiberg31022942016-03-11 14:18:21 -08002799 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002800 f2_.CreateOffer(opts, answer.get()));
2801 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002802 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002803 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2804
2805 const AudioContentDescription* updated_acd =
2806 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002807 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002808
2809 const VideoContentDescription* updated_vcd =
2810 GetFirstVideoContentDescription(updated_answer.get());
2811
2812 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002813 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002814 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002815 EXPECT_NE(used_pl_type, new_h264_pl_type);
2816 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002817 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002818 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2819 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2820}
2821
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002822// Create an updated offer with RTX after creating an answer to an offer
2823// without RTX, and with different default payload types.
2824// Verify that the added RTX codec references the correct payload type.
2825TEST_F(MediaSessionDescriptionFactoryTest,
2826 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2827 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002828 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002829
2830 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2831 // This creates rtx for H264 with the payload type |f2_| uses.
2832 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2833 f2_.set_video_codecs(f2_codecs);
2834
Steve Anton6fe1fba2018-12-11 10:15:23 -08002835 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002836 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002837 std::unique_ptr<SessionDescription> answer =
2838 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002839
2840 const VideoContentDescription* vcd =
2841 GetFirstVideoContentDescription(answer.get());
2842
2843 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2844 EXPECT_EQ(expected_codecs, vcd->codecs());
2845
2846 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2847 // updated offer, even though the default payload types are different from
2848 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002849 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002850 f2_.CreateOffer(opts, answer.get()));
2851 ASSERT_TRUE(updated_offer);
2852
2853 const VideoContentDescription* updated_vcd =
2854 GetFirstVideoContentDescription(updated_offer.get());
2855
2856 // New offer should attempt to add H263, and RTX for H264.
2857 expected_codecs.push_back(kVideoCodecs2[1]);
2858 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2859 &expected_codecs);
2860 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2861}
2862
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002863// Test that RTX is ignored when there is no associated payload type parameter.
2864TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2865 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002866 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2867 RtpTransceiverDirection::kRecvOnly, kActive,
2868 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002869 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002870 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002871 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002872 f1_.set_video_codecs(f1_codecs);
2873
2874 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002875 // This creates RTX for H264 with the payload type |f2_| uses.
2876 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002877 f2_.set_video_codecs(f2_codecs);
2878
Steve Anton6fe1fba2018-12-11 10:15:23 -08002879 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002880 ASSERT_TRUE(offer.get() != NULL);
2881 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2882 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2883 // is possible to test that that RTX is dropped when
2884 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002885 MediaContentDescription* media_desc =
2886 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2887 ASSERT_TRUE(media_desc);
2888 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002889 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002890 for (VideoCodec& codec : codecs) {
2891 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2892 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002893 }
2894 }
2895 desc->set_codecs(codecs);
2896
Steve Anton6fe1fba2018-12-11 10:15:23 -08002897 std::unique_ptr<SessionDescription> answer =
2898 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002899
Steve Anton64b626b2019-01-28 17:25:26 -08002900 EXPECT_THAT(
2901 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2902 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002903}
2904
2905// Test that RTX will be filtered out in the answer if its associated payload
2906// type doesn't match the local value.
2907TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2908 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002909 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2910 RtpTransceiverDirection::kRecvOnly, kActive,
2911 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002912 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2913 // This creates RTX for H264 in sender.
2914 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2915 f1_.set_video_codecs(f1_codecs);
2916
2917 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2918 // This creates RTX for H263 in receiver.
2919 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2920 f2_.set_video_codecs(f2_codecs);
2921
Steve Anton6fe1fba2018-12-11 10:15:23 -08002922 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002923 ASSERT_TRUE(offer.get() != NULL);
2924 // Associated payload type doesn't match, therefore, RTX codec is removed in
2925 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002926 std::unique_ptr<SessionDescription> answer =
2927 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002928
Steve Anton64b626b2019-01-28 17:25:26 -08002929 EXPECT_THAT(
2930 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2931 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002932}
2933
2934// Test that when multiple RTX codecs are offered, only the matched RTX codec
2935// is added in the answer, and the unsupported RTX codec is filtered out.
2936TEST_F(MediaSessionDescriptionFactoryTest,
2937 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2938 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002939 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2940 RtpTransceiverDirection::kRecvOnly, kActive,
2941 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002942 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2943 // This creates RTX for H264-SVC in sender.
2944 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2945 f1_.set_video_codecs(f1_codecs);
2946
2947 // This creates RTX for H264 in sender.
2948 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2949 f1_.set_video_codecs(f1_codecs);
2950
2951 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2952 // This creates RTX for H264 in receiver.
2953 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2954 f2_.set_video_codecs(f2_codecs);
2955
2956 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2957 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002958 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002959 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002960 std::unique_ptr<SessionDescription> answer =
2961 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002962 const VideoContentDescription* vcd =
2963 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002964 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2965 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2966 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002967
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002968 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002969}
2970
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002971// Test that after one RTX codec has been negotiated, a new offer can attempt
2972// to add another.
2973TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2974 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002975 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2976 RtpTransceiverDirection::kRecvOnly, kActive,
2977 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002978 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2979 // This creates RTX for H264 for the offerer.
2980 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2981 f1_.set_video_codecs(f1_codecs);
2982
Steve Anton6fe1fba2018-12-11 10:15:23 -08002983 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002984 ASSERT_TRUE(offer);
2985 const VideoContentDescription* vcd =
2986 GetFirstVideoContentDescription(offer.get());
2987
2988 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2989 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2990 &expected_codecs);
2991 EXPECT_EQ(expected_codecs, vcd->codecs());
2992
2993 // Now, attempt to add RTX for H264-SVC.
2994 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2995 f1_.set_video_codecs(f1_codecs);
2996
kwiberg31022942016-03-11 14:18:21 -08002997 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002998 f1_.CreateOffer(opts, offer.get()));
2999 ASSERT_TRUE(updated_offer);
3000 vcd = GetFirstVideoContentDescription(updated_offer.get());
3001
3002 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3003 &expected_codecs);
3004 EXPECT_EQ(expected_codecs, vcd->codecs());
3005}
3006
Noah Richards2e7a0982015-05-18 14:02:54 -07003007// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3008// generated for each simulcast ssrc and correctly grouped.
3009TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3010 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003011 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3012 RtpTransceiverDirection::kSendRecv, kActive,
3013 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003014 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003015 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3016 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003017
3018 // Use a single real codec, and then add RTX for it.
3019 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003020 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003021 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
3022 f1_.set_video_codecs(f1_codecs);
3023
3024 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3025 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003026 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003027 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003028 MediaContentDescription* media_desc =
3029 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3030 ASSERT_TRUE(media_desc);
3031 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003032 const StreamParamsVec& streams = desc->streams();
3033 // Single stream.
3034 ASSERT_EQ(1u, streams.size());
3035 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3036 EXPECT_EQ(6u, streams[0].ssrcs.size());
3037 // And should have a SIM group for the simulcast.
3038 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3039 // And a FID group for RTX.
3040 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003041 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003042 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3043 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003044 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003045 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3046 EXPECT_EQ(3u, fid_ssrcs.size());
3047}
3048
brandtr03d5fb12016-11-22 03:37:59 -08003049// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3050// together with a FEC-FR grouping.
3051TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3052 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003053 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3054 RtpTransceiverDirection::kSendRecv, kActive,
3055 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003056 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003057 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3058 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003059
3060 // Use a single real codec, and then add FlexFEC for it.
3061 std::vector<VideoCodec> f1_codecs;
3062 f1_codecs.push_back(VideoCodec(97, "H264"));
3063 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3064 f1_.set_video_codecs(f1_codecs);
3065
3066 // Ensure that the offer has a single FlexFEC ssrc and that
3067 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003068 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003069 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003070 MediaContentDescription* media_desc =
3071 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3072 ASSERT_TRUE(media_desc);
3073 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003074 const StreamParamsVec& streams = desc->streams();
3075 // Single stream.
3076 ASSERT_EQ(1u, streams.size());
3077 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3078 EXPECT_EQ(2u, streams[0].ssrcs.size());
3079 // And should have a FEC-FR group for FlexFEC.
3080 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3081 std::vector<uint32_t> primary_ssrcs;
3082 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3083 ASSERT_EQ(1u, primary_ssrcs.size());
3084 uint32_t flexfec_ssrc;
3085 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3086 EXPECT_NE(flexfec_ssrc, 0u);
3087}
3088
3089// Test that FlexFEC is disabled for simulcast.
3090// TODO(brandtr): Remove this test when we support simulcast, either through
3091// multiple FlexfecSenders, or through multistream protection.
3092TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3093 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003094 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3095 RtpTransceiverDirection::kSendRecv, kActive,
3096 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003097 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003098 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3099 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003100
3101 // Use a single real codec, and then add FlexFEC for it.
3102 std::vector<VideoCodec> f1_codecs;
3103 f1_codecs.push_back(VideoCodec(97, "H264"));
3104 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3105 f1_.set_video_codecs(f1_codecs);
3106
3107 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3108 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003109 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003110 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003111 MediaContentDescription* media_desc =
3112 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3113 ASSERT_TRUE(media_desc);
3114 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003115 const StreamParamsVec& streams = desc->streams();
3116 // Single stream.
3117 ASSERT_EQ(1u, streams.size());
3118 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3119 EXPECT_EQ(3u, streams[0].ssrcs.size());
3120 // And should have a SIM group for the simulcast.
3121 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3122 // And not a FEC-FR group for FlexFEC.
3123 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3124 std::vector<uint32_t> primary_ssrcs;
3125 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3126 EXPECT_EQ(3u, primary_ssrcs.size());
3127 for (uint32_t primary_ssrc : primary_ssrcs) {
3128 uint32_t flexfec_ssrc;
3129 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3130 }
3131}
3132
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003133// Create an updated offer after creating an answer to the original offer and
3134// verify that the RTP header extensions that were part of the original answer
3135// are not changed in the updated offer.
3136TEST_F(MediaSessionDescriptionFactoryTest,
3137 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3138 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003139 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003140
3141 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3142 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3143 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3144 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3145
Steve Anton6fe1fba2018-12-11 10:15:23 -08003146 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3147 std::unique_ptr<SessionDescription> answer =
3148 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003149
Yves Gerey665174f2018-06-19 15:03:05 +02003150 EXPECT_EQ(
3151 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3152 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3153 EXPECT_EQ(
3154 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3155 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003156
kwiberg31022942016-03-11 14:18:21 -08003157 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003158 f2_.CreateOffer(opts, answer.get()));
3159
3160 // The expected RTP header extensions in the new offer are the resulting
3161 // extensions from the first offer/answer exchange plus the extensions only
3162 // |f2_| offer.
3163 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003164 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003165 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3166 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3167 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003168 };
3169
3170 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003171 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003172 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3173 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3174 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003175 };
3176
3177 const AudioContentDescription* updated_acd =
3178 GetFirstAudioContentDescription(updated_offer.get());
3179 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3180 updated_acd->rtp_header_extensions());
3181
3182 const VideoContentDescription* updated_vcd =
3183 GetFirstVideoContentDescription(updated_offer.get());
3184 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3185 updated_vcd->rtp_header_extensions());
3186}
3187
deadbeefa5b273a2015-08-20 17:30:13 -07003188// Verify that if the same RTP extension URI is used for audio and video, the
3189// same ID is used. Also verify that the ID isn't changed when creating an
3190// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003191TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003192 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003193 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003194
3195 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3196 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3197
Steve Anton6fe1fba2018-12-11 10:15:23 -08003198 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003199
3200 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3201 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003202 const RtpExtension kExpectedVideoRtpExtension[] = {
3203 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003204 };
3205
Yves Gerey665174f2018-06-19 15:03:05 +02003206 EXPECT_EQ(
3207 MAKE_VECTOR(kAudioRtpExtension3),
3208 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3209 EXPECT_EQ(
3210 MAKE_VECTOR(kExpectedVideoRtpExtension),
3211 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003212
3213 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003214 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003215 f1_.CreateOffer(opts, offer.get()));
3216
3217 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003218 GetFirstAudioContentDescription(updated_offer.get())
3219 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003220 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003221 GetFirstVideoContentDescription(updated_offer.get())
3222 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003223}
3224
jbauch5869f502017-06-29 12:31:36 -07003225// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3226TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3227 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003228 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003229
3230 f1_.set_enable_encrypted_rtp_header_extensions(true);
3231 f2_.set_enable_encrypted_rtp_header_extensions(true);
3232
3233 f1_.set_audio_rtp_header_extensions(
3234 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3235 f1_.set_video_rtp_header_extensions(
3236 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3237
Steve Anton6fe1fba2018-12-11 10:15:23 -08003238 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003239
3240 // The extensions that are shared between audio and video should use the same
3241 // id.
3242 const RtpExtension kExpectedVideoRtpExtension[] = {
3243 kVideoRtpExtension3ForEncryption[0],
3244 kAudioRtpExtension3ForEncryptionOffer[1],
3245 kAudioRtpExtension3ForEncryptionOffer[2],
3246 };
3247
Yves Gerey665174f2018-06-19 15:03:05 +02003248 EXPECT_EQ(
3249 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3250 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3251 EXPECT_EQ(
3252 MAKE_VECTOR(kExpectedVideoRtpExtension),
3253 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003254
3255 // Nothing should change when creating a new offer
3256 std::unique_ptr<SessionDescription> updated_offer(
3257 f1_.CreateOffer(opts, offer.get()));
3258
3259 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003260 GetFirstAudioContentDescription(updated_offer.get())
3261 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003262 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003263 GetFirstVideoContentDescription(updated_offer.get())
3264 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003265}
3266
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003267TEST(MediaSessionDescription, CopySessionDescription) {
3268 SessionDescription source;
3269 cricket::ContentGroup group(cricket::CN_AUDIO);
3270 source.AddGroup(group);
3271 AudioContentDescription* acd(new AudioContentDescription());
3272 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3273 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003274 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003275 VideoContentDescription* vcd(new VideoContentDescription());
3276 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3277 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003278 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003279
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003280 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003281 ASSERT_TRUE(copy.get() != NULL);
3282 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3283 const ContentInfo* ac = copy->GetContentByName("audio");
3284 const ContentInfo* vc = copy->GetContentByName("video");
3285 ASSERT_TRUE(ac != NULL);
3286 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003287 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003288 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003289 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3290 EXPECT_EQ(1u, acd->first_ssrc());
3291
Steve Anton5adfafd2017-12-20 16:34:00 -08003292 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003293 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003294 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3295 EXPECT_EQ(2u, vcd->first_ssrc());
3296}
3297
3298// The below TestTransportInfoXXX tests create different offers/answers, and
3299// ensure the TransportInfo in the SessionDescription matches what we expect.
3300TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3301 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003302 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3303 RtpTransceiverDirection::kRecvOnly, kActive,
3304 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003305 TestTransportInfo(true, options, false);
3306}
3307
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003308TEST_F(MediaSessionDescriptionFactoryTest,
3309 TestTransportInfoOfferIceRenomination) {
3310 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003311 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3312 RtpTransceiverDirection::kRecvOnly, kActive,
3313 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003314 options.media_description_options[0]
3315 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003316 TestTransportInfo(true, options, false);
3317}
3318
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003319TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3320 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003321 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3322 RtpTransceiverDirection::kRecvOnly, kActive,
3323 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003324 TestTransportInfo(true, options, true);
3325}
3326
3327TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3328 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003329 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3330 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3331 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003332 TestTransportInfo(true, options, false);
3333}
3334
3335TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003336 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003337 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003338 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3339 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3340 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003341 TestTransportInfo(true, options, true);
3342}
3343
3344TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3345 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003346 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3347 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3348 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003349 options.bundle_enabled = true;
3350 TestTransportInfo(true, options, false);
3351}
3352
3353TEST_F(MediaSessionDescriptionFactoryTest,
3354 TestTransportInfoOfferBundleCurrent) {
3355 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003356 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3357 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3358 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003359 options.bundle_enabled = true;
3360 TestTransportInfo(true, options, true);
3361}
3362
3363TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3364 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003365 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3366 RtpTransceiverDirection::kRecvOnly, kActive,
3367 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003368 TestTransportInfo(false, options, false);
3369}
3370
3371TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003372 TestTransportInfoAnswerIceRenomination) {
3373 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003374 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3375 RtpTransceiverDirection::kRecvOnly, kActive,
3376 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003377 options.media_description_options[0]
3378 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003379 TestTransportInfo(false, options, false);
3380}
3381
3382TEST_F(MediaSessionDescriptionFactoryTest,
3383 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003384 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003385 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3386 RtpTransceiverDirection::kRecvOnly, kActive,
3387 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003388 TestTransportInfo(false, options, true);
3389}
3390
3391TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3392 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003393 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3394 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3395 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003396 TestTransportInfo(false, options, false);
3397}
3398
3399TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003400 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003401 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003402 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3403 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3404 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003405 TestTransportInfo(false, options, true);
3406}
3407
3408TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3409 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003410 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3411 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3412 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003413 options.bundle_enabled = true;
3414 TestTransportInfo(false, options, false);
3415}
3416
3417TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003418 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003419 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003420 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3421 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3422 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003423 options.bundle_enabled = true;
3424 TestTransportInfo(false, options, true);
3425}
3426
3427// Create an offer with bundle enabled and verify the crypto parameters are
3428// the common set of the available cryptos.
3429TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3430 TestCryptoWithBundle(true);
3431}
3432
3433// Create an answer with bundle enabled and verify the crypto parameters are
3434// the common set of the available cryptos.
3435TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3436 TestCryptoWithBundle(false);
3437}
3438
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003439// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3440// DTLS is not enabled locally.
3441TEST_F(MediaSessionDescriptionFactoryTest,
3442 TestOfferDtlsSavpfWithoutDtlsFailed) {
3443 f1_.set_secure(SEC_ENABLED);
3444 f2_.set_secure(SEC_ENABLED);
3445 tdf1_.set_secure(SEC_DISABLED);
3446 tdf2_.set_secure(SEC_DISABLED);
3447
Steve Anton6fe1fba2018-12-11 10:15:23 -08003448 std::unique_ptr<SessionDescription> offer =
3449 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003450 ASSERT_TRUE(offer.get() != NULL);
3451 ContentInfo* offer_content = offer->GetContentByName("audio");
3452 ASSERT_TRUE(offer_content != NULL);
3453 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003454 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003455 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3456
Steve Anton6fe1fba2018-12-11 10:15:23 -08003457 std::unique_ptr<SessionDescription> answer =
3458 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003459 ASSERT_TRUE(answer != NULL);
3460 ContentInfo* answer_content = answer->GetContentByName("audio");
3461 ASSERT_TRUE(answer_content != NULL);
3462
3463 ASSERT_TRUE(answer_content->rejected);
3464}
3465
3466// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3467// UDP/TLS/RTP/SAVPF.
3468TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3469 f1_.set_secure(SEC_ENABLED);
3470 f2_.set_secure(SEC_ENABLED);
3471 tdf1_.set_secure(SEC_ENABLED);
3472 tdf2_.set_secure(SEC_ENABLED);
3473
Steve Anton6fe1fba2018-12-11 10:15:23 -08003474 std::unique_ptr<SessionDescription> offer =
3475 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003476 ASSERT_TRUE(offer.get() != NULL);
3477 ContentInfo* offer_content = offer->GetContentByName("audio");
3478 ASSERT_TRUE(offer_content != NULL);
3479 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003480 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003481 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3482
Steve Anton6fe1fba2018-12-11 10:15:23 -08003483 std::unique_ptr<SessionDescription> answer =
3484 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003485 ASSERT_TRUE(answer != NULL);
3486
3487 const ContentInfo* answer_content = answer->GetContentByName("audio");
3488 ASSERT_TRUE(answer_content != NULL);
3489 ASSERT_FALSE(answer_content->rejected);
3490
3491 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003492 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003493 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003494}
3495
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003496// Test that we include both SDES and DTLS in the offer, but only include SDES
3497// in the answer if DTLS isn't negotiated.
3498TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3499 f1_.set_secure(SEC_ENABLED);
3500 f2_.set_secure(SEC_ENABLED);
3501 tdf1_.set_secure(SEC_ENABLED);
3502 tdf2_.set_secure(SEC_DISABLED);
3503 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003504 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003505 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003506 const cricket::MediaContentDescription* audio_media_desc;
3507 const cricket::MediaContentDescription* video_media_desc;
3508 const cricket::TransportDescription* audio_trans_desc;
3509 const cricket::TransportDescription* video_trans_desc;
3510
3511 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003512 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003513 ASSERT_TRUE(offer.get() != NULL);
3514
Steve Antonb1c1de12017-12-21 15:14:30 -08003515 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003516 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003517 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003518 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003519 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003520 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3521
3522 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3523 ASSERT_TRUE(audio_trans_desc != NULL);
3524 video_trans_desc = offer->GetTransportDescriptionByName("video");
3525 ASSERT_TRUE(video_trans_desc != NULL);
3526 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3527 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3528
3529 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003530 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003531 ASSERT_TRUE(answer.get() != NULL);
3532
Steve Antonb1c1de12017-12-21 15:14:30 -08003533 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003534 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003535 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003536 ASSERT_TRUE(video_media_desc != NULL);
3537 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3538 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3539
3540 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3541 ASSERT_TRUE(audio_trans_desc != NULL);
3542 video_trans_desc = answer->GetTransportDescriptionByName("video");
3543 ASSERT_TRUE(video_trans_desc != NULL);
3544 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3545 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3546
3547 // Enable DTLS; the answer should now only have DTLS support.
3548 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003549 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003550 ASSERT_TRUE(answer.get() != NULL);
3551
Steve Antonb1c1de12017-12-21 15:14:30 -08003552 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003553 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003554 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003555 ASSERT_TRUE(video_media_desc != NULL);
3556 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3557 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003558 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3559 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003560
3561 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3562 ASSERT_TRUE(audio_trans_desc != NULL);
3563 video_trans_desc = answer->GetTransportDescriptionByName("video");
3564 ASSERT_TRUE(video_trans_desc != NULL);
3565 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3566 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003567
3568 // Try creating offer again. DTLS enabled now, crypto's should be empty
3569 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003570 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003571 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003572 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003573 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003574 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003575 ASSERT_TRUE(video_media_desc != NULL);
3576 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3577 EXPECT_TRUE(video_media_desc->cryptos().empty());
3578
3579 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3580 ASSERT_TRUE(audio_trans_desc != NULL);
3581 video_trans_desc = offer->GetTransportDescriptionByName("video");
3582 ASSERT_TRUE(video_trans_desc != NULL);
3583 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3584 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003585}
3586
3587// Test that an answer can't be created if cryptos are required but the offer is
3588// unsecure.
3589TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003590 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003591 f1_.set_secure(SEC_DISABLED);
3592 tdf1_.set_secure(SEC_DISABLED);
3593 f2_.set_secure(SEC_REQUIRED);
3594 tdf1_.set_secure(SEC_ENABLED);
3595
Steve Anton6fe1fba2018-12-11 10:15:23 -08003596 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003597 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003598 std::unique_ptr<SessionDescription> answer =
3599 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003600 EXPECT_TRUE(answer.get() == NULL);
3601}
3602
3603// Test that we accept a DTLS offer without SDES and create an appropriate
3604// answer.
3605TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3606 f1_.set_secure(SEC_DISABLED);
3607 f2_.set_secure(SEC_ENABLED);
3608 tdf1_.set_secure(SEC_ENABLED);
3609 tdf2_.set_secure(SEC_ENABLED);
3610 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003611 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3612 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3613 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003614
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003615 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003616 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003617 ASSERT_TRUE(offer.get() != NULL);
3618
3619 const AudioContentDescription* audio_offer =
3620 GetFirstAudioContentDescription(offer.get());
3621 ASSERT_TRUE(audio_offer->cryptos().empty());
3622 const VideoContentDescription* video_offer =
3623 GetFirstVideoContentDescription(offer.get());
3624 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003625 const RtpDataContentDescription* data_offer =
3626 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003627 ASSERT_TRUE(data_offer->cryptos().empty());
3628
3629 const cricket::TransportDescription* audio_offer_trans_desc =
3630 offer->GetTransportDescriptionByName("audio");
3631 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3632 const cricket::TransportDescription* video_offer_trans_desc =
3633 offer->GetTransportDescriptionByName("video");
3634 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3635 const cricket::TransportDescription* data_offer_trans_desc =
3636 offer->GetTransportDescriptionByName("data");
3637 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3638
3639 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003640 std::unique_ptr<SessionDescription> answer =
3641 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003642 ASSERT_TRUE(answer.get() != NULL);
3643
3644 const cricket::TransportDescription* audio_answer_trans_desc =
3645 answer->GetTransportDescriptionByName("audio");
3646 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3647 const cricket::TransportDescription* video_answer_trans_desc =
3648 answer->GetTransportDescriptionByName("video");
3649 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3650 const cricket::TransportDescription* data_answer_trans_desc =
3651 answer->GetTransportDescriptionByName("data");
3652 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3653}
3654
3655// Verifies if vad_enabled option is set to false, CN codecs are not present in
3656// offer or answer.
3657TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3658 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003659 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003660 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003661 ASSERT_TRUE(offer.get() != NULL);
3662 const ContentInfo* audio_content = offer->GetContentByName("audio");
3663 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3664
3665 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003666 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003667 ASSERT_TRUE(offer.get() != NULL);
3668 audio_content = offer->GetContentByName("audio");
3669 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003670 std::unique_ptr<SessionDescription> answer =
3671 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003672 ASSERT_TRUE(answer.get() != NULL);
3673 audio_content = answer->GetContentByName("audio");
3674 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3675}
deadbeef44f08192015-12-15 16:20:09 -08003676
zhihuang1c378ed2017-08-17 14:10:50 -07003677// Test that the generated MIDs match the existing offer.
3678TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003679 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003680 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3681 RtpTransceiverDirection::kRecvOnly, kActive,
3682 &opts);
3683 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3684 RtpTransceiverDirection::kRecvOnly, kActive,
3685 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003686 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003687 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3688 RtpTransceiverDirection::kSendRecv, kActive,
3689 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003690 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003691 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003692 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003693 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003694
deadbeef44f08192015-12-15 16:20:09 -08003695 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3696 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3697 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3698 ASSERT_TRUE(audio_content != nullptr);
3699 ASSERT_TRUE(video_content != nullptr);
3700 ASSERT_TRUE(data_content != nullptr);
3701 EXPECT_EQ("audio_modified", audio_content->name);
3702 EXPECT_EQ("video_modified", video_content->name);
3703 EXPECT_EQ("data_modified", data_content->name);
3704}
zhihuangcf5b37c2016-05-05 11:44:35 -07003705
zhihuang1c378ed2017-08-17 14:10:50 -07003706// The following tests verify that the unified plan SDP is supported.
3707// Test that we can create an offer with multiple media sections of same media
3708// type.
3709TEST_F(MediaSessionDescriptionFactoryTest,
3710 CreateOfferWithMultipleAVMediaSections) {
3711 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003712 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3713 RtpTransceiverDirection::kSendRecv, kActive,
3714 &opts);
3715 AttachSenderToMediaDescriptionOptions(
3716 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003717
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003718 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3719 RtpTransceiverDirection::kSendRecv, kActive,
3720 &opts);
3721 AttachSenderToMediaDescriptionOptions(
3722 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003723
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003724 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3725 RtpTransceiverDirection::kSendRecv, kActive,
3726 &opts);
3727 AttachSenderToMediaDescriptionOptions(
3728 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003729
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003730 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3731 RtpTransceiverDirection::kSendRecv, kActive,
3732 &opts);
3733 AttachSenderToMediaDescriptionOptions(
3734 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003735 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003736 ASSERT_TRUE(offer);
3737
3738 ASSERT_EQ(4u, offer->contents().size());
3739 EXPECT_FALSE(offer->contents()[0].rejected);
3740 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003741 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003742 ASSERT_EQ(1u, acd->streams().size());
3743 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003744 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003745
3746 EXPECT_FALSE(offer->contents()[1].rejected);
3747 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003748 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003749 ASSERT_EQ(1u, vcd->streams().size());
3750 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003751 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003752
3753 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003754 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003755 ASSERT_EQ(1u, acd->streams().size());
3756 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003757 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003758
3759 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003760 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003761 ASSERT_EQ(1u, vcd->streams().size());
3762 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003763 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003764}
3765
3766// Test that we can create an answer with multiple media sections of same media
3767// type.
3768TEST_F(MediaSessionDescriptionFactoryTest,
3769 CreateAnswerWithMultipleAVMediaSections) {
3770 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003771 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3772 RtpTransceiverDirection::kSendRecv, kActive,
3773 &opts);
3774 AttachSenderToMediaDescriptionOptions(
3775 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003776
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003777 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3778 RtpTransceiverDirection::kSendRecv, kActive,
3779 &opts);
3780 AttachSenderToMediaDescriptionOptions(
3781 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003782
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003783 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3784 RtpTransceiverDirection::kSendRecv, kActive,
3785 &opts);
3786 AttachSenderToMediaDescriptionOptions(
3787 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003788
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003789 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3790 RtpTransceiverDirection::kSendRecv, kActive,
3791 &opts);
3792 AttachSenderToMediaDescriptionOptions(
3793 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003794
Steve Anton6fe1fba2018-12-11 10:15:23 -08003795 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003796 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003797 std::unique_ptr<SessionDescription> answer =
3798 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003799
3800 ASSERT_EQ(4u, answer->contents().size());
3801 EXPECT_FALSE(answer->contents()[0].rejected);
3802 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003803 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003804 ASSERT_EQ(1u, acd->streams().size());
3805 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003806 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003807
3808 EXPECT_FALSE(answer->contents()[1].rejected);
3809 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003810 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003811 ASSERT_EQ(1u, vcd->streams().size());
3812 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003813 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003814
3815 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003816 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003817 ASSERT_EQ(1u, acd->streams().size());
3818 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003819 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003820
3821 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003822 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003823 ASSERT_EQ(1u, vcd->streams().size());
3824 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003825 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003826}
3827
3828// Test that the media section will be rejected in offer if the corresponding
3829// MediaDescriptionOptions is stopped by the offerer.
3830TEST_F(MediaSessionDescriptionFactoryTest,
3831 CreateOfferWithMediaSectionStoppedByOfferer) {
3832 // Create an offer with two audio sections and one of them is stopped.
3833 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003834 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3835 RtpTransceiverDirection::kSendRecv, kActive,
3836 &offer_opts);
3837 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3838 RtpTransceiverDirection::kInactive, kStopped,
3839 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003840 std::unique_ptr<SessionDescription> offer =
3841 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003842 ASSERT_TRUE(offer);
3843 ASSERT_EQ(2u, offer->contents().size());
3844 EXPECT_FALSE(offer->contents()[0].rejected);
3845 EXPECT_TRUE(offer->contents()[1].rejected);
3846}
3847
3848// Test that the media section will be rejected in answer if the corresponding
3849// MediaDescriptionOptions is stopped by the offerer.
3850TEST_F(MediaSessionDescriptionFactoryTest,
3851 CreateAnswerWithMediaSectionStoppedByOfferer) {
3852 // Create an offer with two audio sections and one of them is stopped.
3853 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003854 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3855 RtpTransceiverDirection::kSendRecv, kActive,
3856 &offer_opts);
3857 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3858 RtpTransceiverDirection::kInactive, kStopped,
3859 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003860 std::unique_ptr<SessionDescription> offer =
3861 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003862 ASSERT_TRUE(offer);
3863 ASSERT_EQ(2u, offer->contents().size());
3864 EXPECT_FALSE(offer->contents()[0].rejected);
3865 EXPECT_TRUE(offer->contents()[1].rejected);
3866
3867 // Create an answer based on the offer.
3868 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003869 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3870 RtpTransceiverDirection::kSendRecv, kActive,
3871 &answer_opts);
3872 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3873 RtpTransceiverDirection::kSendRecv, kActive,
3874 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003875 std::unique_ptr<SessionDescription> answer =
3876 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003877 ASSERT_EQ(2u, answer->contents().size());
3878 EXPECT_FALSE(answer->contents()[0].rejected);
3879 EXPECT_TRUE(answer->contents()[1].rejected);
3880}
3881
3882// Test that the media section will be rejected in answer if the corresponding
3883// MediaDescriptionOptions is stopped by the answerer.
3884TEST_F(MediaSessionDescriptionFactoryTest,
3885 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3886 // Create an offer with two audio sections.
3887 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003888 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3889 RtpTransceiverDirection::kSendRecv, kActive,
3890 &offer_opts);
3891 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3892 RtpTransceiverDirection::kSendRecv, kActive,
3893 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003894 std::unique_ptr<SessionDescription> offer =
3895 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003896 ASSERT_TRUE(offer);
3897 ASSERT_EQ(2u, offer->contents().size());
3898 ASSERT_FALSE(offer->contents()[0].rejected);
3899 ASSERT_FALSE(offer->contents()[1].rejected);
3900
3901 // The answerer rejects one of the audio sections.
3902 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003903 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3904 RtpTransceiverDirection::kSendRecv, kActive,
3905 &answer_opts);
3906 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3907 RtpTransceiverDirection::kInactive, kStopped,
3908 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003909 std::unique_ptr<SessionDescription> answer =
3910 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003911 ASSERT_EQ(2u, answer->contents().size());
3912 EXPECT_FALSE(answer->contents()[0].rejected);
3913 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003914
3915 // The TransportInfo of the rejected m= section is expected to be added in the
3916 // answer.
3917 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003918}
3919
3920// Test the generated media sections has the same order of the
3921// corresponding MediaDescriptionOptions.
3922TEST_F(MediaSessionDescriptionFactoryTest,
3923 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3924 MediaSessionOptions opts;
3925 // This tests put video section first because normally audio comes first by
3926 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003927 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3928 RtpTransceiverDirection::kSendRecv, kActive,
3929 &opts);
3930 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3931 RtpTransceiverDirection::kSendRecv, kActive,
3932 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003933 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003934
3935 ASSERT_TRUE(offer);
3936 ASSERT_EQ(2u, offer->contents().size());
3937 EXPECT_EQ("video", offer->contents()[0].name);
3938 EXPECT_EQ("audio", offer->contents()[1].name);
3939}
3940
3941// Test that different media sections using the same codec have same payload
3942// type.
3943TEST_F(MediaSessionDescriptionFactoryTest,
3944 PayloadTypesSharedByMediaSectionsOfSameType) {
3945 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003946 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3947 RtpTransceiverDirection::kSendRecv, kActive,
3948 &opts);
3949 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3950 RtpTransceiverDirection::kSendRecv, kActive,
3951 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003952 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003953 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003954 ASSERT_TRUE(offer);
3955 ASSERT_EQ(2u, offer->contents().size());
3956 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003957 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003958 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003959 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003960 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3961 ASSERT_EQ(2u, vcd1->codecs().size());
3962 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3963 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3964 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3965 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3966
3967 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003968 std::unique_ptr<SessionDescription> answer =
3969 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003970 ASSERT_TRUE(answer);
3971 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003972 vcd1 = answer->contents()[0].media_description()->as_video();
3973 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003974 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3975 ASSERT_EQ(1u, vcd1->codecs().size());
3976 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3977 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3978}
3979
3980// Test that the codec preference order per media section is respected in
3981// subsequent offer.
3982TEST_F(MediaSessionDescriptionFactoryTest,
3983 CreateOfferRespectsCodecPreferenceOrder) {
3984 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003985 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3986 RtpTransceiverDirection::kSendRecv, kActive,
3987 &opts);
3988 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3989 RtpTransceiverDirection::kSendRecv, kActive,
3990 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003991 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003992 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003993 ASSERT_TRUE(offer);
3994 ASSERT_EQ(2u, offer->contents().size());
3995 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003996 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003997 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003998 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003999 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4000 EXPECT_EQ(video_codecs, vcd1->codecs());
4001 EXPECT_EQ(video_codecs, vcd2->codecs());
4002
4003 // Change the codec preference of the first video section and create a
4004 // follow-up offer.
4005 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4006 vcd1->set_codecs(video_codecs_reverse);
4007 std::unique_ptr<SessionDescription> updated_offer(
4008 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004009 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4010 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004011 // The video codec preference order should be respected.
4012 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4013 EXPECT_EQ(video_codecs, vcd2->codecs());
4014}
4015
4016// Test that the codec preference order per media section is respected in
4017// the answer.
4018TEST_F(MediaSessionDescriptionFactoryTest,
4019 CreateAnswerRespectsCodecPreferenceOrder) {
4020 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004021 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4022 RtpTransceiverDirection::kSendRecv, kActive,
4023 &opts);
4024 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4025 RtpTransceiverDirection::kSendRecv, kActive,
4026 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004027 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004028 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004029 ASSERT_TRUE(offer);
4030 ASSERT_EQ(2u, offer->contents().size());
4031 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004032 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004033 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004034 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004035 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4036 EXPECT_EQ(video_codecs, vcd1->codecs());
4037 EXPECT_EQ(video_codecs, vcd2->codecs());
4038
4039 // Change the codec preference of the first video section and create an
4040 // answer.
4041 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4042 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004043 std::unique_ptr<SessionDescription> answer =
4044 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004045 vcd1 = answer->contents()[0].media_description()->as_video();
4046 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004047 // The video codec preference order should be respected.
4048 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4049 EXPECT_EQ(video_codecs, vcd2->codecs());
4050}
4051
Zhi Huang6f367472017-11-22 13:20:02 -08004052// Test that when creating an answer, the codecs use local parameters instead of
4053// the remote ones.
4054TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4055 const std::string audio_param_name = "audio_param";
4056 const std::string audio_value1 = "audio_v1";
4057 const std::string audio_value2 = "audio_v2";
4058 const std::string video_param_name = "video_param";
4059 const std::string video_value1 = "video_v1";
4060 const std::string video_value2 = "video_v2";
4061
4062 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4063 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4064 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4065 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4066
4067 // Set the parameters for codecs.
4068 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4069 video_codecs1[0].SetParam(video_param_name, video_value1);
4070 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4071 video_codecs2[0].SetParam(video_param_name, video_value2);
4072
4073 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
4074 f1_.set_video_codecs(video_codecs1);
4075 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
4076 f2_.set_video_codecs(video_codecs2);
4077
4078 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004079 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4080 RtpTransceiverDirection::kSendRecv, kActive,
4081 &opts);
4082 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4083 RtpTransceiverDirection::kSendRecv, kActive,
4084 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004085
Steve Anton6fe1fba2018-12-11 10:15:23 -08004086 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004087 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004088 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4089 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004090 std::string value;
4091 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4092 EXPECT_EQ(audio_value1, value);
4093 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4094 EXPECT_EQ(video_value1, value);
4095
Steve Anton6fe1fba2018-12-11 10:15:23 -08004096 std::unique_ptr<SessionDescription> answer =
4097 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004098 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004099 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4100 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004101 // Use the parameters from the local codecs.
4102 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4103 EXPECT_EQ(audio_value2, value);
4104 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4105 EXPECT_EQ(video_value2, value);
4106}
4107
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004108// Test that matching packetization-mode is part of the criteria for matching
4109// H264 codecs (in addition to profile-level-id). Previously, this was not the
4110// case, so the first H264 codec with the same profile-level-id would match and
4111// the payload type in the answer would be incorrect.
4112// This is a regression test for bugs.webrtc.org/8808
4113TEST_F(MediaSessionDescriptionFactoryTest,
4114 H264MatchCriteriaIncludesPacketizationMode) {
4115 // Create two H264 codecs with the same profile level ID and different
4116 // packetization modes.
4117 VideoCodec h264_pm0(96, "H264");
4118 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4119 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4120 VideoCodec h264_pm1(97, "H264");
4121 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4122 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4123
4124 // Offerer will send both codecs, answerer should choose the one with matching
4125 // packetization mode (and not the first one it sees).
4126 f1_.set_video_codecs({h264_pm0, h264_pm1});
4127 f2_.set_video_codecs({h264_pm1});
4128
4129 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004130 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4131 RtpTransceiverDirection::kSendRecv, kActive,
4132 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004133
Steve Anton6fe1fba2018-12-11 10:15:23 -08004134 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004135 ASSERT_TRUE(offer);
4136
Steve Anton6fe1fba2018-12-11 10:15:23 -08004137 std::unique_ptr<SessionDescription> answer =
4138 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004139 ASSERT_TRUE(answer);
4140
4141 // Answer should have one negotiated codec with packetization-mode=1 using the
4142 // offered payload type.
4143 ASSERT_EQ(1u, answer->contents().size());
4144 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4145 ASSERT_EQ(1u, answer_vcd->codecs().size());
4146 auto answer_codec = answer_vcd->codecs()[0];
4147 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4148}
4149
zhihuangcf5b37c2016-05-05 11:44:35 -07004150class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4151 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004152 MediaProtocolTest()
4153 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004154 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4155 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004156 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004157 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004158 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4159 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004160 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004161 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004162 f1_.set_secure(SEC_ENABLED);
4163 f2_.set_secure(SEC_ENABLED);
4164 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004165 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004166 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004167 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004168 tdf1_.set_secure(SEC_ENABLED);
4169 tdf2_.set_secure(SEC_ENABLED);
4170 }
4171
4172 protected:
4173 MediaSessionDescriptionFactory f1_;
4174 MediaSessionDescriptionFactory f2_;
4175 TransportDescriptionFactory tdf1_;
4176 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004177 UniqueRandomIdGenerator ssrc_generator1;
4178 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004179};
4180
4181TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4182 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004183 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004184 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004185 ASSERT_TRUE(offer.get() != nullptr);
4186 // Set the protocol for all the contents.
4187 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004188 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004189 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004190 std::unique_ptr<SessionDescription> answer =
4191 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004192 const ContentInfo* ac = answer->GetContentByName("audio");
4193 const ContentInfo* vc = answer->GetContentByName("video");
4194 ASSERT_TRUE(ac != nullptr);
4195 ASSERT_TRUE(vc != nullptr);
4196 EXPECT_FALSE(ac->rejected); // the offer is accepted
4197 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004198 const AudioContentDescription* acd = ac->media_description()->as_audio();
4199 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004200 EXPECT_EQ(GetParam(), acd->protocol());
4201 EXPECT_EQ(GetParam(), vcd->protocol());
4202}
4203
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004204INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4205 MediaProtocolTest,
4206 ::testing::ValuesIn(kMediaProtocols));
4207INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4208 MediaProtocolTest,
4209 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004210
4211TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4212 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004213 UniqueRandomIdGenerator ssrc_generator;
4214 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004215 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4216 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4217
4218 // The merged list of codecs should contain any send codecs that are also
4219 // nominally in the recieve codecs list. Payload types should be picked from
4220 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4221 // (set to 1). This equals what happens when the send codecs are used in an
4222 // offer and the receive codecs are used in the following answer.
4223 const std::vector<AudioCodec> sendrecv_codecs =
4224 MAKE_VECTOR(kAudioCodecsAnswer);
4225 const std::vector<AudioCodec> no_codecs;
4226
4227 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4228 << "Please don't change shared test data!";
4229 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4230 << "Please don't change shared test data!";
4231 // Alter iLBC send codec to have zero channels, to test that that is handled
4232 // properly.
4233 send_codecs[1].channels = 0;
4234
4235 // Alther iLBC receive codec to be lowercase, to test that case conversions
4236 // are handled properly.
4237 recv_codecs[2].name = "ilbc";
4238
4239 // Test proper merge
4240 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004241 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4242 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4243 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004244
4245 // Test empty send codecs list
4246 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004247 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4248 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4249 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004250
4251 // Test empty recv codecs list
4252 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004253 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4254 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4255 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004256
4257 // Test all empty codec lists
4258 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004259 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4260 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4261 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004262}
4263
Amit Hilbuch77938e62018-12-21 09:23:38 -08004264// Checks that the RID extensions are added to the video RTP header extensions.
4265// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4266// not very well defined, as calling set() and immediately get() will yield
4267// an object that is not semantically equivalent to the set object.
4268TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4269 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004270 UniqueRandomIdGenerator ssrc_generator;
4271 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004272 sf.set_is_unified_plan(true);
4273 cricket::RtpHeaderExtensions extensions;
4274 sf.set_video_rtp_header_extensions(extensions);
4275 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4276 // Check to see that RID extensions were added to the extension list
4277 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004278 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004279 RtpExtension::kMidUri)));
4280 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004281 RtpExtension::kRidUri)));
4282 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4283 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004284}
4285
4286// Checks that the RID extensions are added to the audio RTP header extensions.
4287// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4288// not very well defined, as calling set() and immediately get() will yield
4289// an object that is not semantically equivalent to the set object.
4290TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4291 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004292 UniqueRandomIdGenerator ssrc_generator;
4293 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004294 sf.set_is_unified_plan(true);
4295 cricket::RtpHeaderExtensions extensions;
4296 sf.set_audio_rtp_header_extensions(extensions);
4297 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4298 // Check to see that RID extensions were added to the extension list
4299 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004300 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004301 RtpExtension::kMidUri)));
4302 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004303 RtpExtension::kRidUri)));
4304 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4305 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004306}
4307
ossu075af922016-06-14 03:29:38 -07004308namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004309// Compare the two vectors of codecs ignoring the payload type.
4310template <class Codec>
4311bool CodecsMatch(const std::vector<Codec>& codecs1,
4312 const std::vector<Codec>& codecs2) {
4313 if (codecs1.size() != codecs2.size()) {
4314 return false;
4315 }
4316
4317 for (size_t i = 0; i < codecs1.size(); ++i) {
4318 if (!codecs1[i].Matches(codecs2[i])) {
4319 return false;
4320 }
4321 }
4322 return true;
4323}
4324
Steve Anton4e70a722017-11-28 14:57:10 -08004325void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004326 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004327 UniqueRandomIdGenerator ssrc_generator;
4328 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004329 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4330 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4331 const std::vector<AudioCodec> sendrecv_codecs =
4332 MAKE_VECTOR(kAudioCodecsAnswer);
4333 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004334
4335 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004336 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4337 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004338
Steve Anton4e70a722017-11-28 14:57:10 -08004339 if (direction == RtpTransceiverDirection::kSendRecv ||
4340 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004341 AttachSenderToMediaDescriptionOptions(
4342 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004343 }
ossu075af922016-06-14 03:29:38 -07004344
Steve Anton6fe1fba2018-12-11 10:15:23 -08004345 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004346 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004347 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004348
4349 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004350 // that the codecs put in are right. This happens when we neither want to
4351 // send nor receive audio. The checks are still in place if at some point
4352 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004353 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004354 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004355 // sendrecv and inactive should both present lists as if the channel was
4356 // to be used for sending and receiving. Inactive essentially means it
4357 // might eventually be used anything, but we don't know more at this
4358 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004359 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004360 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004361 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004362 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004363 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004364 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004365 }
4366 }
4367}
4368
4369static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004370 AudioCodec(0, "codec0", 16000, -1, 1),
4371 AudioCodec(1, "codec1", 8000, 13300, 1),
4372 AudioCodec(2, "codec2", 8000, 64000, 1),
4373 AudioCodec(3, "codec3", 8000, 64000, 1),
4374 AudioCodec(4, "codec4", 8000, 0, 2),
4375 AudioCodec(5, "codec5", 32000, 0, 1),
4376 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004377
zhihuang1c378ed2017-08-17 14:10:50 -07004378/* The codecs groups below are chosen as per the matrix below. The objective
4379 * is to have different sets of codecs in the inputs, to get unique sets of
4380 * codecs after negotiation, depending on offer and answer communication
4381 * directions. One-way directions in the offer should either result in the
4382 * opposite direction in the answer, or an inactive answer. Regardless, the
4383 * choice of codecs should be as if the answer contained the opposite
4384 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004385 *
4386 * | Offer | Answer | Result
4387 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4388 * 0 | x - - | - x - | x - - - -
4389 * 1 | x x x | - x - | x - - x -
4390 * 2 | - x - | x - - | - x - - -
4391 * 3 | x x x | x - - | - x x - -
4392 * 4 | - x - | x x x | - x - - -
4393 * 5 | x - - | x x x | x - - - -
4394 * 6 | x x x | x x x | x x x x x
4395 */
4396// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004397static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4398static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004399// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4400// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004401static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4402static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004403// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004404static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4405static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4406static const int kResultSendrecv_SendCodecs[] = {3, 6};
4407static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4408static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004409
4410template <typename T, int IDXS>
4411std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4412 std::vector<T> out;
4413 out.reserve(IDXS);
4414 for (int idx : indices)
4415 out.push_back(array[idx]);
4416
4417 return out;
4418}
4419
Steve Anton4e70a722017-11-28 14:57:10 -08004420void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4421 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004422 bool add_legacy_stream) {
4423 TransportDescriptionFactory offer_tdf;
4424 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004425 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4426 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4427 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004428 offer_factory.set_audio_codecs(
4429 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4430 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4431 answer_factory.set_audio_codecs(
4432 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4433 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4434
ossu075af922016-06-14 03:29:38 -07004435 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004436 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4437 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004438
Steve Anton4e70a722017-11-28 14:57:10 -08004439 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004440 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4441 kAudioTrack1, {kMediaStream1}, 1,
4442 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004443 }
4444
Steve Anton6fe1fba2018-12-11 10:15:23 -08004445 std::unique_ptr<SessionDescription> offer =
4446 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004447 ASSERT_TRUE(offer.get() != NULL);
4448
4449 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004450 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4451 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004452
Steve Anton4e70a722017-11-28 14:57:10 -08004453 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004454 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4455 kAudioTrack1, {kMediaStream1}, 1,
4456 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004457 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004458 std::unique_ptr<SessionDescription> answer =
4459 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004460 const ContentInfo* ac = answer->GetContentByName("audio");
4461
zhihuang1c378ed2017-08-17 14:10:50 -07004462 // If the factory didn't add any audio content to the answer, we cannot
4463 // check that the codecs put in are right. This happens when we neither want
4464 // to send nor receive audio. The checks are still in place if at some point
4465 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004466 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004467 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4468 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004469
ossu075af922016-06-14 03:29:38 -07004470 std::vector<AudioCodec> target_codecs;
4471 // For offers with sendrecv or inactive, we should never reply with more
4472 // codecs than offered, with these codec sets.
4473 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004474 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004475 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4476 kResultSendrecv_SendrecvCodecs);
4477 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004478 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004479 target_codecs =
4480 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004481 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004482 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004483 target_codecs =
4484 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004485 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004486 case RtpTransceiverDirection::kSendRecv:
4487 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004488 target_codecs =
4489 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004490 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004491 target_codecs =
4492 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004493 } else {
4494 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4495 kResultSendrecv_SendrecvCodecs);
4496 }
4497 break;
4498 }
4499
zhihuang1c378ed2017-08-17 14:10:50 -07004500 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004501 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004502 bool first = true;
4503 os << "{";
4504 for (const auto& c : codecs) {
4505 os << (first ? " " : ", ") << c.id;
4506 first = false;
4507 }
4508 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004509 return os.Release();
ossu075af922016-06-14 03:29:38 -07004510 };
4511
4512 EXPECT_TRUE(acd->codecs() == target_codecs)
4513 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004514 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4515 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004516 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004517 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4518 << "; got: "
4519 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004520 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004521 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004522 << "Only inactive offers are allowed to not generate any audio "
4523 "content";
ossu075af922016-06-14 03:29:38 -07004524 }
4525}
brandtr03d5fb12016-11-22 03:37:59 -08004526
4527} // namespace
ossu075af922016-06-14 03:29:38 -07004528
4529class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004530 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004531
4532TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004533 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004534}
4535
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004536INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4537 AudioCodecsOfferTest,
4538 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4539 RtpTransceiverDirection::kRecvOnly,
4540 RtpTransceiverDirection::kSendRecv,
4541 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004542
4543class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004544 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4545 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004546 bool>> {};
ossu075af922016-06-14 03:29:38 -07004547
4548TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004549 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4550 ::testing::get<1>(GetParam()),
4551 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004552}
4553
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004554INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004555 MediaSessionDescriptionFactoryTest,
4556 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004557 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4558 RtpTransceiverDirection::kRecvOnly,
4559 RtpTransceiverDirection::kSendRecv,
4560 RtpTransceiverDirection::kInactive),
4561 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4562 RtpTransceiverDirection::kRecvOnly,
4563 RtpTransceiverDirection::kSendRecv,
4564 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004565 ::testing::Bool()));