blob: 0a756f34628688500a9d81b25051c80c9a6dbc21 [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>
Harald Alvestrand1716d392019-06-03 20:35:45 +020014#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <vector>
16
Steve Anton64b626b2019-01-28 17:25:26 -080017#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080018#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020021#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "p2p/base/p2p_constants.h"
23#include "p2p/base/transport_description.h"
24#include "p2p/base/transport_info.h"
25#include "pc/media_session.h"
26#include "pc/rtp_media_utils.h"
27#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/message_digest.h"
32#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020033#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080034#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080035#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036
Yves Gerey665174f2018-06-19 15:03:05 +020037#define ASSERT_CRYPTO(cd, s, cs) \
38 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080039 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040
41typedef std::vector<cricket::Candidate> Candidates;
42
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080043using cricket::AudioCodec;
44using cricket::AudioContentDescription;
45using cricket::ContentInfo;
46using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080047using cricket::GetFirstAudioContent;
48using cricket::GetFirstAudioContentDescription;
49using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020050using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080051using cricket::GetFirstVideoContent;
52using cricket::GetFirstVideoContentDescription;
53using cricket::kAutoBandwidth;
54using cricket::MEDIA_TYPE_AUDIO;
55using cricket::MEDIA_TYPE_DATA;
56using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070058using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080059using cricket::MediaProtocolType;
60using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061using cricket::MediaSessionOptions;
62using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080063using cricket::RidDescription;
64using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020065using cricket::RtpDataCodec;
66using cricket::RtpDataContentDescription;
67using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080068using cricket::SEC_DISABLED;
69using cricket::SEC_ENABLED;
70using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080072using cricket::SimulcastDescription;
73using cricket::SimulcastLayer;
74using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075using cricket::SsrcGroup;
76using cricket::StreamParams;
77using cricket::StreamParamsVec;
78using cricket::TransportDescription;
79using cricket::TransportDescriptionFactory;
80using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080082using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070083using rtc::CS_AEAD_AES_128_GCM;
84using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080085using rtc::CS_AES_CM_128_HMAC_SHA1_32;
86using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080087using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020088using ::testing::Contains;
89using ::testing::Each;
90using ::testing::ElementsAreArray;
91using ::testing::Eq;
92using ::testing::Field;
93using ::testing::IsEmpty;
94using ::testing::IsFalse;
95using ::testing::Ne;
96using ::testing::Not;
97using ::testing::Pointwise;
98using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070099using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800100using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101
102static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700103 AudioCodec(103, "ISAC", 16000, -1, 1),
104 AudioCodec(102, "iLBC", 8000, 13300, 1),
105 AudioCodec(0, "PCMU", 8000, 64000, 1),
106 AudioCodec(8, "PCMA", 8000, 64000, 1),
107 AudioCodec(117, "red", 8000, 0, 1),
108 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109
110static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200111 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700112 AudioCodec(0, "PCMU", 8000, 64000, 1),
113 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114};
115
116static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700117 AudioCodec(102, "iLBC", 8000, 13300, 1),
118 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119};
120
perkj26752742016-10-24 01:21:16 -0700121static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
122 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123
zhihuang1c378ed2017-08-17 14:10:50 -0700124static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
125 VideoCodec(96, "H264-SVC")};
126
perkj26752742016-10-24 01:21:16 -0700127static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
128 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000129
perkj26752742016-10-24 01:21:16 -0700130static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200132static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
133 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200135static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
136 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200138static const RtpDataCodec kDataCodecsAnswer[] = {
139 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140
isheriff6f8d6862016-05-26 11:24:55 -0700141static const RtpExtension kAudioRtpExtension1[] = {
142 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
143 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000144};
145
jbauch5869f502017-06-29 12:31:36 -0700146static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
147 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
148 RtpExtension("http://google.com/testing/audio_something", 10),
149 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
150};
151
isheriff6f8d6862016-05-26 11:24:55 -0700152static const RtpExtension kAudioRtpExtension2[] = {
153 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
154 RtpExtension("http://google.com/testing/audio_something_else", 8),
155 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000156};
157
isheriff6f8d6862016-05-26 11:24:55 -0700158static const RtpExtension kAudioRtpExtension3[] = {
159 RtpExtension("http://google.com/testing/audio_something", 2),
160 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700161};
162
jbauch5869f502017-06-29 12:31:36 -0700163static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
164 RtpExtension("http://google.com/testing/audio_something", 2),
165 // Use RTP extension that supports encryption.
166 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
167};
168
169static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
170 RtpExtension("http://google.com/testing/audio_something", 2),
171 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
172 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
173};
174
isheriff6f8d6862016-05-26 11:24:55 -0700175static const RtpExtension kAudioRtpExtensionAnswer[] = {
176 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000177};
178
jbauch5869f502017-06-29 12:31:36 -0700179static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
180 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
181};
182
isheriff6f8d6862016-05-26 11:24:55 -0700183static const RtpExtension kVideoRtpExtension1[] = {
184 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
185 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000186};
187
jbauch5869f502017-06-29 12:31:36 -0700188static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
189 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
190 RtpExtension("http://google.com/testing/video_something", 13),
191 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
192};
193
isheriff6f8d6862016-05-26 11:24:55 -0700194static const RtpExtension kVideoRtpExtension2[] = {
195 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
196 RtpExtension("http://google.com/testing/video_something_else", 14),
197 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198};
199
isheriff6f8d6862016-05-26 11:24:55 -0700200static const RtpExtension kVideoRtpExtension3[] = {
201 RtpExtension("http://google.com/testing/video_something", 4),
202 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700203};
204
jbauch5869f502017-06-29 12:31:36 -0700205static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
206 RtpExtension("http://google.com/testing/video_something", 4),
207 // Use RTP extension that supports encryption.
208 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
209};
210
isheriff6f8d6862016-05-26 11:24:55 -0700211static const RtpExtension kVideoRtpExtensionAnswer[] = {
212 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000213};
214
jbauch5869f502017-06-29 12:31:36 -0700215static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
216 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
217};
218
Johannes Kronce8e8672019-02-22 13:06:44 +0100219static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
220 RtpExtension("http://www.ietf.org/id/"
221 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
222 1),
223};
224
225static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
226 RtpExtension("http://www.ietf.org/id/"
227 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
228 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100229 RtpExtension(
230 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
231 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100232};
233
234static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100235 RtpExtension(
236 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
237 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100238};
239
Peter Boström0c4e06b2015-10-07 12:23:21 +0200240static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
241static const uint32_t kSimSsrc[] = {10, 20, 30};
242static const uint32_t kFec1Ssrc[] = {10, 11};
243static const uint32_t kFec2Ssrc[] = {20, 21};
244static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000245
246static const char kMediaStream1[] = "stream_1";
247static const char kMediaStream2[] = "stream_2";
248static const char kVideoTrack1[] = "video_1";
249static const char kVideoTrack2[] = "video_2";
250static const char kAudioTrack1[] = "audio_1";
251static const char kAudioTrack2[] = "audio_2";
252static const char kAudioTrack3[] = "audio_3";
253static const char kDataTrack1[] = "data_1";
254static const char kDataTrack2[] = "data_2";
255static const char kDataTrack3[] = "data_3";
256
zhihuangcf5b37c2016-05-05 11:44:35 -0700257static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
258 "RTP/SAVPF"};
259static const char* kMediaProtocolsDtls[] = {
260 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
261 "UDP/TLS/RTP/SAVP"};
262
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700263// SRTP cipher name negotiated by the tests. This must be updated if the
264// default changes.
265static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
266static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
267
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800268// These constants are used to make the code using "AddMediaDescriptionOptions"
269// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700270static constexpr bool kStopped = true;
271static constexpr bool kActive = false;
272
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000273static bool IsMediaContentOfType(const ContentInfo* content,
274 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800275 RTC_DCHECK(content);
276 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000277}
278
Steve Anton4e70a722017-11-28 14:57:10 -0800279static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800280 RTC_DCHECK(content);
281 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000282}
283
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000284static void AddRtxCodec(const VideoCodec& rtx_codec,
285 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800286 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000287 codecs->push_back(rtx_codec);
288}
289
290template <class T>
291static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
292 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100293 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000294 for (const auto& codec : codecs) {
295 codec_names.push_back(codec.name);
296 }
297 return codec_names;
298}
299
zhihuang1c378ed2017-08-17 14:10:50 -0700300// This is used for test only. MIDs are not the identification of the
301// MediaDescriptionOptions since some end points may not support MID and the SDP
302// may not contain 'mid'.
303std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
304 const std::string& mid,
305 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800306 return absl::c_find_if(
307 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700308 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
309}
310
311std::vector<MediaDescriptionOptions>::const_iterator
312FindFirstMediaDescriptionByMid(const std::string& mid,
313 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800314 return absl::c_find_if(
315 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700316 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700317}
318
319// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800320static void AddMediaDescriptionOptions(MediaType type,
321 const std::string& mid,
322 RtpTransceiverDirection direction,
323 bool stopped,
324 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800325 opts->media_description_options.push_back(
326 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700327}
328
Steve Anton4e70a722017-11-28 14:57:10 -0800329static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700330 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800331 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
332 opts);
333 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
334 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700335}
336
337static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800338 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700339 MediaSessionOptions* opts) {
340 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800341 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700342}
343
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800344static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700345 const std::string& mid,
346 MediaType type,
347 const std::string& track_id,
348 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800349 const std::vector<RidDescription>& rids,
350 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700351 int num_sim_layer,
352 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700353 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
354 switch (type) {
355 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700356 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700357 break;
358 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800359 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
360 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700361 break;
362 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700363 RTC_CHECK(stream_ids.size() == 1U);
364 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700365 break;
366 default:
367 RTC_NOTREACHED();
368 }
369}
370
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800371static void AttachSenderToMediaDescriptionOptions(
372 const std::string& mid,
373 MediaType type,
374 const std::string& track_id,
375 const std::vector<std::string>& stream_ids,
376 int num_sim_layer,
377 MediaSessionOptions* session_options) {
378 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
379 SimulcastLayerList(), num_sim_layer,
380 session_options);
381}
382
zhihuang1c378ed2017-08-17 14:10:50 -0700383static void DetachSenderFromMediaSection(const std::string& mid,
384 const std::string& track_id,
385 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700386 std::vector<cricket::SenderOptions>& sender_options_list =
387 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
388 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800389 absl::c_find_if(sender_options_list,
390 [track_id](const cricket::SenderOptions& sender_options) {
391 return sender_options.track_id == track_id;
392 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700393 RTC_DCHECK(sender_it != sender_options_list.end());
394 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700395}
396
397// Helper function used to create a default MediaSessionOptions for Plan B SDP.
398// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
399static MediaSessionOptions CreatePlanBMediaSessionOptions() {
400 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800401 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
402 RtpTransceiverDirection::kRecvOnly, kActive,
403 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700404 return session_options;
405}
406
407// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
408// was designed for Plan B SDP, where only one audio "m=" section and one video
409// "m=" section could be generated, and ordering couldn't be controlled. Many of
410// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200411class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000412 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800413 MediaSessionDescriptionFactoryTest()
414 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700415 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
416 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000417 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200418 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700419 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
420 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200422 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200423 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700424 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200425 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700426 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 }
428
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000429 // Create a video StreamParamsVec object with:
430 // - one video stream with 3 simulcast streams and FEC,
431 StreamParamsVec CreateComplexVideoStreamParamsVec() {
432 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
433 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
434 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
435 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
436
437 std::vector<SsrcGroup> ssrc_groups;
438 ssrc_groups.push_back(sim_group);
439 ssrc_groups.push_back(fec_group1);
440 ssrc_groups.push_back(fec_group2);
441 ssrc_groups.push_back(fec_group3);
442
443 StreamParams simulcast_params;
444 simulcast_params.id = kVideoTrack1;
445 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
446 simulcast_params.ssrc_groups = ssrc_groups;
447 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800448 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000449
450 StreamParamsVec video_streams;
451 video_streams.push_back(simulcast_params);
452
453 return video_streams;
454 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455
456 bool CompareCryptoParams(const CryptoParamsVec& c1,
457 const CryptoParamsVec& c2) {
458 if (c1.size() != c2.size())
459 return false;
460 for (size_t i = 0; i < c1.size(); ++i)
461 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
462 c1[i].key_params != c2[i].key_params ||
463 c1[i].session_params != c2[i].session_params)
464 return false;
465 return true;
466 }
467
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700468 // Returns true if the transport info contains "renomination" as an
469 // ICE option.
470 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800471 return absl::c_linear_search(transport_info->description.transport_options,
472 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700473 }
474
zhihuang1c378ed2017-08-17 14:10:50 -0700475 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700476 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000477 bool has_current_desc) {
478 const std::string current_audio_ufrag = "current_audio_ufrag";
479 const std::string current_audio_pwd = "current_audio_pwd";
480 const std::string current_video_ufrag = "current_video_ufrag";
481 const std::string current_video_pwd = "current_video_pwd";
482 const std::string current_data_ufrag = "current_data_ufrag";
483 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800484 std::unique_ptr<SessionDescription> current_desc;
485 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000486 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800487 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800488 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200489 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800490 TransportDescription(current_audio_ufrag, current_audio_pwd)));
491 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200492 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800493 TransportDescription(current_video_ufrag, current_video_pwd)));
494 current_desc->AddTransportInfo(TransportInfo(
495 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496 }
497 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800498 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499 } else {
kwiberg31022942016-03-11 14:18:21 -0800500 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800501 offer = f1_.CreateOffer(options, NULL);
502 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000503 }
504 ASSERT_TRUE(desc.get() != NULL);
505 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000506 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 EXPECT_TRUE(ti_audio != NULL);
508 if (has_current_desc) {
509 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
510 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
511 } else {
512 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
513 ti_audio->description.ice_ufrag.size());
514 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
515 ti_audio->description.ice_pwd.size());
516 }
zhihuang1c378ed2017-08-17 14:10:50 -0700517 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700518 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700519 EXPECT_EQ(
520 media_desc_options_it->transport_options.enable_ice_renomination,
521 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700522 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
523 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000524
525 } else {
526 EXPECT_TRUE(ti_audio == NULL);
527 }
528 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000529 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700531 auto media_desc_options_it =
532 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 if (options.bundle_enabled) {
534 EXPECT_EQ(ti_audio->description.ice_ufrag,
535 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200536 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700537 EXPECT_EQ(ti_audio->description.opaque_parameters,
538 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 } else {
540 if (has_current_desc) {
541 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
542 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
543 } else {
544 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
545 ti_video->description.ice_ufrag.size());
546 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
547 ti_video->description.ice_pwd.size());
548 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700549 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
550 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000551 }
zhihuang1c378ed2017-08-17 14:10:50 -0700552 EXPECT_EQ(
553 media_desc_options_it->transport_options.enable_ice_renomination,
554 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 } else {
556 EXPECT_TRUE(ti_video == NULL);
557 }
558 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
559 if (options.has_data()) {
560 EXPECT_TRUE(ti_data != NULL);
561 if (options.bundle_enabled) {
562 EXPECT_EQ(ti_audio->description.ice_ufrag,
563 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200564 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 } else {
566 if (has_current_desc) {
567 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
568 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
569 } else {
570 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
571 ti_data->description.ice_ufrag.size());
572 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
573 ti_data->description.ice_pwd.size());
574 }
575 }
zhihuang1c378ed2017-08-17 14:10:50 -0700576 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700577 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700578 EXPECT_EQ(
579 media_desc_options_it->transport_options.enable_ice_renomination,
580 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700581
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700583 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 }
585 }
586
587 void TestCryptoWithBundle(bool offer) {
588 f1_.set_secure(SEC_ENABLED);
589 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800590 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
591 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
592 &options);
kwiberg31022942016-03-11 14:18:21 -0800593 std::unique_ptr<SessionDescription> ref_desc;
594 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 if (offer) {
596 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800597 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800599 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 } else {
601 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800602 ref_desc = f1_.CreateOffer(options, NULL);
603 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800605 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800607 desc->GetContentDescriptionByName("audio");
608 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800610 desc->GetContentDescriptionByName("video");
611 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
613 video_media_desc->cryptos()));
614 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800615 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 audio_media_desc->cryptos()[0].cipher_suite);
617
618 // Verify the selected crypto is one from the reference audio
619 // media content.
620 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800621 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 bool found = false;
623 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
624 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200625 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 found = true;
627 break;
628 }
629 }
630 EXPECT_TRUE(found);
631 }
632
633 // This test that the audio and video media direction is set to
634 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700635 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800637 RtpTransceiverDirection direction_in_offer,
638 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700639 MediaSessionOptions offer_opts;
640 AddAudioVideoSections(direction_in_offer, &offer_opts);
641
Steve Anton6fe1fba2018-12-11 10:15:23 -0800642 std::unique_ptr<SessionDescription> offer =
643 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700645 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700647 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000648 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649
zhihuang1c378ed2017-08-17 14:10:50 -0700650 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800651 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800652 std::unique_ptr<SessionDescription> answer =
653 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 const AudioContentDescription* acd_answer =
655 GetFirstAudioContentDescription(answer.get());
656 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
657 const VideoContentDescription* vcd_answer =
658 GetFirstVideoContentDescription(answer.get());
659 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
660 }
661
662 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800663 RTC_DCHECK(content);
664 RTC_CHECK(content->media_description());
665 const cricket::AudioContentDescription* audio_desc =
666 content->media_description()->as_audio();
667 RTC_CHECK(audio_desc);
668 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
669 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800671 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000672 }
673 return true;
674 }
675
jbauchcb560652016-08-04 05:20:32 -0700676 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
677 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800678 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700679 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700680
jbauchcb560652016-08-04 05:20:32 -0700681 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800682 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700683 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700684
jbauchcb560652016-08-04 05:20:32 -0700685 f1_.set_secure(SEC_ENABLED);
686 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800687 std::unique_ptr<SessionDescription> offer =
688 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700689 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800690 std::unique_ptr<SessionDescription> answer =
691 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700692 const ContentInfo* ac = answer->GetContentByName("audio");
693 const ContentInfo* vc = answer->GetContentByName("video");
694 ASSERT_TRUE(ac != NULL);
695 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800696 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
697 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800698 const AudioContentDescription* acd = ac->media_description()->as_audio();
699 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700700 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800701 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700702 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700703 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700704 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
705 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700706 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700707 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700708 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700709 }
710 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800711 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200712 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
713 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700714 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700715 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700716 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700717 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700718 }
Steve Antone38a5a12018-11-21 16:05:15 -0800719 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700720 }
721
Johannes Kronce8e8672019-02-22 13:06:44 +0100722 void TestTransportSequenceNumberNegotiation(
723 const cricket::RtpHeaderExtensions& local,
724 const cricket::RtpHeaderExtensions& offered,
725 const cricket::RtpHeaderExtensions& expectedAnswer) {
726 MediaSessionOptions opts;
727 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
728 f1_.set_audio_rtp_header_extensions(offered);
729 f1_.set_video_rtp_header_extensions(offered);
730 f2_.set_audio_rtp_header_extensions(local);
731 f2_.set_video_rtp_header_extensions(local);
732
733 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
734 ASSERT_TRUE(offer.get() != NULL);
735 std::unique_ptr<SessionDescription> answer =
736 f2_.CreateAnswer(offer.get(), opts, NULL);
737
738 EXPECT_EQ(
739 expectedAnswer,
740 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
741 EXPECT_EQ(
742 expectedAnswer,
743 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
744 }
745
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800747 UniqueRandomIdGenerator ssrc_generator1;
748 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 MediaSessionDescriptionFactory f1_;
750 MediaSessionDescriptionFactory f2_;
751 TransportDescriptionFactory tdf1_;
752 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753};
754
755// Create a typical audio offer, and ensure it matches what we expect.
756TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
757 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800758 std::unique_ptr<SessionDescription> offer =
759 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 ASSERT_TRUE(offer.get() != NULL);
761 const ContentInfo* ac = offer->GetContentByName("audio");
762 const ContentInfo* vc = offer->GetContentByName("video");
763 ASSERT_TRUE(ac != NULL);
764 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800765 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800766 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700768 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700769 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
771 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700772 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800773 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774}
775
776// Create a typical video offer, and ensure it matches what we expect.
777TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
778 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800779 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000780 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800781 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782 ASSERT_TRUE(offer.get() != NULL);
783 const ContentInfo* ac = offer->GetContentByName("audio");
784 const ContentInfo* vc = offer->GetContentByName("video");
785 ASSERT_TRUE(ac != NULL);
786 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800787 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
788 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800789 const AudioContentDescription* acd = ac->media_description()->as_audio();
790 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700792 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700793 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
795 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700796 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800797 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
799 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700800 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
802 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700803 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800804 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805}
806
807// Test creating an offer with bundle where the Codecs have the same dynamic
808// RTP playlod type. The test verifies that the offer don't contain the
809// duplicate RTP payload types.
810TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
811 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700812 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200813 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
815 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
816
817 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800818 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
819 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800821 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822 const VideoContentDescription* vcd =
823 GetFirstVideoContentDescription(offer.get());
824 const AudioContentDescription* acd =
825 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200826 const RtpDataContentDescription* dcd =
827 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 ASSERT_TRUE(NULL != vcd);
829 ASSERT_TRUE(NULL != acd);
830 ASSERT_TRUE(NULL != dcd);
831 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
832 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
833 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
834 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
835 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
836 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
837}
838
zhihuang1c378ed2017-08-17 14:10:50 -0700839// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840// after an audio only session has been negotiated.
841TEST_F(MediaSessionDescriptionFactoryTest,
842 TestCreateUpdatedVideoOfferWithBundle) {
843 f1_.set_secure(SEC_ENABLED);
844 f2_.set_secure(SEC_ENABLED);
845 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800846 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
847 RtpTransceiverDirection::kRecvOnly, kActive,
848 &opts);
849 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
850 RtpTransceiverDirection::kInactive, kStopped,
851 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 opts.data_channel_type = cricket::DCT_NONE;
853 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800854 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
855 std::unique_ptr<SessionDescription> answer =
856 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857
858 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800859 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
860 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
861 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800863 std::unique_ptr<SessionDescription> updated_offer(
864 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865
866 const AudioContentDescription* acd =
867 GetFirstAudioContentDescription(updated_offer.get());
868 const VideoContentDescription* vcd =
869 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200870 const RtpDataContentDescription* dcd =
871 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872 EXPECT_TRUE(NULL != vcd);
873 EXPECT_TRUE(NULL != acd);
874 EXPECT_TRUE(NULL != dcd);
875
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700876 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800877 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700878 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800879 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700880 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800881 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882}
deadbeef44f08192015-12-15 16:20:09 -0800883
wu@webrtc.org78187522013-10-07 23:32:02 +0000884// Create a RTP data offer, and ensure it matches what we expect.
885TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000886 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800887 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
888 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000889 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800890 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891 ASSERT_TRUE(offer.get() != NULL);
892 const ContentInfo* ac = offer->GetContentByName("audio");
893 const ContentInfo* dc = offer->GetContentByName("data");
894 ASSERT_TRUE(ac != NULL);
895 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800896 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
897 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800898 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200899 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700901 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700902 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
904 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700905 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800906 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200908 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700909 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000910 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200911 dcd->bandwidth()); // default bandwidth (auto)
912 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700913 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800914 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915}
916
wu@webrtc.org78187522013-10-07 23:32:02 +0000917// Create an SCTP data offer with bundle without error.
918TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
919 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000920 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800921 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000922 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800923 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000924 EXPECT_TRUE(offer.get() != NULL);
925 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000926 auto dcd = GetFirstSctpDataContentDescription(offer.get());
927 ASSERT_TRUE(dcd);
928 // Since this transport is insecure, the protocol should be "SCTP".
929 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
930}
931
932// Create an SCTP data offer with bundle without error.
933TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
934 MediaSessionOptions opts;
935 opts.bundle_enabled = true;
936 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
937 f1_.set_secure(SEC_ENABLED);
938 tdf1_.set_secure(SEC_ENABLED);
939 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
940 EXPECT_TRUE(offer.get() != NULL);
941 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
942 auto dcd = GetFirstSctpDataContentDescription(offer.get());
943 ASSERT_TRUE(dcd);
944 // The protocol should now be "UDP/DTLS/SCTP"
945 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000946}
947
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000948// Test creating an sctp data channel from an already generated offer.
949TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
950 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000951 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800952 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000953 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800954 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000955 ASSERT_TRUE(offer1.get() != NULL);
956 const ContentInfo* data = offer1->GetContentByName("data");
957 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800958 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000959
960 // Now set data_channel_type to 'none' (default) and make sure that the
961 // datachannel type that gets generated from the previous offer, is of the
962 // same type.
963 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800964 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000965 f1_.CreateOffer(opts, offer1.get()));
966 data = offer2->GetContentByName("data");
967 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800968 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000969}
970
Steve Anton2bed3972019-01-04 17:04:30 -0800971// Test that if BUNDLE is enabled and all media sections are rejected then the
972// BUNDLE group is not present in the re-offer.
973TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
974 MediaSessionOptions opts;
975 opts.bundle_enabled = true;
976 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
977 RtpTransceiverDirection::kSendRecv, kActive,
978 &opts);
979 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
980
981 opts.media_description_options[0].stopped = true;
982 std::unique_ptr<SessionDescription> reoffer =
983 f1_.CreateOffer(opts, offer.get());
984
985 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
986}
987
988// Test that if BUNDLE is enabled and the remote re-offer does not include a
989// BUNDLE group since all media sections are rejected, then the re-answer also
990// does not include a BUNDLE group.
991TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
992 MediaSessionOptions opts;
993 opts.bundle_enabled = true;
994 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
995 RtpTransceiverDirection::kSendRecv, kActive,
996 &opts);
997 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
998 std::unique_ptr<SessionDescription> answer =
999 f2_.CreateAnswer(offer.get(), opts, nullptr);
1000
1001 opts.media_description_options[0].stopped = true;
1002 std::unique_ptr<SessionDescription> reoffer =
1003 f1_.CreateOffer(opts, offer.get());
1004 std::unique_ptr<SessionDescription> reanswer =
1005 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1006
1007 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1008}
1009
1010// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1011// was rejected then the new offerer-tagged media section is the non-rejected
1012// media section.
1013TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1014 MediaSessionOptions opts;
1015 opts.bundle_enabled = true;
1016 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1017 RtpTransceiverDirection::kSendRecv, kActive,
1018 &opts);
1019 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1020
1021 // Reject the audio m= section and add a video m= section.
1022 opts.media_description_options[0].stopped = true;
1023 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1024 RtpTransceiverDirection::kSendRecv, kActive,
1025 &opts);
1026 std::unique_ptr<SessionDescription> reoffer =
1027 f1_.CreateOffer(opts, offer.get());
1028
1029 const cricket::ContentGroup* bundle_group =
1030 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1031 ASSERT_TRUE(bundle_group);
1032 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1033 EXPECT_TRUE(bundle_group->HasContentName("video"));
1034}
1035
1036// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1037// was rejected and a new media section is added, then the re-answer BUNDLE
1038// group will contain only the non-rejected media section.
1039TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1040 MediaSessionOptions opts;
1041 opts.bundle_enabled = true;
1042 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1043 RtpTransceiverDirection::kSendRecv, kActive,
1044 &opts);
1045 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1046 std::unique_ptr<SessionDescription> answer =
1047 f2_.CreateAnswer(offer.get(), opts, nullptr);
1048
1049 // Reject the audio m= section and add a video m= section.
1050 opts.media_description_options[0].stopped = true;
1051 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1052 RtpTransceiverDirection::kSendRecv, kActive,
1053 &opts);
1054 std::unique_ptr<SessionDescription> reoffer =
1055 f1_.CreateOffer(opts, offer.get());
1056 std::unique_ptr<SessionDescription> reanswer =
1057 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1058
1059 const cricket::ContentGroup* bundle_group =
1060 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1061 ASSERT_TRUE(bundle_group);
1062 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1063 EXPECT_TRUE(bundle_group->HasContentName("video"));
1064}
1065
1066// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1067// and there is still a non-rejected media section that was in the initial
1068// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1069// media section.
1070TEST_F(MediaSessionDescriptionFactoryTest,
1071 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1072 MediaSessionOptions opts;
1073 opts.bundle_enabled = true;
1074 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1075 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1076 std::unique_ptr<SessionDescription> answer =
1077 f2_.CreateAnswer(offer.get(), opts, nullptr);
1078
1079 // Reject the audio m= section.
1080 opts.media_description_options[0].stopped = true;
1081 std::unique_ptr<SessionDescription> reoffer =
1082 f1_.CreateOffer(opts, offer.get());
1083
1084 const TransportDescription* offer_tagged =
1085 offer->GetTransportDescriptionByName("audio");
1086 ASSERT_TRUE(offer_tagged);
1087 const TransportDescription* reoffer_tagged =
1088 reoffer->GetTransportDescriptionByName("video");
1089 ASSERT_TRUE(reoffer_tagged);
1090 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1091 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1092}
1093
1094// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1095// and there is still a non-rejected media section that was in the initial
1096// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1097// media section.
1098TEST_F(MediaSessionDescriptionFactoryTest,
1099 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1100 MediaSessionOptions opts;
1101 opts.bundle_enabled = true;
1102 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1103 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1104 std::unique_ptr<SessionDescription> answer =
1105 f2_.CreateAnswer(offer.get(), opts, nullptr);
1106
1107 // Reject the audio m= section.
1108 opts.media_description_options[0].stopped = true;
1109 std::unique_ptr<SessionDescription> reoffer =
1110 f1_.CreateOffer(opts, offer.get());
1111 std::unique_ptr<SessionDescription> reanswer =
1112 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1113
1114 const TransportDescription* answer_tagged =
1115 answer->GetTransportDescriptionByName("audio");
1116 ASSERT_TRUE(answer_tagged);
1117 const TransportDescription* reanswer_tagged =
1118 reanswer->GetTransportDescriptionByName("video");
1119 ASSERT_TRUE(reanswer_tagged);
1120 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1121 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1122}
1123
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124// Create an audio, video offer without legacy StreamParams.
1125TEST_F(MediaSessionDescriptionFactoryTest,
1126 TestCreateOfferWithoutLegacyStreams) {
1127 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001128 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001129 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001130 ASSERT_TRUE(offer.get() != NULL);
1131 const ContentInfo* ac = offer->GetContentByName("audio");
1132 const ContentInfo* vc = offer->GetContentByName("video");
1133 ASSERT_TRUE(ac != NULL);
1134 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001135 const AudioContentDescription* acd = ac->media_description()->as_audio();
1136 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137
Yves Gerey665174f2018-06-19 15:03:05 +02001138 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1139 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140}
1141
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001142// Creates an audio+video sendonly offer.
1143TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001144 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001145 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001146 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1147 {kMediaStream1}, 1, &opts);
1148 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1149 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001150
Steve Anton6fe1fba2018-12-11 10:15:23 -08001151 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001152 ASSERT_TRUE(offer.get() != NULL);
1153 EXPECT_EQ(2u, offer->contents().size());
1154 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1155 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1156
Steve Anton4e70a722017-11-28 14:57:10 -08001157 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1158 GetMediaDirection(&offer->contents()[0]));
1159 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1160 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001161}
1162
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001163// Verifies that the order of the media contents in the current
1164// SessionDescription is preserved in the new SessionDescription.
1165TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1166 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001167 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001168
kwiberg31022942016-03-11 14:18:21 -08001169 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001170 ASSERT_TRUE(offer1.get() != NULL);
1171 EXPECT_EQ(1u, offer1->contents().size());
1172 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1173
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001174 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1175 RtpTransceiverDirection::kRecvOnly, kActive,
1176 &opts);
kwiberg31022942016-03-11 14:18:21 -08001177 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001178 f1_.CreateOffer(opts, offer1.get()));
1179 ASSERT_TRUE(offer2.get() != NULL);
1180 EXPECT_EQ(2u, offer2->contents().size());
1181 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1182 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1183
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001184 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1185 RtpTransceiverDirection::kRecvOnly, kActive,
1186 &opts);
kwiberg31022942016-03-11 14:18:21 -08001187 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001188 f1_.CreateOffer(opts, offer2.get()));
1189 ASSERT_TRUE(offer3.get() != NULL);
1190 EXPECT_EQ(3u, offer3->contents().size());
1191 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1192 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1193 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001194}
1195
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001196// Create a typical audio answer, and ensure it matches what we expect.
1197TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1198 f1_.set_secure(SEC_ENABLED);
1199 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001200 std::unique_ptr<SessionDescription> offer =
1201 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001203 std::unique_ptr<SessionDescription> answer =
1204 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205 const ContentInfo* ac = answer->GetContentByName("audio");
1206 const ContentInfo* vc = answer->GetContentByName("video");
1207 ASSERT_TRUE(ac != NULL);
1208 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001209 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001210 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001211 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001212 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001213 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001214 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1215 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001216 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001217 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218}
1219
jbauchcb560652016-08-04 05:20:32 -07001220// Create a typical audio answer with GCM ciphers enabled, and ensure it
1221// matches what we expect.
1222TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1223 f1_.set_secure(SEC_ENABLED);
1224 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001225 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001226 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001227 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001228 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001229 std::unique_ptr<SessionDescription> answer =
1230 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001231 const ContentInfo* ac = answer->GetContentByName("audio");
1232 const ContentInfo* vc = answer->GetContentByName("video");
1233 ASSERT_TRUE(ac != NULL);
1234 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001235 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001236 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001237 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001238 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001239 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001240 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1241 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001242 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001243 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001244}
1245
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246// Create a typical video answer, and ensure it matches what we expect.
1247TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1248 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001249 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250 f1_.set_secure(SEC_ENABLED);
1251 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001252 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001254 std::unique_ptr<SessionDescription> answer =
1255 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 const ContentInfo* ac = answer->GetContentByName("audio");
1257 const ContentInfo* vc = answer->GetContentByName("video");
1258 ASSERT_TRUE(ac != NULL);
1259 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001260 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1261 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001262 const AudioContentDescription* acd = ac->media_description()->as_audio();
1263 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001265 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001267 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001269 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001271 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001272 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1273 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001274 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001275 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276}
1277
jbauchcb560652016-08-04 05:20:32 -07001278// Create a typical video answer with GCM ciphers enabled, and ensure it
1279// matches what we expect.
1280TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1281 TestVideoGcmCipher(true, true);
1282}
1283
1284// Create a typical video answer with GCM ciphers enabled for the offer only,
1285// and ensure it matches what we expect.
1286TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1287 TestVideoGcmCipher(true, false);
1288}
1289
1290// Create a typical video answer with GCM ciphers enabled for the answer only,
1291// and ensure it matches what we expect.
1292TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1293 TestVideoGcmCipher(false, true);
1294}
1295
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001297 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001298 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001299 f1_.set_secure(SEC_ENABLED);
1300 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001301 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001302 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001303 std::unique_ptr<SessionDescription> answer =
1304 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001306 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001308 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001309 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1310 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001311 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001312 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001313 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001314 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001315 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001316 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001318 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001319 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001320 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001321 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001322 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001323 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001324 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001325}
1326
jbauchcb560652016-08-04 05:20:32 -07001327TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001328 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001329 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001330 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001331 f1_.set_secure(SEC_ENABLED);
1332 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001333 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001334 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001335 std::unique_ptr<SessionDescription> answer =
1336 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001337 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001338 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001339 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001340 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001341 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1342 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001343 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001344 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001345 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001346 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001347 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001348 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001349 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001350 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001351 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001352 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001353 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001354 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001355 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001356 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001357}
1358
1359// The use_sctpmap flag should be set in a DataContentDescription by default.
1360// The answer's use_sctpmap flag should match the offer's.
1361TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1362 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001363 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001364 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001365 ASSERT_TRUE(offer.get() != NULL);
1366 ContentInfo* dc_offer = offer->GetContentByName("data");
1367 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001368 SctpDataContentDescription* dcd_offer =
1369 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001370 EXPECT_TRUE(dcd_offer->use_sctpmap());
1371
Steve Anton6fe1fba2018-12-11 10:15:23 -08001372 std::unique_ptr<SessionDescription> answer =
1373 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001374 const ContentInfo* dc_answer = answer->GetContentByName("data");
1375 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001376 const SctpDataContentDescription* dcd_answer =
1377 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001378 EXPECT_TRUE(dcd_answer->use_sctpmap());
1379}
1380
1381// The answer's use_sctpmap flag should match the offer's.
1382TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1383 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001384 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001385 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001386 ASSERT_TRUE(offer.get() != NULL);
1387 ContentInfo* dc_offer = offer->GetContentByName("data");
1388 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001389 SctpDataContentDescription* dcd_offer =
1390 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001391 dcd_offer->set_use_sctpmap(false);
1392
Steve Anton6fe1fba2018-12-11 10:15:23 -08001393 std::unique_ptr<SessionDescription> answer =
1394 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001395 const ContentInfo* dc_answer = answer->GetContentByName("data");
1396 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001397 const SctpDataContentDescription* dcd_answer =
1398 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001399 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001400}
1401
deadbeef8b7e9ad2017-05-25 09:38:55 -07001402// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1403// and "TCP/DTLS/SCTP" offers.
1404TEST_F(MediaSessionDescriptionFactoryTest,
1405 TestCreateDataAnswerToDifferentOfferedProtos) {
1406 // Need to enable DTLS offer/answer generation (disabled by default in this
1407 // test).
1408 f1_.set_secure(SEC_ENABLED);
1409 f2_.set_secure(SEC_ENABLED);
1410 tdf1_.set_secure(SEC_ENABLED);
1411 tdf2_.set_secure(SEC_ENABLED);
1412
1413 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001414 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001415 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001416 ASSERT_TRUE(offer.get() != nullptr);
1417 ContentInfo* dc_offer = offer->GetContentByName("data");
1418 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001419 SctpDataContentDescription* dcd_offer =
1420 dc_offer->media_description()->as_sctp();
1421 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001422
1423 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1424 "TCP/DTLS/SCTP"};
1425 for (const std::string& proto : protos) {
1426 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001427 std::unique_ptr<SessionDescription> answer =
1428 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001429 const ContentInfo* dc_answer = answer->GetContentByName("data");
1430 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001431 const SctpDataContentDescription* dcd_answer =
1432 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001433 EXPECT_FALSE(dc_answer->rejected);
1434 EXPECT_EQ(proto, dcd_answer->protocol());
1435 }
1436}
1437
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001438TEST_F(MediaSessionDescriptionFactoryTest,
1439 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1440 // Need to enable DTLS offer/answer generation (disabled by default in this
1441 // test).
1442 f1_.set_secure(SEC_ENABLED);
1443 f2_.set_secure(SEC_ENABLED);
1444 tdf1_.set_secure(SEC_ENABLED);
1445 tdf2_.set_secure(SEC_ENABLED);
1446
1447 MediaSessionOptions opts;
1448 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1449 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1450 ASSERT_TRUE(offer.get() != nullptr);
1451 ContentInfo* dc_offer = offer->GetContentByName("data");
1452 ASSERT_TRUE(dc_offer != nullptr);
1453 SctpDataContentDescription* dcd_offer =
1454 dc_offer->media_description()->as_sctp();
1455 ASSERT_TRUE(dcd_offer);
1456 dcd_offer->set_max_message_size(1234);
1457 std::unique_ptr<SessionDescription> answer =
1458 f2_.CreateAnswer(offer.get(), opts, nullptr);
1459 const ContentInfo* dc_answer = answer->GetContentByName("data");
1460 ASSERT_TRUE(dc_answer != nullptr);
1461 const SctpDataContentDescription* dcd_answer =
1462 dc_answer->media_description()->as_sctp();
1463 EXPECT_FALSE(dc_answer->rejected);
1464 EXPECT_EQ(1234, dcd_answer->max_message_size());
1465}
1466
1467TEST_F(MediaSessionDescriptionFactoryTest,
1468 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1469 // Need to enable DTLS offer/answer generation (disabled by default in this
1470 // test).
1471 f1_.set_secure(SEC_ENABLED);
1472 f2_.set_secure(SEC_ENABLED);
1473 tdf1_.set_secure(SEC_ENABLED);
1474 tdf2_.set_secure(SEC_ENABLED);
1475
1476 MediaSessionOptions opts;
1477 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1478 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1479 ASSERT_TRUE(offer.get() != nullptr);
1480 ContentInfo* dc_offer = offer->GetContentByName("data");
1481 ASSERT_TRUE(dc_offer != nullptr);
1482 SctpDataContentDescription* dcd_offer =
1483 dc_offer->media_description()->as_sctp();
1484 ASSERT_TRUE(dcd_offer);
1485 dcd_offer->set_max_message_size(0);
1486 std::unique_ptr<SessionDescription> answer =
1487 f2_.CreateAnswer(offer.get(), opts, nullptr);
1488 const ContentInfo* dc_answer = answer->GetContentByName("data");
1489 ASSERT_TRUE(dc_answer != nullptr);
1490 const SctpDataContentDescription* dcd_answer =
1491 dc_answer->media_description()->as_sctp();
1492 EXPECT_FALSE(dc_answer->rejected);
1493 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1494}
1495
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001496// Verifies that the order of the media contents in the offer is preserved in
1497// the answer.
1498TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1499 MediaSessionOptions opts;
1500
1501 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001502 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001503 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001504 ASSERT_TRUE(offer1.get() != NULL);
1505
1506 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001507 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1508 RtpTransceiverDirection::kRecvOnly, kActive,
1509 &opts);
kwiberg31022942016-03-11 14:18:21 -08001510 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001511 f1_.CreateOffer(opts, offer1.get()));
1512 ASSERT_TRUE(offer2.get() != NULL);
1513
1514 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001515 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1516 RtpTransceiverDirection::kRecvOnly, kActive,
1517 &opts);
kwiberg31022942016-03-11 14:18:21 -08001518 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001519 f1_.CreateOffer(opts, offer2.get()));
1520 ASSERT_TRUE(offer3.get() != NULL);
1521
Steve Anton6fe1fba2018-12-11 10:15:23 -08001522 std::unique_ptr<SessionDescription> answer =
1523 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001524 ASSERT_TRUE(answer.get() != NULL);
1525 EXPECT_EQ(3u, answer->contents().size());
1526 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1527 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1528 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1529}
1530
ossu075af922016-06-14 03:29:38 -07001531// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1532// answerer settings.
1533
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001534// This test that the media direction is set to send/receive in an answer if
1535// the offer is send receive.
1536TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001537 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1538 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001539}
1540
1541// This test that the media direction is set to receive only in an answer if
1542// the offer is send only.
1543TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001544 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1545 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001546}
1547
1548// This test that the media direction is set to send only in an answer if
1549// the offer is recv only.
1550TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001551 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1552 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001553}
1554
1555// This test that the media direction is set to inactive in an answer if
1556// the offer is inactive.
1557TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001558 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1559 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560}
1561
1562// Test that a data content with an unknown protocol is rejected in an answer.
1563TEST_F(MediaSessionDescriptionFactoryTest,
1564 CreateDataAnswerToOfferWithUnknownProtocol) {
1565 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001566 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001567 f1_.set_secure(SEC_ENABLED);
1568 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001569 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001570 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001571 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001572 RtpDataContentDescription* dcd_offer =
1573 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001575 // Offer must be acceptable as an RTP protocol in order to be set.
1576 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001577 dcd_offer->set_protocol(protocol);
1578
Steve Anton6fe1fba2018-12-11 10:15:23 -08001579 std::unique_ptr<SessionDescription> answer =
1580 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001581
1582 const ContentInfo* dc_answer = answer->GetContentByName("data");
1583 ASSERT_TRUE(dc_answer != NULL);
1584 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001585 const RtpDataContentDescription* dcd_answer =
1586 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001587 ASSERT_TRUE(dcd_answer != NULL);
1588 EXPECT_EQ(protocol, dcd_answer->protocol());
1589}
1590
1591// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1592TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001593 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001594 f1_.set_secure(SEC_DISABLED);
1595 f2_.set_secure(SEC_DISABLED);
1596 tdf1_.set_secure(SEC_DISABLED);
1597 tdf2_.set_secure(SEC_DISABLED);
1598
Steve Anton6fe1fba2018-12-11 10:15:23 -08001599 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001600 const AudioContentDescription* offer_acd =
1601 GetFirstAudioContentDescription(offer.get());
1602 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001603 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604
Steve Anton6fe1fba2018-12-11 10:15:23 -08001605 std::unique_ptr<SessionDescription> answer =
1606 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001607
1608 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1609 ASSERT_TRUE(ac_answer != NULL);
1610 EXPECT_FALSE(ac_answer->rejected);
1611
1612 const AudioContentDescription* answer_acd =
1613 GetFirstAudioContentDescription(answer.get());
1614 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001615 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001616}
1617
1618// Create a video offer and answer and ensure the RTP header extensions
1619// matches what we expect.
1620TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1621 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001622 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001623 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1624 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1625 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1626 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1627
Steve Anton6fe1fba2018-12-11 10:15:23 -08001628 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001629 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001630 std::unique_ptr<SessionDescription> answer =
1631 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001632
Yves Gerey665174f2018-06-19 15:03:05 +02001633 EXPECT_EQ(
1634 MAKE_VECTOR(kAudioRtpExtension1),
1635 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1636 EXPECT_EQ(
1637 MAKE_VECTOR(kVideoRtpExtension1),
1638 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1639 EXPECT_EQ(
1640 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1641 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1642 EXPECT_EQ(
1643 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1644 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001645}
1646
Johannes Kronce8e8672019-02-22 13:06:44 +01001647// Create a audio/video offer and answer and ensure that the
1648// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1649// supported and should take precedence even though not listed among locally
1650// supported extensions.
1651TEST_F(MediaSessionDescriptionFactoryTest,
1652 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1653 TestTransportSequenceNumberNegotiation(
1654 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1655 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1656 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1657}
1658TEST_F(MediaSessionDescriptionFactoryTest,
1659 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1660 TestTransportSequenceNumberNegotiation(
1661 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1662 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1663 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1664}
1665TEST_F(MediaSessionDescriptionFactoryTest,
1666 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1667 TestTransportSequenceNumberNegotiation(
1668 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1669 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1670 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1671}
1672
jbauch5869f502017-06-29 12:31:36 -07001673TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001674 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001675 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001676 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001677
1678 f1_.set_enable_encrypted_rtp_header_extensions(true);
1679 f2_.set_enable_encrypted_rtp_header_extensions(true);
1680
Yves Gerey665174f2018-06-19 15:03:05 +02001681 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1682 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1683 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1684 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001685
Steve Anton6fe1fba2018-12-11 10:15:23 -08001686 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001687 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001688 std::unique_ptr<SessionDescription> answer =
1689 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001690
Yves Gerey665174f2018-06-19 15:03:05 +02001691 EXPECT_EQ(
1692 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1693 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1694 EXPECT_EQ(
1695 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1696 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1697 EXPECT_EQ(
1698 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1699 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1700 EXPECT_EQ(
1701 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1702 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001703}
1704
1705TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001706 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001707 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001708 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001709
1710 f1_.set_enable_encrypted_rtp_header_extensions(true);
1711
Yves Gerey665174f2018-06-19 15:03:05 +02001712 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1713 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1714 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1715 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001716
Steve Anton6fe1fba2018-12-11 10:15:23 -08001717 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001718 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001719 std::unique_ptr<SessionDescription> answer =
1720 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001721
Yves Gerey665174f2018-06-19 15:03:05 +02001722 EXPECT_EQ(
1723 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1724 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1725 EXPECT_EQ(
1726 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1727 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1728 EXPECT_EQ(
1729 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1730 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1731 EXPECT_EQ(
1732 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1733 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001734}
1735
1736TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001737 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001738 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001739 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001740
1741 f2_.set_enable_encrypted_rtp_header_extensions(true);
1742
Yves Gerey665174f2018-06-19 15:03:05 +02001743 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1744 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1745 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1746 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001747
Steve Anton6fe1fba2018-12-11 10:15:23 -08001748 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001749 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001750 std::unique_ptr<SessionDescription> answer =
1751 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001752
Yves Gerey665174f2018-06-19 15:03:05 +02001753 EXPECT_EQ(
1754 MAKE_VECTOR(kAudioRtpExtension1),
1755 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1756 EXPECT_EQ(
1757 MAKE_VECTOR(kVideoRtpExtension1),
1758 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1759 EXPECT_EQ(
1760 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1761 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1762 EXPECT_EQ(
1763 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1764 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001765}
1766
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767// Create an audio, video, data answer without legacy StreamParams.
1768TEST_F(MediaSessionDescriptionFactoryTest,
1769 TestCreateAnswerWithoutLegacyStreams) {
1770 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001771 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1772 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001773 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001775 std::unique_ptr<SessionDescription> answer =
1776 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777 const ContentInfo* ac = answer->GetContentByName("audio");
1778 const ContentInfo* vc = answer->GetContentByName("video");
1779 const ContentInfo* dc = answer->GetContentByName("data");
1780 ASSERT_TRUE(ac != NULL);
1781 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001782 const AudioContentDescription* acd = ac->media_description()->as_audio();
1783 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001784 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001785
1786 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1787 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1788 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1789}
1790
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001791// Create a typical video answer, and ensure it matches what we expect.
1792TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1793 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001794 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1795 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1796 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001797
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001798 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001799 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1800 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1801 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001802
kwiberg31022942016-03-11 14:18:21 -08001803 std::unique_ptr<SessionDescription> offer;
1804 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001805
1806 offer_opts.rtcp_mux_enabled = true;
1807 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001808 offer = f1_.CreateOffer(offer_opts, NULL);
1809 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001810 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1811 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001812 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001813 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1814 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001815 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001816 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1817 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001818 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001819 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1820 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001821 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001822
1823 offer_opts.rtcp_mux_enabled = true;
1824 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001825 offer = f1_.CreateOffer(offer_opts, NULL);
1826 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001827 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1828 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001829 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001830 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1831 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001832 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001833 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1834 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001835 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001836 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1837 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001838 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001839
1840 offer_opts.rtcp_mux_enabled = false;
1841 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001842 offer = f1_.CreateOffer(offer_opts, NULL);
1843 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001844 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1845 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001846 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1848 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001849 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001850 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1851 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001852 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001853 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1854 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001855 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001856
1857 offer_opts.rtcp_mux_enabled = false;
1858 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001859 offer = f1_.CreateOffer(offer_opts, NULL);
1860 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001861 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1862 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001863 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001864 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1865 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001866 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001867 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1868 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001869 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001870 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1871 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001872 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001873}
1874
1875// Create an audio-only answer to a video offer.
1876TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1877 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001878 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1879 RtpTransceiverDirection::kRecvOnly, kActive,
1880 &opts);
1881 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1882 RtpTransceiverDirection::kRecvOnly, kActive,
1883 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001884 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001885 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001886
1887 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001888 std::unique_ptr<SessionDescription> answer =
1889 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001890 const ContentInfo* ac = answer->GetContentByName("audio");
1891 const ContentInfo* vc = answer->GetContentByName("video");
1892 ASSERT_TRUE(ac != NULL);
1893 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001894 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001895 EXPECT_TRUE(vc->rejected);
1896}
1897
1898// Create an audio-only answer to an offer with data.
1899TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001900 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001901 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001902 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1903 RtpTransceiverDirection::kRecvOnly, kActive,
1904 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001905 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001906 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001907
1908 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001909 std::unique_ptr<SessionDescription> answer =
1910 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001911 const ContentInfo* ac = answer->GetContentByName("audio");
1912 const ContentInfo* dc = answer->GetContentByName("data");
1913 ASSERT_TRUE(ac != NULL);
1914 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001915 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001916 EXPECT_TRUE(dc->rejected);
1917}
1918
1919// Create an answer that rejects the contents which are rejected in the offer.
1920TEST_F(MediaSessionDescriptionFactoryTest,
1921 CreateAnswerToOfferWithRejectedMedia) {
1922 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001923 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1924 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001925 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001926 ASSERT_TRUE(offer.get() != NULL);
1927 ContentInfo* ac = offer->GetContentByName("audio");
1928 ContentInfo* vc = offer->GetContentByName("video");
1929 ContentInfo* dc = offer->GetContentByName("data");
1930 ASSERT_TRUE(ac != NULL);
1931 ASSERT_TRUE(vc != NULL);
1932 ASSERT_TRUE(dc != NULL);
1933 ac->rejected = true;
1934 vc->rejected = true;
1935 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001936 std::unique_ptr<SessionDescription> answer =
1937 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001938 ac = answer->GetContentByName("audio");
1939 vc = answer->GetContentByName("video");
1940 dc = answer->GetContentByName("data");
1941 ASSERT_TRUE(ac != NULL);
1942 ASSERT_TRUE(vc != NULL);
1943 ASSERT_TRUE(dc != NULL);
1944 EXPECT_TRUE(ac->rejected);
1945 EXPECT_TRUE(vc->rejected);
1946 EXPECT_TRUE(dc->rejected);
1947}
1948
Johannes Kron0854eb62018-10-10 22:33:20 +02001949TEST_F(MediaSessionDescriptionFactoryTest,
1950 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1951 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001952 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001953 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001954 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001955 ASSERT_TRUE(offer.get() != NULL);
1956 std::unique_ptr<SessionDescription> answer_no_support(
1957 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001958 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001959
1960 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001961 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001962 ASSERT_TRUE(offer.get() != NULL);
1963 std::unique_ptr<SessionDescription> answer_support(
1964 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001965 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001966}
1967
1968TEST_F(MediaSessionDescriptionFactoryTest,
1969 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1970 MediaSessionOptions opts;
1971 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001972 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001973 MediaContentDescription* video_offer =
1974 offer->GetContentDescriptionByName("video");
1975 ASSERT_TRUE(video_offer);
1976 MediaContentDescription* audio_offer =
1977 offer->GetContentDescriptionByName("audio");
1978 ASSERT_TRUE(audio_offer);
1979
1980 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001981 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1982 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001983
1984 ASSERT_TRUE(offer.get() != NULL);
1985 std::unique_ptr<SessionDescription> answer_no_support(
1986 f2_.CreateAnswer(offer.get(), opts, NULL));
1987 MediaContentDescription* video_answer =
1988 answer_no_support->GetContentDescriptionByName("video");
1989 MediaContentDescription* audio_answer =
1990 answer_no_support->GetContentDescriptionByName("audio");
1991 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001992 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001993 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001994 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001995
1996 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001997 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1998 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001999 ASSERT_TRUE(offer.get() != NULL);
2000 std::unique_ptr<SessionDescription> answer_support(
2001 f2_.CreateAnswer(offer.get(), opts, NULL));
2002 video_answer = answer_support->GetContentDescriptionByName("video");
2003 audio_answer = answer_support->GetContentDescriptionByName("audio");
2004 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002005 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002006 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002007 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002008}
2009
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010// Create an audio and video offer with:
2011// - one video track
2012// - two audio tracks
2013// - two data tracks
2014// and ensure it matches what we expect. Also updates the initial offer by
2015// adding a new video track and replaces one of the audio tracks.
2016TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2017 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002018 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002019 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2020 {kMediaStream1}, 1, &opts);
2021 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2022 {kMediaStream1}, 1, &opts);
2023 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2024 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002025
Steve Anton4e70a722017-11-28 14:57:10 -08002026 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002027 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2028 {kMediaStream1}, 1, &opts);
2029 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2030 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002031
2032 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002033 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034
2035 ASSERT_TRUE(offer.get() != NULL);
2036 const ContentInfo* ac = offer->GetContentByName("audio");
2037 const ContentInfo* vc = offer->GetContentByName("video");
2038 const ContentInfo* dc = offer->GetContentByName("data");
2039 ASSERT_TRUE(ac != NULL);
2040 ASSERT_TRUE(vc != NULL);
2041 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002042 const AudioContentDescription* acd = ac->media_description()->as_audio();
2043 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002044 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002045 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002046 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047
2048 const StreamParamsVec& audio_streams = acd->streams();
2049 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002050 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002051 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2052 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2053 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2054 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2055 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2056 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2057
2058 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2059 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002060 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002061
2062 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
2063 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002064 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065
2066 const StreamParamsVec& video_streams = vcd->streams();
2067 ASSERT_EQ(1U, video_streams.size());
2068 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2069 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2070 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2071 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2072
2073 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002074 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002075 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002076
2077 const StreamParamsVec& data_streams = dcd->streams();
2078 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002079 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002080 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2081 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2082 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2083 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2084 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2085 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2086
2087 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002088 dcd->bandwidth()); // default bandwidth (auto)
2089 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002090 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002091
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002092 // Update the offer. Add a new video track that is not synched to the
2093 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002094 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2095 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002096 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002097 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2098 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002099 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002100 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2101 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002102 std::unique_ptr<SessionDescription> updated_offer(
2103 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002104
2105 ASSERT_TRUE(updated_offer.get() != NULL);
2106 ac = updated_offer->GetContentByName("audio");
2107 vc = updated_offer->GetContentByName("video");
2108 dc = updated_offer->GetContentByName("data");
2109 ASSERT_TRUE(ac != NULL);
2110 ASSERT_TRUE(vc != NULL);
2111 ASSERT_TRUE(dc != NULL);
2112 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002113 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002114 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002115 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002116 const RtpDataContentDescription* updated_dcd =
2117 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002118
2119 EXPECT_EQ(acd->type(), updated_acd->type());
2120 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2121 EXPECT_EQ(vcd->type(), updated_vcd->type());
2122 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2123 EXPECT_EQ(dcd->type(), updated_dcd->type());
2124 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002125 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002126 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002127 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002128 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002129 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2131
2132 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2133 ASSERT_EQ(2U, updated_audio_streams.size());
2134 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2135 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2136 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2137 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2138 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2139
2140 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2141 ASSERT_EQ(2U, updated_video_streams.size());
2142 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2143 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002144 // All the media streams in one PeerConnection share one RTCP CNAME.
2145 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002146
2147 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2148 ASSERT_EQ(2U, updated_data_streams.size());
2149 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2150 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2151 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2152 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2153 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002154 // The stream correctly got the CNAME from the MediaSessionOptions.
2155 // The Expected RTCP CNAME is the default one as we are using the default
2156 // MediaSessionOptions.
2157 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002158}
2159
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002160// Create an offer with simulcast video stream.
2161TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2162 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002163 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2164 RtpTransceiverDirection::kRecvOnly, kActive,
2165 &opts);
2166 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2167 RtpTransceiverDirection::kSendRecv, kActive,
2168 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002169 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002170 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2171 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002172 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002173
2174 ASSERT_TRUE(offer.get() != NULL);
2175 const ContentInfo* vc = offer->GetContentByName("video");
2176 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002177 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002178
2179 const StreamParamsVec& video_streams = vcd->streams();
2180 ASSERT_EQ(1U, video_streams.size());
2181 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2182 const SsrcGroup* sim_ssrc_group =
2183 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2184 ASSERT_TRUE(sim_ssrc_group != NULL);
2185 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2186}
2187
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002188MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2189 const RidDescription& rid1 = ::testing::get<0>(arg);
2190 const RidDescription& rid2 = ::testing::get<1>(arg);
2191 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2192}
2193
2194static void CheckSimulcastInSessionDescription(
2195 const SessionDescription* description,
2196 const std::string& content_name,
2197 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002198 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002199 ASSERT_NE(description, nullptr);
2200 const ContentInfo* content = description->GetContentByName(content_name);
2201 ASSERT_NE(content, nullptr);
2202 const MediaContentDescription* cd = content->media_description();
2203 ASSERT_NE(cd, nullptr);
2204 const StreamParamsVec& streams = cd->streams();
2205 ASSERT_THAT(streams, SizeIs(1));
2206 const StreamParams& stream = streams[0];
2207 ASSERT_THAT(stream.ssrcs, IsEmpty());
2208 EXPECT_TRUE(stream.has_rids());
2209 const std::vector<RidDescription> rids = stream.rids();
2210
2211 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2212
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002213 EXPECT_TRUE(cd->HasSimulcast());
2214 const SimulcastDescription& simulcast = cd->simulcast_description();
2215 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2216 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2217
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002218 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002219}
2220
2221// Create an offer with spec-compliant simulcast video stream.
2222TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2223 MediaSessionOptions opts;
2224 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2225 RtpTransceiverDirection::kSendRecv, kActive,
2226 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002227 std::vector<RidDescription> send_rids;
2228 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2229 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2230 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2231 SimulcastLayerList simulcast_layers;
2232 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2233 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2234 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2235 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2236 {kMediaStream1}, send_rids,
2237 simulcast_layers, 0, &opts);
2238 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2239
2240 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002241 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002242}
2243
2244// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2245// In this scenario, RIDs do not need to be negotiated (there is only one).
2246TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2247 MediaSessionOptions opts;
2248 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2249 RtpTransceiverDirection::kSendRecv, kActive,
2250 &opts);
2251 RidDescription rid("f", RidDirection::kSend);
2252 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2253 {kMediaStream1}, {rid},
2254 SimulcastLayerList(), 0, &opts);
2255 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2256
2257 ASSERT_NE(offer.get(), nullptr);
2258 const ContentInfo* content = offer->GetContentByName("video");
2259 ASSERT_NE(content, nullptr);
2260 const MediaContentDescription* cd = content->media_description();
2261 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002262 const StreamParamsVec& streams = cd->streams();
2263 ASSERT_THAT(streams, SizeIs(1));
2264 const StreamParams& stream = streams[0];
2265 ASSERT_THAT(stream.ssrcs, IsEmpty());
2266 EXPECT_FALSE(stream.has_rids());
2267 EXPECT_FALSE(cd->HasSimulcast());
2268}
2269
2270// Create an answer with spec-compliant simulcast video stream.
2271// In this scenario, the SFU is the caller requesting that we send Simulcast.
2272TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2273 MediaSessionOptions offer_opts;
2274 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2275 RtpTransceiverDirection::kSendRecv, kActive,
2276 &offer_opts);
2277 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2278 {kMediaStream1}, 1, &offer_opts);
2279 std::unique_ptr<SessionDescription> offer =
2280 f1_.CreateOffer(offer_opts, nullptr);
2281
2282 MediaSessionOptions answer_opts;
2283 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2284 RtpTransceiverDirection::kSendRecv, kActive,
2285 &answer_opts);
2286
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002287 std::vector<RidDescription> rid_descriptions{
2288 RidDescription("f", RidDirection::kSend),
2289 RidDescription("h", RidDirection::kSend),
2290 RidDescription("q", RidDirection::kSend),
2291 };
2292 SimulcastLayerList simulcast_layers;
2293 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2294 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2295 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2296 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2297 {kMediaStream1}, rid_descriptions,
2298 simulcast_layers, 0, &answer_opts);
2299 std::unique_ptr<SessionDescription> answer =
2300 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2301
2302 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002303 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002304}
2305
2306// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2307// In this scenario, RIDs do not need to be negotiated (there is only one).
2308// Note that RID Direction is not the same as the transceiver direction.
2309TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2310 MediaSessionOptions offer_opts;
2311 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2312 RtpTransceiverDirection::kSendRecv, kActive,
2313 &offer_opts);
2314 RidDescription rid_offer("f", RidDirection::kSend);
2315 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2316 {kMediaStream1}, {rid_offer},
2317 SimulcastLayerList(), 0, &offer_opts);
2318 std::unique_ptr<SessionDescription> offer =
2319 f1_.CreateOffer(offer_opts, nullptr);
2320
2321 MediaSessionOptions answer_opts;
2322 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2323 RtpTransceiverDirection::kSendRecv, kActive,
2324 &answer_opts);
2325
2326 RidDescription rid_answer("f", RidDirection::kReceive);
2327 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2328 {kMediaStream1}, {rid_answer},
2329 SimulcastLayerList(), 0, &answer_opts);
2330 std::unique_ptr<SessionDescription> answer =
2331 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2332
2333 ASSERT_NE(answer.get(), nullptr);
2334 const ContentInfo* content = offer->GetContentByName("video");
2335 ASSERT_NE(content, nullptr);
2336 const MediaContentDescription* cd = content->media_description();
2337 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002338 const StreamParamsVec& streams = cd->streams();
2339 ASSERT_THAT(streams, SizeIs(1));
2340 const StreamParams& stream = streams[0];
2341 ASSERT_THAT(stream.ssrcs, IsEmpty());
2342 EXPECT_FALSE(stream.has_rids());
2343 EXPECT_FALSE(cd->HasSimulcast());
2344}
2345
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002346// Create an audio and video answer to a standard video offer with:
2347// - one video track
2348// - two audio tracks
2349// - two data tracks
2350// and ensure it matches what we expect. Also updates the initial answer by
2351// adding a new video track and removes one of the audio tracks.
2352TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2353 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002354 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2355 RtpTransceiverDirection::kRecvOnly, kActive,
2356 &offer_opts);
2357 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2358 RtpTransceiverDirection::kRecvOnly, kActive,
2359 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002361 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2362 RtpTransceiverDirection::kRecvOnly, kActive,
2363 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002364 f1_.set_secure(SEC_ENABLED);
2365 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002366 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002367
zhihuang1c378ed2017-08-17 14:10:50 -07002368 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002369 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2370 RtpTransceiverDirection::kSendRecv, kActive,
2371 &answer_opts);
2372 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2373 RtpTransceiverDirection::kSendRecv, kActive,
2374 &answer_opts);
2375 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2376 {kMediaStream1}, 1, &answer_opts);
2377 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2378 {kMediaStream1}, 1, &answer_opts);
2379 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2380 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002381
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002382 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2383 RtpTransceiverDirection::kSendRecv, kActive,
2384 &answer_opts);
2385 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2386 {kMediaStream1}, 1, &answer_opts);
2387 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2388 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002389 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002390
Steve Anton6fe1fba2018-12-11 10:15:23 -08002391 std::unique_ptr<SessionDescription> answer =
2392 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002393
2394 ASSERT_TRUE(answer.get() != NULL);
2395 const ContentInfo* ac = answer->GetContentByName("audio");
2396 const ContentInfo* vc = answer->GetContentByName("video");
2397 const ContentInfo* dc = answer->GetContentByName("data");
2398 ASSERT_TRUE(ac != NULL);
2399 ASSERT_TRUE(vc != NULL);
2400 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002401 const AudioContentDescription* acd = ac->media_description()->as_audio();
2402 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002403 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002404 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2405 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2406 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002407
2408 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002409 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002410
2411 const StreamParamsVec& audio_streams = acd->streams();
2412 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002413 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002414 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2415 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2416 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2417 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2418 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2419 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2420
2421 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2422 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2423
2424 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002425 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002426
2427 const StreamParamsVec& video_streams = vcd->streams();
2428 ASSERT_EQ(1U, video_streams.size());
2429 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2430 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2431 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2432 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2433
2434 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002435 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002436
2437 const StreamParamsVec& data_streams = dcd->streams();
2438 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002439 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002440 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2441 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2442 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2443 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2444 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2445 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2446
2447 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002448 dcd->bandwidth()); // default bandwidth (auto)
2449 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002450
2451 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002452 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002453 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2454 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002455 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2456 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002457 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002458 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002459
2460 ASSERT_TRUE(updated_answer.get() != NULL);
2461 ac = updated_answer->GetContentByName("audio");
2462 vc = updated_answer->GetContentByName("video");
2463 dc = updated_answer->GetContentByName("data");
2464 ASSERT_TRUE(ac != NULL);
2465 ASSERT_TRUE(vc != NULL);
2466 ASSERT_TRUE(dc != NULL);
2467 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002468 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002469 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002470 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002471 const RtpDataContentDescription* updated_dcd =
2472 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002473
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002474 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002475 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002476 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002477 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002478 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002479 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2480
2481 EXPECT_EQ(acd->type(), updated_acd->type());
2482 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2483 EXPECT_EQ(vcd->type(), updated_vcd->type());
2484 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2485 EXPECT_EQ(dcd->type(), updated_dcd->type());
2486 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2487
2488 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2489 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002490 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002491
2492 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2493 ASSERT_EQ(2U, updated_video_streams.size());
2494 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2495 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002496 // All media streams in one PeerConnection share one CNAME.
2497 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002498
2499 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2500 ASSERT_EQ(1U, updated_data_streams.size());
2501 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2502}
2503
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002504// Create an updated offer after creating an answer to the original offer and
2505// verify that the codecs that were part of the original answer are not changed
2506// in the updated offer.
2507TEST_F(MediaSessionDescriptionFactoryTest,
2508 RespondentCreatesOfferAfterCreatingAnswer) {
2509 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002510 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002511
Steve Anton6fe1fba2018-12-11 10:15:23 -08002512 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2513 std::unique_ptr<SessionDescription> answer =
2514 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002515
2516 const AudioContentDescription* acd =
2517 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002518 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002519
2520 const VideoContentDescription* vcd =
2521 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002522 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002523
kwiberg31022942016-03-11 14:18:21 -08002524 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002525 f2_.CreateOffer(opts, answer.get()));
2526
2527 // The expected audio codecs are the common audio codecs from the first
2528 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2529 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002530 // TODO(wu): |updated_offer| should not include the codec
2531 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002532 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002533 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002534 };
2535
2536 // The expected video codecs are the common video codecs from the first
2537 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2538 // preference order.
2539 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002540 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002541 };
2542
2543 const AudioContentDescription* updated_acd =
2544 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002545 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002546
2547 const VideoContentDescription* updated_vcd =
2548 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002549 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002550}
2551
Steve Anton5c72e712018-12-10 14:25:30 -08002552// Test that a reoffer does not reuse audio codecs from a previous media section
2553// that is being recycled.
2554TEST_F(MediaSessionDescriptionFactoryTest,
2555 ReOfferDoesNotReUseRecycledAudioCodecs) {
2556 f1_.set_video_codecs({});
2557 f2_.set_video_codecs({});
2558
2559 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002560 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2561 RtpTransceiverDirection::kSendRecv, kActive,
2562 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002563 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2564 std::unique_ptr<SessionDescription> answer =
2565 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002566
2567 // Recycle the media section by changing its mid.
2568 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002569 std::unique_ptr<SessionDescription> reoffer =
2570 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002571
2572 // Expect that the results of the first negotiation are ignored. If the m=
2573 // section was not recycled the payload types would match the initial offerer.
2574 const AudioContentDescription* acd =
2575 GetFirstAudioContentDescription(reoffer.get());
2576 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2577}
2578
2579// Test that a reoffer does not reuse video codecs from a previous media section
2580// that is being recycled.
2581TEST_F(MediaSessionDescriptionFactoryTest,
2582 ReOfferDoesNotReUseRecycledVideoCodecs) {
2583 f1_.set_audio_codecs({}, {});
2584 f2_.set_audio_codecs({}, {});
2585
2586 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002587 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2588 RtpTransceiverDirection::kSendRecv, kActive,
2589 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002590 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2591 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002592
2593 // Recycle the media section by changing its mid.
2594 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002595 std::unique_ptr<SessionDescription> reoffer =
2596 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002597
2598 // Expect that the results of the first negotiation are ignored. If the m=
2599 // section was not recycled the payload types would match the initial offerer.
2600 const VideoContentDescription* vcd =
2601 GetFirstVideoContentDescription(reoffer.get());
2602 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2603}
2604
2605// Test that a reanswer does not reuse audio codecs from a previous media
2606// section that is being recycled.
2607TEST_F(MediaSessionDescriptionFactoryTest,
2608 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2609 f1_.set_video_codecs({});
2610 f2_.set_video_codecs({});
2611
2612 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2613 // second offer/answer is forward (|f1_| as offerer).
2614 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002615 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2616 RtpTransceiverDirection::kSendRecv, kActive,
2617 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002618 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2619 std::unique_ptr<SessionDescription> answer =
2620 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002621
2622 // Recycle the media section by changing its mid.
2623 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002624 std::unique_ptr<SessionDescription> reoffer =
2625 f1_.CreateOffer(opts, answer.get());
2626 std::unique_ptr<SessionDescription> reanswer =
2627 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002628
2629 // Expect that the results of the first negotiation are ignored. If the m=
2630 // section was not recycled the payload types would match the initial offerer.
2631 const AudioContentDescription* acd =
2632 GetFirstAudioContentDescription(reanswer.get());
2633 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2634}
2635
2636// Test that a reanswer does not reuse video codecs from a previous media
2637// section that is being recycled.
2638TEST_F(MediaSessionDescriptionFactoryTest,
2639 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2640 f1_.set_audio_codecs({}, {});
2641 f2_.set_audio_codecs({}, {});
2642
2643 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2644 // second offer/answer is forward (|f1_| as offerer).
2645 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002646 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2647 RtpTransceiverDirection::kSendRecv, kActive,
2648 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002649 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2650 std::unique_ptr<SessionDescription> answer =
2651 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002652
2653 // Recycle the media section by changing its mid.
2654 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002655 std::unique_ptr<SessionDescription> reoffer =
2656 f1_.CreateOffer(opts, answer.get());
2657 std::unique_ptr<SessionDescription> reanswer =
2658 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002659
2660 // Expect that the results of the first negotiation are ignored. If the m=
2661 // section was not recycled the payload types would match the initial offerer.
2662 const VideoContentDescription* vcd =
2663 GetFirstVideoContentDescription(reanswer.get());
2664 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2665}
2666
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002667// Create an updated offer after creating an answer to the original offer and
2668// verify that the codecs that were part of the original answer are not changed
2669// in the updated offer. In this test Rtx is enabled.
2670TEST_F(MediaSessionDescriptionFactoryTest,
2671 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2672 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002673 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2674 RtpTransceiverDirection::kRecvOnly, kActive,
2675 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002676 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002677 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002678 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002679 f1_.set_video_codecs(f1_codecs);
2680
2681 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002682 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002683 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684 f2_.set_video_codecs(f2_codecs);
2685
Steve Anton6fe1fba2018-12-11 10:15:23 -08002686 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002687 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002688 std::unique_ptr<SessionDescription> answer =
2689 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002690
2691 const VideoContentDescription* vcd =
2692 GetFirstVideoContentDescription(answer.get());
2693
2694 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002695 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2696 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002697
2698 EXPECT_EQ(expected_codecs, vcd->codecs());
2699
deadbeef67cf2c12016-04-13 10:07:16 -07002700 // Now, make sure we get same result (except for the order) if |f2_| creates
2701 // an updated offer even though the default payload types between |f1_| and
2702 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002703 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002704 f2_.CreateOffer(opts, answer.get()));
2705 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002706 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2708
2709 const VideoContentDescription* updated_vcd =
2710 GetFirstVideoContentDescription(updated_answer.get());
2711
2712 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2713}
2714
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002715// Regression test for:
2716// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2717// Existing codecs should always appear before new codecs in re-offers. But
2718// under a specific set of circumstances, the existing RTX codec was ending up
2719// added to the end of the list.
2720TEST_F(MediaSessionDescriptionFactoryTest,
2721 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2722 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002723 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2724 RtpTransceiverDirection::kRecvOnly, kActive,
2725 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002726 // We specifically choose different preferred payload types for VP8 to
2727 // trigger the issue.
2728 cricket::VideoCodec vp8_offerer(100, "VP8");
2729 cricket::VideoCodec vp8_offerer_rtx =
2730 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2731 cricket::VideoCodec vp8_answerer(110, "VP8");
2732 cricket::VideoCodec vp8_answerer_rtx =
2733 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2734 cricket::VideoCodec vp9(120, "VP9");
2735 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2736
2737 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2738 // We also specifically cause the answerer to prefer VP9, such that if it
2739 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2740 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2741 vp8_answerer_rtx};
2742
2743 f1_.set_video_codecs(f1_codecs);
2744 f2_.set_video_codecs(f2_codecs);
2745 std::vector<AudioCodec> audio_codecs;
2746 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2747 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2748
2749 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002750 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002751 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002752 std::unique_ptr<SessionDescription> answer =
2753 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002754
2755 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2756 // But if the bug is triggered, RTX for VP8 ends up last.
2757 std::unique_ptr<SessionDescription> updated_offer(
2758 f2_.CreateOffer(opts, answer.get()));
2759
2760 const VideoContentDescription* vcd =
2761 GetFirstVideoContentDescription(updated_offer.get());
2762 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2763 ASSERT_EQ(4u, codecs.size());
2764 EXPECT_EQ(vp8_offerer, codecs[0]);
2765 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2766 EXPECT_EQ(vp9, codecs[2]);
2767 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002768}
2769
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002770// Create an updated offer that adds video after creating an audio only answer
2771// to the original offer. This test verifies that if a video codec and the RTX
2772// codec have the same default payload type as an audio codec that is already in
2773// use, the added codecs payload types are changed.
2774TEST_F(MediaSessionDescriptionFactoryTest,
2775 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2776 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002778 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002779 f1_.set_video_codecs(f1_codecs);
2780
2781 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002782 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2783 RtpTransceiverDirection::kRecvOnly, kActive,
2784 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002785
Steve Anton6fe1fba2018-12-11 10:15:23 -08002786 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2787 std::unique_ptr<SessionDescription> answer =
2788 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002789
2790 const AudioContentDescription* acd =
2791 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002792 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793
2794 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2795 // reference be the same as an audio codec that was negotiated in the
2796 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002797 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002798 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002799
2800 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2801 int used_pl_type = acd->codecs()[0].id;
2802 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002803 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002804 f2_.set_video_codecs(f2_codecs);
2805
kwiberg31022942016-03-11 14:18:21 -08002806 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002807 f2_.CreateOffer(opts, answer.get()));
2808 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002809 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002810 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2811
2812 const AudioContentDescription* updated_acd =
2813 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002814 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002815
2816 const VideoContentDescription* updated_vcd =
2817 GetFirstVideoContentDescription(updated_answer.get());
2818
2819 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002820 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002821 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002822 EXPECT_NE(used_pl_type, new_h264_pl_type);
2823 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002824 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002825 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2826 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2827}
2828
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002829// Create an updated offer with RTX after creating an answer to an offer
2830// without RTX, and with different default payload types.
2831// Verify that the added RTX codec references the correct payload type.
2832TEST_F(MediaSessionDescriptionFactoryTest,
2833 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2834 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002835 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002836
2837 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2838 // This creates rtx for H264 with the payload type |f2_| uses.
2839 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2840 f2_.set_video_codecs(f2_codecs);
2841
Steve Anton6fe1fba2018-12-11 10:15:23 -08002842 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002843 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002844 std::unique_ptr<SessionDescription> answer =
2845 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002846
2847 const VideoContentDescription* vcd =
2848 GetFirstVideoContentDescription(answer.get());
2849
2850 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2851 EXPECT_EQ(expected_codecs, vcd->codecs());
2852
2853 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2854 // updated offer, even though the default payload types are different from
2855 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002856 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002857 f2_.CreateOffer(opts, answer.get()));
2858 ASSERT_TRUE(updated_offer);
2859
2860 const VideoContentDescription* updated_vcd =
2861 GetFirstVideoContentDescription(updated_offer.get());
2862
2863 // New offer should attempt to add H263, and RTX for H264.
2864 expected_codecs.push_back(kVideoCodecs2[1]);
2865 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2866 &expected_codecs);
2867 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2868}
2869
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002870// Test that RTX is ignored when there is no associated payload type parameter.
2871TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2872 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002873 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2874 RtpTransceiverDirection::kRecvOnly, kActive,
2875 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002876 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002877 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002878 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002879 f1_.set_video_codecs(f1_codecs);
2880
2881 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002882 // This creates RTX for H264 with the payload type |f2_| uses.
2883 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002884 f2_.set_video_codecs(f2_codecs);
2885
Steve Anton6fe1fba2018-12-11 10:15:23 -08002886 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002887 ASSERT_TRUE(offer.get() != NULL);
2888 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2889 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2890 // is possible to test that that RTX is dropped when
2891 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002892 MediaContentDescription* media_desc =
2893 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2894 ASSERT_TRUE(media_desc);
2895 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002896 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002897 for (VideoCodec& codec : codecs) {
2898 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2899 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002900 }
2901 }
2902 desc->set_codecs(codecs);
2903
Steve Anton6fe1fba2018-12-11 10:15:23 -08002904 std::unique_ptr<SessionDescription> answer =
2905 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002906
Steve Anton64b626b2019-01-28 17:25:26 -08002907 EXPECT_THAT(
2908 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2909 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002910}
2911
2912// Test that RTX will be filtered out in the answer if its associated payload
2913// type doesn't match the local value.
2914TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2915 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002916 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2917 RtpTransceiverDirection::kRecvOnly, kActive,
2918 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002919 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2920 // This creates RTX for H264 in sender.
2921 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2922 f1_.set_video_codecs(f1_codecs);
2923
2924 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2925 // This creates RTX for H263 in receiver.
2926 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2927 f2_.set_video_codecs(f2_codecs);
2928
Steve Anton6fe1fba2018-12-11 10:15:23 -08002929 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002930 ASSERT_TRUE(offer.get() != NULL);
2931 // Associated payload type doesn't match, therefore, RTX codec is removed in
2932 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002933 std::unique_ptr<SessionDescription> answer =
2934 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002935
Steve Anton64b626b2019-01-28 17:25:26 -08002936 EXPECT_THAT(
2937 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2938 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002939}
2940
2941// Test that when multiple RTX codecs are offered, only the matched RTX codec
2942// is added in the answer, and the unsupported RTX codec is filtered out.
2943TEST_F(MediaSessionDescriptionFactoryTest,
2944 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2945 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002946 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2947 RtpTransceiverDirection::kRecvOnly, kActive,
2948 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002949 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2950 // This creates RTX for H264-SVC in sender.
2951 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2952 f1_.set_video_codecs(f1_codecs);
2953
2954 // This creates RTX for H264 in sender.
2955 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2956 f1_.set_video_codecs(f1_codecs);
2957
2958 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2959 // This creates RTX for H264 in receiver.
2960 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2961 f2_.set_video_codecs(f2_codecs);
2962
2963 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2964 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002965 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002966 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002967 std::unique_ptr<SessionDescription> answer =
2968 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002969 const VideoContentDescription* vcd =
2970 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002971 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2972 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2973 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002975 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002976}
2977
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002978// Test that after one RTX codec has been negotiated, a new offer can attempt
2979// to add another.
2980TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2981 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002982 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2983 RtpTransceiverDirection::kRecvOnly, kActive,
2984 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002985 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2986 // This creates RTX for H264 for the offerer.
2987 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2988 f1_.set_video_codecs(f1_codecs);
2989
Steve Anton6fe1fba2018-12-11 10:15:23 -08002990 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002991 ASSERT_TRUE(offer);
2992 const VideoContentDescription* vcd =
2993 GetFirstVideoContentDescription(offer.get());
2994
2995 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2996 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2997 &expected_codecs);
2998 EXPECT_EQ(expected_codecs, vcd->codecs());
2999
3000 // Now, attempt to add RTX for H264-SVC.
3001 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
3002 f1_.set_video_codecs(f1_codecs);
3003
kwiberg31022942016-03-11 14:18:21 -08003004 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003005 f1_.CreateOffer(opts, offer.get()));
3006 ASSERT_TRUE(updated_offer);
3007 vcd = GetFirstVideoContentDescription(updated_offer.get());
3008
3009 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3010 &expected_codecs);
3011 EXPECT_EQ(expected_codecs, vcd->codecs());
3012}
3013
Noah Richards2e7a0982015-05-18 14:02:54 -07003014// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3015// generated for each simulcast ssrc and correctly grouped.
3016TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3017 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003018 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3019 RtpTransceiverDirection::kSendRecv, kActive,
3020 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003021 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003022 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3023 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003024
3025 // Use a single real codec, and then add RTX for it.
3026 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003027 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003028 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
3029 f1_.set_video_codecs(f1_codecs);
3030
3031 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3032 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003033 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003034 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003035 MediaContentDescription* media_desc =
3036 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3037 ASSERT_TRUE(media_desc);
3038 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003039 const StreamParamsVec& streams = desc->streams();
3040 // Single stream.
3041 ASSERT_EQ(1u, streams.size());
3042 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3043 EXPECT_EQ(6u, streams[0].ssrcs.size());
3044 // And should have a SIM group for the simulcast.
3045 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3046 // And a FID group for RTX.
3047 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003048 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003049 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3050 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003051 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003052 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3053 EXPECT_EQ(3u, fid_ssrcs.size());
3054}
3055
brandtr03d5fb12016-11-22 03:37:59 -08003056// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3057// together with a FEC-FR grouping.
3058TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3059 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003060 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3061 RtpTransceiverDirection::kSendRecv, kActive,
3062 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003063 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003064 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3065 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003066
3067 // Use a single real codec, and then add FlexFEC for it.
3068 std::vector<VideoCodec> f1_codecs;
3069 f1_codecs.push_back(VideoCodec(97, "H264"));
3070 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3071 f1_.set_video_codecs(f1_codecs);
3072
3073 // Ensure that the offer has a single FlexFEC ssrc and that
3074 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003075 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003076 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003077 MediaContentDescription* media_desc =
3078 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3079 ASSERT_TRUE(media_desc);
3080 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003081 const StreamParamsVec& streams = desc->streams();
3082 // Single stream.
3083 ASSERT_EQ(1u, streams.size());
3084 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3085 EXPECT_EQ(2u, streams[0].ssrcs.size());
3086 // And should have a FEC-FR group for FlexFEC.
3087 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3088 std::vector<uint32_t> primary_ssrcs;
3089 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3090 ASSERT_EQ(1u, primary_ssrcs.size());
3091 uint32_t flexfec_ssrc;
3092 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3093 EXPECT_NE(flexfec_ssrc, 0u);
3094}
3095
3096// Test that FlexFEC is disabled for simulcast.
3097// TODO(brandtr): Remove this test when we support simulcast, either through
3098// multiple FlexfecSenders, or through multistream protection.
3099TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3100 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003101 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3102 RtpTransceiverDirection::kSendRecv, kActive,
3103 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003104 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003105 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3106 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003107
3108 // Use a single real codec, and then add FlexFEC for it.
3109 std::vector<VideoCodec> f1_codecs;
3110 f1_codecs.push_back(VideoCodec(97, "H264"));
3111 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3112 f1_.set_video_codecs(f1_codecs);
3113
3114 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3115 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003116 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003117 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003118 MediaContentDescription* media_desc =
3119 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3120 ASSERT_TRUE(media_desc);
3121 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003122 const StreamParamsVec& streams = desc->streams();
3123 // Single stream.
3124 ASSERT_EQ(1u, streams.size());
3125 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3126 EXPECT_EQ(3u, streams[0].ssrcs.size());
3127 // And should have a SIM group for the simulcast.
3128 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3129 // And not a FEC-FR group for FlexFEC.
3130 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3131 std::vector<uint32_t> primary_ssrcs;
3132 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3133 EXPECT_EQ(3u, primary_ssrcs.size());
3134 for (uint32_t primary_ssrc : primary_ssrcs) {
3135 uint32_t flexfec_ssrc;
3136 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3137 }
3138}
3139
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003140// Create an updated offer after creating an answer to the original offer and
3141// verify that the RTP header extensions that were part of the original answer
3142// are not changed in the updated offer.
3143TEST_F(MediaSessionDescriptionFactoryTest,
3144 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3145 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003146 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003147
3148 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3149 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3150 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3151 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3152
Steve Anton6fe1fba2018-12-11 10:15:23 -08003153 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3154 std::unique_ptr<SessionDescription> answer =
3155 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003156
Yves Gerey665174f2018-06-19 15:03:05 +02003157 EXPECT_EQ(
3158 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3159 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3160 EXPECT_EQ(
3161 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3162 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003163
kwiberg31022942016-03-11 14:18:21 -08003164 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003165 f2_.CreateOffer(opts, answer.get()));
3166
3167 // The expected RTP header extensions in the new offer are the resulting
3168 // extensions from the first offer/answer exchange plus the extensions only
3169 // |f2_| offer.
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, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003172 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3173 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3174 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003175 };
3176
3177 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003178 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003179 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3180 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3181 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003182 };
3183
3184 const AudioContentDescription* updated_acd =
3185 GetFirstAudioContentDescription(updated_offer.get());
3186 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3187 updated_acd->rtp_header_extensions());
3188
3189 const VideoContentDescription* updated_vcd =
3190 GetFirstVideoContentDescription(updated_offer.get());
3191 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3192 updated_vcd->rtp_header_extensions());
3193}
3194
deadbeefa5b273a2015-08-20 17:30:13 -07003195// Verify that if the same RTP extension URI is used for audio and video, the
3196// same ID is used. Also verify that the ID isn't changed when creating an
3197// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003198TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003199 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003200 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003201
3202 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3203 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3204
Steve Anton6fe1fba2018-12-11 10:15:23 -08003205 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003206
3207 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3208 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003209 const RtpExtension kExpectedVideoRtpExtension[] = {
3210 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003211 };
3212
Yves Gerey665174f2018-06-19 15:03:05 +02003213 EXPECT_EQ(
3214 MAKE_VECTOR(kAudioRtpExtension3),
3215 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3216 EXPECT_EQ(
3217 MAKE_VECTOR(kExpectedVideoRtpExtension),
3218 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003219
3220 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003221 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003222 f1_.CreateOffer(opts, offer.get()));
3223
3224 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003225 GetFirstAudioContentDescription(updated_offer.get())
3226 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003227 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003228 GetFirstVideoContentDescription(updated_offer.get())
3229 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003230}
3231
jbauch5869f502017-06-29 12:31:36 -07003232// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3233TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3234 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003235 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003236
3237 f1_.set_enable_encrypted_rtp_header_extensions(true);
3238 f2_.set_enable_encrypted_rtp_header_extensions(true);
3239
3240 f1_.set_audio_rtp_header_extensions(
3241 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3242 f1_.set_video_rtp_header_extensions(
3243 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3244
Steve Anton6fe1fba2018-12-11 10:15:23 -08003245 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003246
3247 // The extensions that are shared between audio and video should use the same
3248 // id.
3249 const RtpExtension kExpectedVideoRtpExtension[] = {
3250 kVideoRtpExtension3ForEncryption[0],
3251 kAudioRtpExtension3ForEncryptionOffer[1],
3252 kAudioRtpExtension3ForEncryptionOffer[2],
3253 };
3254
Yves Gerey665174f2018-06-19 15:03:05 +02003255 EXPECT_EQ(
3256 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3257 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3258 EXPECT_EQ(
3259 MAKE_VECTOR(kExpectedVideoRtpExtension),
3260 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003261
3262 // Nothing should change when creating a new offer
3263 std::unique_ptr<SessionDescription> updated_offer(
3264 f1_.CreateOffer(opts, offer.get()));
3265
3266 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003267 GetFirstAudioContentDescription(updated_offer.get())
3268 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003269 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003270 GetFirstVideoContentDescription(updated_offer.get())
3271 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003272}
3273
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003274TEST(MediaSessionDescription, CopySessionDescription) {
3275 SessionDescription source;
3276 cricket::ContentGroup group(cricket::CN_AUDIO);
3277 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003278 std::unique_ptr<AudioContentDescription> acd =
3279 absl::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003280 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3281 acd->AddLegacyStream(1);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003282 std::unique_ptr<AudioContentDescription> acd_passed =
3283 absl::WrapUnique(acd->Copy());
3284 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp,
3285 std::move(acd_passed));
3286 std::unique_ptr<VideoContentDescription> vcd =
3287 absl::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003288 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3289 vcd->AddLegacyStream(2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003290 std::unique_ptr<VideoContentDescription> vcd_passed =
3291 absl::WrapUnique(vcd->Copy());
3292 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp,
3293 std::move(vcd_passed));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003294
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003295 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003296 ASSERT_TRUE(copy.get() != NULL);
3297 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3298 const ContentInfo* ac = copy->GetContentByName("audio");
3299 const ContentInfo* vc = copy->GetContentByName("video");
3300 ASSERT_TRUE(ac != NULL);
3301 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003302 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003303 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003304 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3305 EXPECT_EQ(1u, acd->first_ssrc());
3306
Steve Anton5adfafd2017-12-20 16:34:00 -08003307 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003308 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003309 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3310 EXPECT_EQ(2u, vcd->first_ssrc());
3311}
3312
3313// The below TestTransportInfoXXX tests create different offers/answers, and
3314// ensure the TransportInfo in the SessionDescription matches what we expect.
3315TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3316 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003317 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3318 RtpTransceiverDirection::kRecvOnly, kActive,
3319 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003320 TestTransportInfo(true, options, false);
3321}
3322
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003323TEST_F(MediaSessionDescriptionFactoryTest,
3324 TestTransportInfoOfferIceRenomination) {
3325 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003326 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3327 RtpTransceiverDirection::kRecvOnly, kActive,
3328 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003329 options.media_description_options[0]
3330 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003331 TestTransportInfo(true, options, false);
3332}
3333
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003334TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3335 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003336 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3337 RtpTransceiverDirection::kRecvOnly, kActive,
3338 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003339 TestTransportInfo(true, options, true);
3340}
3341
3342TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3343 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003344 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3345 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3346 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003347 TestTransportInfo(true, options, false);
3348}
3349
3350TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003351 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003352 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003353 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3354 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3355 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003356 TestTransportInfo(true, options, true);
3357}
3358
3359TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3360 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003361 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3362 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3363 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003364 options.bundle_enabled = true;
3365 TestTransportInfo(true, options, false);
3366}
3367
3368TEST_F(MediaSessionDescriptionFactoryTest,
3369 TestTransportInfoOfferBundleCurrent) {
3370 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003371 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3372 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3373 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003374 options.bundle_enabled = true;
3375 TestTransportInfo(true, options, true);
3376}
3377
3378TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3379 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003380 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3381 RtpTransceiverDirection::kRecvOnly, kActive,
3382 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003383 TestTransportInfo(false, options, false);
3384}
3385
3386TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003387 TestTransportInfoAnswerIceRenomination) {
3388 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003389 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3390 RtpTransceiverDirection::kRecvOnly, kActive,
3391 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003392 options.media_description_options[0]
3393 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003394 TestTransportInfo(false, options, false);
3395}
3396
3397TEST_F(MediaSessionDescriptionFactoryTest,
3398 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003399 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003400 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3401 RtpTransceiverDirection::kRecvOnly, kActive,
3402 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003403 TestTransportInfo(false, options, true);
3404}
3405
3406TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3407 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003408 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3409 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3410 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003411 TestTransportInfo(false, options, false);
3412}
3413
3414TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003415 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003416 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003417 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3418 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3419 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003420 TestTransportInfo(false, options, true);
3421}
3422
3423TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3424 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003425 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3426 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3427 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003428 options.bundle_enabled = true;
3429 TestTransportInfo(false, options, false);
3430}
3431
3432TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003433 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003434 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003435 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3436 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3437 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003438 options.bundle_enabled = true;
3439 TestTransportInfo(false, options, true);
3440}
3441
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003442TEST_F(MediaSessionDescriptionFactoryTest,
3443 TestTransportInfoOfferBundlesTransportOptions) {
3444 MediaSessionOptions options;
3445 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3446
3447 cricket::OpaqueTransportParameters audio_params;
3448 audio_params.protocol = "audio-transport";
3449 audio_params.parameters = "audio-params";
3450 FindFirstMediaDescriptionByMid("audio", &options)
3451 ->transport_options.opaque_parameters = audio_params;
3452
3453 cricket::OpaqueTransportParameters video_params;
3454 video_params.protocol = "video-transport";
3455 video_params.parameters = "video-params";
3456 FindFirstMediaDescriptionByMid("video", &options)
3457 ->transport_options.opaque_parameters = video_params;
3458
3459 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3460}
3461
3462TEST_F(MediaSessionDescriptionFactoryTest,
3463 TestTransportInfoAnswerBundlesTransportOptions) {
3464 MediaSessionOptions options;
3465 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3466
3467 cricket::OpaqueTransportParameters audio_params;
3468 audio_params.protocol = "audio-transport";
3469 audio_params.parameters = "audio-params";
3470 FindFirstMediaDescriptionByMid("audio", &options)
3471 ->transport_options.opaque_parameters = audio_params;
3472
3473 cricket::OpaqueTransportParameters video_params;
3474 video_params.protocol = "video-transport";
3475 video_params.parameters = "video-params";
3476 FindFirstMediaDescriptionByMid("video", &options)
3477 ->transport_options.opaque_parameters = video_params;
3478
3479 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3480}
3481
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003482// Create an offer with bundle enabled and verify the crypto parameters are
3483// the common set of the available cryptos.
3484TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3485 TestCryptoWithBundle(true);
3486}
3487
3488// Create an answer with bundle enabled and verify the crypto parameters are
3489// the common set of the available cryptos.
3490TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3491 TestCryptoWithBundle(false);
3492}
3493
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003494// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3495// DTLS is not enabled locally.
3496TEST_F(MediaSessionDescriptionFactoryTest,
3497 TestOfferDtlsSavpfWithoutDtlsFailed) {
3498 f1_.set_secure(SEC_ENABLED);
3499 f2_.set_secure(SEC_ENABLED);
3500 tdf1_.set_secure(SEC_DISABLED);
3501 tdf2_.set_secure(SEC_DISABLED);
3502
Steve Anton6fe1fba2018-12-11 10:15:23 -08003503 std::unique_ptr<SessionDescription> offer =
3504 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003505 ASSERT_TRUE(offer.get() != NULL);
3506 ContentInfo* offer_content = offer->GetContentByName("audio");
3507 ASSERT_TRUE(offer_content != NULL);
3508 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003509 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003510 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3511
Steve Anton6fe1fba2018-12-11 10:15:23 -08003512 std::unique_ptr<SessionDescription> answer =
3513 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003514 ASSERT_TRUE(answer != NULL);
3515 ContentInfo* answer_content = answer->GetContentByName("audio");
3516 ASSERT_TRUE(answer_content != NULL);
3517
3518 ASSERT_TRUE(answer_content->rejected);
3519}
3520
3521// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3522// UDP/TLS/RTP/SAVPF.
3523TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3524 f1_.set_secure(SEC_ENABLED);
3525 f2_.set_secure(SEC_ENABLED);
3526 tdf1_.set_secure(SEC_ENABLED);
3527 tdf2_.set_secure(SEC_ENABLED);
3528
Steve Anton6fe1fba2018-12-11 10:15:23 -08003529 std::unique_ptr<SessionDescription> offer =
3530 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003531 ASSERT_TRUE(offer.get() != NULL);
3532 ContentInfo* offer_content = offer->GetContentByName("audio");
3533 ASSERT_TRUE(offer_content != NULL);
3534 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003535 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003536 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3537
Steve Anton6fe1fba2018-12-11 10:15:23 -08003538 std::unique_ptr<SessionDescription> answer =
3539 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003540 ASSERT_TRUE(answer != NULL);
3541
3542 const ContentInfo* answer_content = answer->GetContentByName("audio");
3543 ASSERT_TRUE(answer_content != NULL);
3544 ASSERT_FALSE(answer_content->rejected);
3545
3546 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003547 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003548 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003549}
3550
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003551// Test that we include both SDES and DTLS in the offer, but only include SDES
3552// in the answer if DTLS isn't negotiated.
3553TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3554 f1_.set_secure(SEC_ENABLED);
3555 f2_.set_secure(SEC_ENABLED);
3556 tdf1_.set_secure(SEC_ENABLED);
3557 tdf2_.set_secure(SEC_DISABLED);
3558 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003559 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003560 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003561 const cricket::MediaContentDescription* audio_media_desc;
3562 const cricket::MediaContentDescription* video_media_desc;
3563 const cricket::TransportDescription* audio_trans_desc;
3564 const cricket::TransportDescription* video_trans_desc;
3565
3566 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003567 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003568 ASSERT_TRUE(offer.get() != NULL);
3569
Steve Antonb1c1de12017-12-21 15:14:30 -08003570 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003571 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003572 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003573 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003574 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003575 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3576
3577 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3578 ASSERT_TRUE(audio_trans_desc != NULL);
3579 video_trans_desc = offer->GetTransportDescriptionByName("video");
3580 ASSERT_TRUE(video_trans_desc != NULL);
3581 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3582 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3583
3584 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003585 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003586 ASSERT_TRUE(answer.get() != NULL);
3587
Steve Antonb1c1de12017-12-21 15:14:30 -08003588 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003589 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003590 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003591 ASSERT_TRUE(video_media_desc != NULL);
3592 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3593 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3594
3595 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3596 ASSERT_TRUE(audio_trans_desc != NULL);
3597 video_trans_desc = answer->GetTransportDescriptionByName("video");
3598 ASSERT_TRUE(video_trans_desc != NULL);
3599 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3600 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3601
3602 // Enable DTLS; the answer should now only have DTLS support.
3603 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003604 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003605 ASSERT_TRUE(answer.get() != NULL);
3606
Steve Antonb1c1de12017-12-21 15:14:30 -08003607 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003608 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003609 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003610 ASSERT_TRUE(video_media_desc != NULL);
3611 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3612 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003613 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3614 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003615
3616 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3617 ASSERT_TRUE(audio_trans_desc != NULL);
3618 video_trans_desc = answer->GetTransportDescriptionByName("video");
3619 ASSERT_TRUE(video_trans_desc != NULL);
3620 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3621 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003622
3623 // Try creating offer again. DTLS enabled now, crypto's should be empty
3624 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003625 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003626 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003627 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003628 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003629 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003630 ASSERT_TRUE(video_media_desc != NULL);
3631 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3632 EXPECT_TRUE(video_media_desc->cryptos().empty());
3633
3634 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3635 ASSERT_TRUE(audio_trans_desc != NULL);
3636 video_trans_desc = offer->GetTransportDescriptionByName("video");
3637 ASSERT_TRUE(video_trans_desc != NULL);
3638 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3639 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003640}
3641
3642// Test that an answer can't be created if cryptos are required but the offer is
3643// unsecure.
3644TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003645 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003646 f1_.set_secure(SEC_DISABLED);
3647 tdf1_.set_secure(SEC_DISABLED);
3648 f2_.set_secure(SEC_REQUIRED);
3649 tdf1_.set_secure(SEC_ENABLED);
3650
Steve Anton6fe1fba2018-12-11 10:15:23 -08003651 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003652 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003653 std::unique_ptr<SessionDescription> answer =
3654 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003655 EXPECT_TRUE(answer.get() == NULL);
3656}
3657
3658// Test that we accept a DTLS offer without SDES and create an appropriate
3659// answer.
3660TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3661 f1_.set_secure(SEC_DISABLED);
3662 f2_.set_secure(SEC_ENABLED);
3663 tdf1_.set_secure(SEC_ENABLED);
3664 tdf2_.set_secure(SEC_ENABLED);
3665 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003666 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3667 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3668 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003669
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003670 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003671 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003672 ASSERT_TRUE(offer.get() != NULL);
3673
3674 const AudioContentDescription* audio_offer =
3675 GetFirstAudioContentDescription(offer.get());
3676 ASSERT_TRUE(audio_offer->cryptos().empty());
3677 const VideoContentDescription* video_offer =
3678 GetFirstVideoContentDescription(offer.get());
3679 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003680 const RtpDataContentDescription* data_offer =
3681 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003682 ASSERT_TRUE(data_offer->cryptos().empty());
3683
3684 const cricket::TransportDescription* audio_offer_trans_desc =
3685 offer->GetTransportDescriptionByName("audio");
3686 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3687 const cricket::TransportDescription* video_offer_trans_desc =
3688 offer->GetTransportDescriptionByName("video");
3689 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3690 const cricket::TransportDescription* data_offer_trans_desc =
3691 offer->GetTransportDescriptionByName("data");
3692 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3693
3694 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003695 std::unique_ptr<SessionDescription> answer =
3696 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003697 ASSERT_TRUE(answer.get() != NULL);
3698
3699 const cricket::TransportDescription* audio_answer_trans_desc =
3700 answer->GetTransportDescriptionByName("audio");
3701 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3702 const cricket::TransportDescription* video_answer_trans_desc =
3703 answer->GetTransportDescriptionByName("video");
3704 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3705 const cricket::TransportDescription* data_answer_trans_desc =
3706 answer->GetTransportDescriptionByName("data");
3707 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3708}
3709
3710// Verifies if vad_enabled option is set to false, CN codecs are not present in
3711// offer or answer.
3712TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3713 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003714 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003715 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003716 ASSERT_TRUE(offer.get() != NULL);
3717 const ContentInfo* audio_content = offer->GetContentByName("audio");
3718 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3719
3720 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003721 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003722 ASSERT_TRUE(offer.get() != NULL);
3723 audio_content = offer->GetContentByName("audio");
3724 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003725 std::unique_ptr<SessionDescription> answer =
3726 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003727 ASSERT_TRUE(answer.get() != NULL);
3728 audio_content = answer->GetContentByName("audio");
3729 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3730}
deadbeef44f08192015-12-15 16:20:09 -08003731
zhihuang1c378ed2017-08-17 14:10:50 -07003732// Test that the generated MIDs match the existing offer.
3733TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003734 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003735 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3736 RtpTransceiverDirection::kRecvOnly, kActive,
3737 &opts);
3738 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3739 RtpTransceiverDirection::kRecvOnly, kActive,
3740 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003741 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003742 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3743 RtpTransceiverDirection::kSendRecv, kActive,
3744 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003745 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003746 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003747 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003748 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003749
deadbeef44f08192015-12-15 16:20:09 -08003750 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3751 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3752 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3753 ASSERT_TRUE(audio_content != nullptr);
3754 ASSERT_TRUE(video_content != nullptr);
3755 ASSERT_TRUE(data_content != nullptr);
3756 EXPECT_EQ("audio_modified", audio_content->name);
3757 EXPECT_EQ("video_modified", video_content->name);
3758 EXPECT_EQ("data_modified", data_content->name);
3759}
zhihuangcf5b37c2016-05-05 11:44:35 -07003760
zhihuang1c378ed2017-08-17 14:10:50 -07003761// The following tests verify that the unified plan SDP is supported.
3762// Test that we can create an offer with multiple media sections of same media
3763// type.
3764TEST_F(MediaSessionDescriptionFactoryTest,
3765 CreateOfferWithMultipleAVMediaSections) {
3766 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003767 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3768 RtpTransceiverDirection::kSendRecv, kActive,
3769 &opts);
3770 AttachSenderToMediaDescriptionOptions(
3771 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003772
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003773 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3774 RtpTransceiverDirection::kSendRecv, kActive,
3775 &opts);
3776 AttachSenderToMediaDescriptionOptions(
3777 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003778
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003779 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3780 RtpTransceiverDirection::kSendRecv, kActive,
3781 &opts);
3782 AttachSenderToMediaDescriptionOptions(
3783 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003784
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003785 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3786 RtpTransceiverDirection::kSendRecv, kActive,
3787 &opts);
3788 AttachSenderToMediaDescriptionOptions(
3789 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003790 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003791 ASSERT_TRUE(offer);
3792
3793 ASSERT_EQ(4u, offer->contents().size());
3794 EXPECT_FALSE(offer->contents()[0].rejected);
3795 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003796 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003797 ASSERT_EQ(1u, acd->streams().size());
3798 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003799 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003800
3801 EXPECT_FALSE(offer->contents()[1].rejected);
3802 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003803 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003804 ASSERT_EQ(1u, vcd->streams().size());
3805 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003806 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003807
3808 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003809 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003810 ASSERT_EQ(1u, acd->streams().size());
3811 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003812 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003813
3814 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003815 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003816 ASSERT_EQ(1u, vcd->streams().size());
3817 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003818 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003819}
3820
3821// Test that we can create an answer with multiple media sections of same media
3822// type.
3823TEST_F(MediaSessionDescriptionFactoryTest,
3824 CreateAnswerWithMultipleAVMediaSections) {
3825 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003826 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3827 RtpTransceiverDirection::kSendRecv, kActive,
3828 &opts);
3829 AttachSenderToMediaDescriptionOptions(
3830 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003831
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003832 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3833 RtpTransceiverDirection::kSendRecv, kActive,
3834 &opts);
3835 AttachSenderToMediaDescriptionOptions(
3836 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003837
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003838 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3839 RtpTransceiverDirection::kSendRecv, kActive,
3840 &opts);
3841 AttachSenderToMediaDescriptionOptions(
3842 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003843
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003844 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3845 RtpTransceiverDirection::kSendRecv, kActive,
3846 &opts);
3847 AttachSenderToMediaDescriptionOptions(
3848 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003849
Steve Anton6fe1fba2018-12-11 10:15:23 -08003850 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003851 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003852 std::unique_ptr<SessionDescription> answer =
3853 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003854
3855 ASSERT_EQ(4u, answer->contents().size());
3856 EXPECT_FALSE(answer->contents()[0].rejected);
3857 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003858 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003859 ASSERT_EQ(1u, acd->streams().size());
3860 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003861 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003862
3863 EXPECT_FALSE(answer->contents()[1].rejected);
3864 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003865 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003866 ASSERT_EQ(1u, vcd->streams().size());
3867 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003868 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003869
3870 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003871 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003872 ASSERT_EQ(1u, acd->streams().size());
3873 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003874 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003875
3876 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003877 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003878 ASSERT_EQ(1u, vcd->streams().size());
3879 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003880 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003881}
3882
3883// Test that the media section will be rejected in offer if the corresponding
3884// MediaDescriptionOptions is stopped by the offerer.
3885TEST_F(MediaSessionDescriptionFactoryTest,
3886 CreateOfferWithMediaSectionStoppedByOfferer) {
3887 // Create an offer with two audio sections and one of them is stopped.
3888 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003889 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3890 RtpTransceiverDirection::kSendRecv, kActive,
3891 &offer_opts);
3892 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3893 RtpTransceiverDirection::kInactive, kStopped,
3894 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003895 std::unique_ptr<SessionDescription> offer =
3896 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003897 ASSERT_TRUE(offer);
3898 ASSERT_EQ(2u, offer->contents().size());
3899 EXPECT_FALSE(offer->contents()[0].rejected);
3900 EXPECT_TRUE(offer->contents()[1].rejected);
3901}
3902
3903// Test that the media section will be rejected in answer if the corresponding
3904// MediaDescriptionOptions is stopped by the offerer.
3905TEST_F(MediaSessionDescriptionFactoryTest,
3906 CreateAnswerWithMediaSectionStoppedByOfferer) {
3907 // Create an offer with two audio sections and one of them is stopped.
3908 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003909 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3910 RtpTransceiverDirection::kSendRecv, kActive,
3911 &offer_opts);
3912 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3913 RtpTransceiverDirection::kInactive, kStopped,
3914 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003915 std::unique_ptr<SessionDescription> offer =
3916 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003917 ASSERT_TRUE(offer);
3918 ASSERT_EQ(2u, offer->contents().size());
3919 EXPECT_FALSE(offer->contents()[0].rejected);
3920 EXPECT_TRUE(offer->contents()[1].rejected);
3921
3922 // Create an answer based on the offer.
3923 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003924 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3925 RtpTransceiverDirection::kSendRecv, kActive,
3926 &answer_opts);
3927 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3928 RtpTransceiverDirection::kSendRecv, kActive,
3929 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003930 std::unique_ptr<SessionDescription> answer =
3931 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003932 ASSERT_EQ(2u, answer->contents().size());
3933 EXPECT_FALSE(answer->contents()[0].rejected);
3934 EXPECT_TRUE(answer->contents()[1].rejected);
3935}
3936
3937// Test that the media section will be rejected in answer if the corresponding
3938// MediaDescriptionOptions is stopped by the answerer.
3939TEST_F(MediaSessionDescriptionFactoryTest,
3940 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3941 // Create an offer with two audio sections.
3942 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003943 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3944 RtpTransceiverDirection::kSendRecv, kActive,
3945 &offer_opts);
3946 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3947 RtpTransceiverDirection::kSendRecv, kActive,
3948 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003949 std::unique_ptr<SessionDescription> offer =
3950 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003951 ASSERT_TRUE(offer);
3952 ASSERT_EQ(2u, offer->contents().size());
3953 ASSERT_FALSE(offer->contents()[0].rejected);
3954 ASSERT_FALSE(offer->contents()[1].rejected);
3955
3956 // The answerer rejects one of the audio sections.
3957 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003958 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3959 RtpTransceiverDirection::kSendRecv, kActive,
3960 &answer_opts);
3961 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3962 RtpTransceiverDirection::kInactive, kStopped,
3963 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003964 std::unique_ptr<SessionDescription> answer =
3965 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003966 ASSERT_EQ(2u, answer->contents().size());
3967 EXPECT_FALSE(answer->contents()[0].rejected);
3968 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003969
3970 // The TransportInfo of the rejected m= section is expected to be added in the
3971 // answer.
3972 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003973}
3974
3975// Test the generated media sections has the same order of the
3976// corresponding MediaDescriptionOptions.
3977TEST_F(MediaSessionDescriptionFactoryTest,
3978 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3979 MediaSessionOptions opts;
3980 // This tests put video section first because normally audio comes first by
3981 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003982 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3983 RtpTransceiverDirection::kSendRecv, kActive,
3984 &opts);
3985 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3986 RtpTransceiverDirection::kSendRecv, kActive,
3987 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003988 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003989
3990 ASSERT_TRUE(offer);
3991 ASSERT_EQ(2u, offer->contents().size());
3992 EXPECT_EQ("video", offer->contents()[0].name);
3993 EXPECT_EQ("audio", offer->contents()[1].name);
3994}
3995
3996// Test that different media sections using the same codec have same payload
3997// type.
3998TEST_F(MediaSessionDescriptionFactoryTest,
3999 PayloadTypesSharedByMediaSectionsOfSameType) {
4000 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004001 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4002 RtpTransceiverDirection::kSendRecv, kActive,
4003 &opts);
4004 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4005 RtpTransceiverDirection::kSendRecv, kActive,
4006 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004007 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004008 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004009 ASSERT_TRUE(offer);
4010 ASSERT_EQ(2u, offer->contents().size());
4011 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004012 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004013 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004014 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004015 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4016 ASSERT_EQ(2u, vcd1->codecs().size());
4017 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4018 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4019 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4020 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4021
4022 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004023 std::unique_ptr<SessionDescription> answer =
4024 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004025 ASSERT_TRUE(answer);
4026 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004027 vcd1 = answer->contents()[0].media_description()->as_video();
4028 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004029 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4030 ASSERT_EQ(1u, vcd1->codecs().size());
4031 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4032 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4033}
4034
4035// Test that the codec preference order per media section is respected in
4036// subsequent offer.
4037TEST_F(MediaSessionDescriptionFactoryTest,
4038 CreateOfferRespectsCodecPreferenceOrder) {
4039 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004040 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4041 RtpTransceiverDirection::kSendRecv, kActive,
4042 &opts);
4043 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4044 RtpTransceiverDirection::kSendRecv, kActive,
4045 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004046 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004047 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004048 ASSERT_TRUE(offer);
4049 ASSERT_EQ(2u, offer->contents().size());
4050 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004051 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004052 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004053 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004054 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4055 EXPECT_EQ(video_codecs, vcd1->codecs());
4056 EXPECT_EQ(video_codecs, vcd2->codecs());
4057
4058 // Change the codec preference of the first video section and create a
4059 // follow-up offer.
4060 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4061 vcd1->set_codecs(video_codecs_reverse);
4062 std::unique_ptr<SessionDescription> updated_offer(
4063 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004064 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4065 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004066 // The video codec preference order should be respected.
4067 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4068 EXPECT_EQ(video_codecs, vcd2->codecs());
4069}
4070
4071// Test that the codec preference order per media section is respected in
4072// the answer.
4073TEST_F(MediaSessionDescriptionFactoryTest,
4074 CreateAnswerRespectsCodecPreferenceOrder) {
4075 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004076 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4077 RtpTransceiverDirection::kSendRecv, kActive,
4078 &opts);
4079 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4080 RtpTransceiverDirection::kSendRecv, kActive,
4081 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004082 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004083 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004084 ASSERT_TRUE(offer);
4085 ASSERT_EQ(2u, offer->contents().size());
4086 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004087 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004088 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004089 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004090 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4091 EXPECT_EQ(video_codecs, vcd1->codecs());
4092 EXPECT_EQ(video_codecs, vcd2->codecs());
4093
4094 // Change the codec preference of the first video section and create an
4095 // answer.
4096 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4097 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004098 std::unique_ptr<SessionDescription> answer =
4099 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004100 vcd1 = answer->contents()[0].media_description()->as_video();
4101 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004102 // The video codec preference order should be respected.
4103 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4104 EXPECT_EQ(video_codecs, vcd2->codecs());
4105}
4106
Zhi Huang6f367472017-11-22 13:20:02 -08004107// Test that when creating an answer, the codecs use local parameters instead of
4108// the remote ones.
4109TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4110 const std::string audio_param_name = "audio_param";
4111 const std::string audio_value1 = "audio_v1";
4112 const std::string audio_value2 = "audio_v2";
4113 const std::string video_param_name = "video_param";
4114 const std::string video_value1 = "video_v1";
4115 const std::string video_value2 = "video_v2";
4116
4117 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4118 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4119 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4120 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4121
4122 // Set the parameters for codecs.
4123 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4124 video_codecs1[0].SetParam(video_param_name, video_value1);
4125 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4126 video_codecs2[0].SetParam(video_param_name, video_value2);
4127
4128 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
4129 f1_.set_video_codecs(video_codecs1);
4130 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
4131 f2_.set_video_codecs(video_codecs2);
4132
4133 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004134 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4135 RtpTransceiverDirection::kSendRecv, kActive,
4136 &opts);
4137 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4138 RtpTransceiverDirection::kSendRecv, kActive,
4139 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004140
Steve Anton6fe1fba2018-12-11 10:15:23 -08004141 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004142 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004143 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4144 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004145 std::string value;
4146 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4147 EXPECT_EQ(audio_value1, value);
4148 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4149 EXPECT_EQ(video_value1, value);
4150
Steve Anton6fe1fba2018-12-11 10:15:23 -08004151 std::unique_ptr<SessionDescription> answer =
4152 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004153 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004154 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4155 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004156 // Use the parameters from the local codecs.
4157 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4158 EXPECT_EQ(audio_value2, value);
4159 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4160 EXPECT_EQ(video_value2, value);
4161}
4162
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004163// Test that matching packetization-mode is part of the criteria for matching
4164// H264 codecs (in addition to profile-level-id). Previously, this was not the
4165// case, so the first H264 codec with the same profile-level-id would match and
4166// the payload type in the answer would be incorrect.
4167// This is a regression test for bugs.webrtc.org/8808
4168TEST_F(MediaSessionDescriptionFactoryTest,
4169 H264MatchCriteriaIncludesPacketizationMode) {
4170 // Create two H264 codecs with the same profile level ID and different
4171 // packetization modes.
4172 VideoCodec h264_pm0(96, "H264");
4173 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4174 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4175 VideoCodec h264_pm1(97, "H264");
4176 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4177 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4178
4179 // Offerer will send both codecs, answerer should choose the one with matching
4180 // packetization mode (and not the first one it sees).
4181 f1_.set_video_codecs({h264_pm0, h264_pm1});
4182 f2_.set_video_codecs({h264_pm1});
4183
4184 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004185 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4186 RtpTransceiverDirection::kSendRecv, kActive,
4187 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004188
Steve Anton6fe1fba2018-12-11 10:15:23 -08004189 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004190 ASSERT_TRUE(offer);
4191
Steve Anton6fe1fba2018-12-11 10:15:23 -08004192 std::unique_ptr<SessionDescription> answer =
4193 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004194 ASSERT_TRUE(answer);
4195
4196 // Answer should have one negotiated codec with packetization-mode=1 using the
4197 // offered payload type.
4198 ASSERT_EQ(1u, answer->contents().size());
4199 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4200 ASSERT_EQ(1u, answer_vcd->codecs().size());
4201 auto answer_codec = answer_vcd->codecs()[0];
4202 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4203}
4204
zhihuangcf5b37c2016-05-05 11:44:35 -07004205class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4206 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004207 MediaProtocolTest()
4208 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004209 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4210 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004211 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004212 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004213 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4214 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004215 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004216 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004217 f1_.set_secure(SEC_ENABLED);
4218 f2_.set_secure(SEC_ENABLED);
4219 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004220 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004221 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004222 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004223 tdf1_.set_secure(SEC_ENABLED);
4224 tdf2_.set_secure(SEC_ENABLED);
4225 }
4226
4227 protected:
4228 MediaSessionDescriptionFactory f1_;
4229 MediaSessionDescriptionFactory f2_;
4230 TransportDescriptionFactory tdf1_;
4231 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004232 UniqueRandomIdGenerator ssrc_generator1;
4233 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004234};
4235
4236TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4237 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004238 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004239 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004240 ASSERT_TRUE(offer.get() != nullptr);
4241 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004242 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004243 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004244 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004245 std::unique_ptr<SessionDescription> answer =
4246 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004247 const ContentInfo* ac = answer->GetContentByName("audio");
4248 const ContentInfo* vc = answer->GetContentByName("video");
4249 ASSERT_TRUE(ac != nullptr);
4250 ASSERT_TRUE(vc != nullptr);
4251 EXPECT_FALSE(ac->rejected); // the offer is accepted
4252 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004253 const AudioContentDescription* acd = ac->media_description()->as_audio();
4254 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004255 EXPECT_EQ(GetParam(), acd->protocol());
4256 EXPECT_EQ(GetParam(), vcd->protocol());
4257}
4258
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004259INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4260 MediaProtocolTest,
4261 ::testing::ValuesIn(kMediaProtocols));
4262INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4263 MediaProtocolTest,
4264 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004265
4266TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4267 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004268 UniqueRandomIdGenerator ssrc_generator;
4269 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004270 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4271 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4272
4273 // The merged list of codecs should contain any send codecs that are also
4274 // nominally in the recieve codecs list. Payload types should be picked from
4275 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4276 // (set to 1). This equals what happens when the send codecs are used in an
4277 // offer and the receive codecs are used in the following answer.
4278 const std::vector<AudioCodec> sendrecv_codecs =
4279 MAKE_VECTOR(kAudioCodecsAnswer);
4280 const std::vector<AudioCodec> no_codecs;
4281
4282 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4283 << "Please don't change shared test data!";
4284 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4285 << "Please don't change shared test data!";
4286 // Alter iLBC send codec to have zero channels, to test that that is handled
4287 // properly.
4288 send_codecs[1].channels = 0;
4289
4290 // Alther iLBC receive codec to be lowercase, to test that case conversions
4291 // are handled properly.
4292 recv_codecs[2].name = "ilbc";
4293
4294 // Test proper merge
4295 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004296 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4297 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4298 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004299
4300 // Test empty send codecs list
4301 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004302 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4303 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4304 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004305
4306 // Test empty recv codecs list
4307 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004308 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4309 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4310 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004311
4312 // Test all empty codec lists
4313 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004314 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4315 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4316 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004317}
4318
Amit Hilbuch77938e62018-12-21 09:23:38 -08004319// Checks that the RID extensions are added to the video RTP header extensions.
4320// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4321// not very well defined, as calling set() and immediately get() will yield
4322// an object that is not semantically equivalent to the set object.
4323TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4324 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004325 UniqueRandomIdGenerator ssrc_generator;
4326 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004327 sf.set_is_unified_plan(true);
4328 cricket::RtpHeaderExtensions extensions;
4329 sf.set_video_rtp_header_extensions(extensions);
4330 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4331 // Check to see that RID extensions were added to the extension list
4332 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004333 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004334 RtpExtension::kMidUri)));
4335 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004336 RtpExtension::kRidUri)));
4337 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4338 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004339}
4340
4341// Checks that the RID extensions are added to the audio RTP header extensions.
4342// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4343// not very well defined, as calling set() and immediately get() will yield
4344// an object that is not semantically equivalent to the set object.
4345TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4346 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004347 UniqueRandomIdGenerator ssrc_generator;
4348 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004349 sf.set_is_unified_plan(true);
4350 cricket::RtpHeaderExtensions extensions;
4351 sf.set_audio_rtp_header_extensions(extensions);
4352 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4353 // Check to see that RID extensions were added to the extension list
4354 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004355 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004356 RtpExtension::kMidUri)));
4357 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004358 RtpExtension::kRidUri)));
4359 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4360 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004361}
4362
ossu075af922016-06-14 03:29:38 -07004363namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004364// Compare the two vectors of codecs ignoring the payload type.
4365template <class Codec>
4366bool CodecsMatch(const std::vector<Codec>& codecs1,
4367 const std::vector<Codec>& codecs2) {
4368 if (codecs1.size() != codecs2.size()) {
4369 return false;
4370 }
4371
4372 for (size_t i = 0; i < codecs1.size(); ++i) {
4373 if (!codecs1[i].Matches(codecs2[i])) {
4374 return false;
4375 }
4376 }
4377 return true;
4378}
4379
Steve Anton4e70a722017-11-28 14:57:10 -08004380void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004381 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004382 UniqueRandomIdGenerator ssrc_generator;
4383 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004384 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4385 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4386 const std::vector<AudioCodec> sendrecv_codecs =
4387 MAKE_VECTOR(kAudioCodecsAnswer);
4388 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004389
4390 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004391 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4392 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004393
Steve Anton4e70a722017-11-28 14:57:10 -08004394 if (direction == RtpTransceiverDirection::kSendRecv ||
4395 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004396 AttachSenderToMediaDescriptionOptions(
4397 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004398 }
ossu075af922016-06-14 03:29:38 -07004399
Steve Anton6fe1fba2018-12-11 10:15:23 -08004400 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004401 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004402 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004403
4404 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004405 // that the codecs put in are right. This happens when we neither want to
4406 // send nor receive audio. The checks are still in place if at some point
4407 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004408 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004409 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004410 // sendrecv and inactive should both present lists as if the channel was
4411 // to be used for sending and receiving. Inactive essentially means it
4412 // might eventually be used anything, but we don't know more at this
4413 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004414 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004415 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004416 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004417 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004418 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004419 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004420 }
4421 }
4422}
4423
4424static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004425 AudioCodec(0, "codec0", 16000, -1, 1),
4426 AudioCodec(1, "codec1", 8000, 13300, 1),
4427 AudioCodec(2, "codec2", 8000, 64000, 1),
4428 AudioCodec(3, "codec3", 8000, 64000, 1),
4429 AudioCodec(4, "codec4", 8000, 0, 2),
4430 AudioCodec(5, "codec5", 32000, 0, 1),
4431 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004432
zhihuang1c378ed2017-08-17 14:10:50 -07004433/* The codecs groups below are chosen as per the matrix below. The objective
4434 * is to have different sets of codecs in the inputs, to get unique sets of
4435 * codecs after negotiation, depending on offer and answer communication
4436 * directions. One-way directions in the offer should either result in the
4437 * opposite direction in the answer, or an inactive answer. Regardless, the
4438 * choice of codecs should be as if the answer contained the opposite
4439 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004440 *
4441 * | Offer | Answer | Result
4442 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4443 * 0 | x - - | - x - | x - - - -
4444 * 1 | x x x | - x - | x - - x -
4445 * 2 | - x - | x - - | - x - - -
4446 * 3 | x x x | x - - | - x x - -
4447 * 4 | - x - | x x x | - x - - -
4448 * 5 | x - - | x x x | x - - - -
4449 * 6 | x x x | x x x | x x x x x
4450 */
4451// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004452static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4453static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004454// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4455// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004456static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4457static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004458// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004459static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4460static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4461static const int kResultSendrecv_SendCodecs[] = {3, 6};
4462static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4463static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004464
4465template <typename T, int IDXS>
4466std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4467 std::vector<T> out;
4468 out.reserve(IDXS);
4469 for (int idx : indices)
4470 out.push_back(array[idx]);
4471
4472 return out;
4473}
4474
Steve Anton4e70a722017-11-28 14:57:10 -08004475void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4476 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004477 bool add_legacy_stream) {
4478 TransportDescriptionFactory offer_tdf;
4479 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004480 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4481 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4482 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004483 offer_factory.set_audio_codecs(
4484 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4485 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4486 answer_factory.set_audio_codecs(
4487 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4488 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4489
ossu075af922016-06-14 03:29:38 -07004490 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004491 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4492 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004493
Steve Anton4e70a722017-11-28 14:57:10 -08004494 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004495 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4496 kAudioTrack1, {kMediaStream1}, 1,
4497 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004498 }
4499
Steve Anton6fe1fba2018-12-11 10:15:23 -08004500 std::unique_ptr<SessionDescription> offer =
4501 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004502 ASSERT_TRUE(offer.get() != NULL);
4503
4504 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004505 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4506 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004507
Steve Anton4e70a722017-11-28 14:57:10 -08004508 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004509 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4510 kAudioTrack1, {kMediaStream1}, 1,
4511 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004512 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004513 std::unique_ptr<SessionDescription> answer =
4514 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004515 const ContentInfo* ac = answer->GetContentByName("audio");
4516
zhihuang1c378ed2017-08-17 14:10:50 -07004517 // If the factory didn't add any audio content to the answer, we cannot
4518 // check that the codecs put in are right. This happens when we neither want
4519 // to send nor receive audio. The checks are still in place if at some point
4520 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004521 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004522 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4523 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004524
ossu075af922016-06-14 03:29:38 -07004525 std::vector<AudioCodec> target_codecs;
4526 // For offers with sendrecv or inactive, we should never reply with more
4527 // codecs than offered, with these codec sets.
4528 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004529 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004530 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4531 kResultSendrecv_SendrecvCodecs);
4532 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004533 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004534 target_codecs =
4535 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004536 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004537 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004538 target_codecs =
4539 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004540 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004541 case RtpTransceiverDirection::kSendRecv:
4542 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004543 target_codecs =
4544 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004545 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004546 target_codecs =
4547 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004548 } else {
4549 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4550 kResultSendrecv_SendrecvCodecs);
4551 }
4552 break;
4553 }
4554
zhihuang1c378ed2017-08-17 14:10:50 -07004555 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004556 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004557 bool first = true;
4558 os << "{";
4559 for (const auto& c : codecs) {
4560 os << (first ? " " : ", ") << c.id;
4561 first = false;
4562 }
4563 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004564 return os.Release();
ossu075af922016-06-14 03:29:38 -07004565 };
4566
4567 EXPECT_TRUE(acd->codecs() == target_codecs)
4568 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004569 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4570 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004571 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004572 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4573 << "; got: "
4574 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004575 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004576 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004577 << "Only inactive offers are allowed to not generate any audio "
4578 "content";
ossu075af922016-06-14 03:29:38 -07004579 }
4580}
brandtr03d5fb12016-11-22 03:37:59 -08004581
4582} // namespace
ossu075af922016-06-14 03:29:38 -07004583
4584class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004585 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004586
4587TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004588 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004589}
4590
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004591INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4592 AudioCodecsOfferTest,
4593 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4594 RtpTransceiverDirection::kRecvOnly,
4595 RtpTransceiverDirection::kSendRecv,
4596 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004597
4598class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004599 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4600 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004601 bool>> {};
ossu075af922016-06-14 03:29:38 -07004602
4603TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004604 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4605 ::testing::get<1>(GetParam()),
4606 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004607}
4608
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004609INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004610 MediaSessionDescriptionFactoryTest,
4611 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004612 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4613 RtpTransceiverDirection::kRecvOnly,
4614 RtpTransceiverDirection::kSendRecv,
4615 RtpTransceiverDirection::kInactive),
4616 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4617 RtpTransceiverDirection::kRecvOnly,
4618 RtpTransceiverDirection::kSendRecv,
4619 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004620 ::testing::Bool()));