blob: 76a33d0745c6084947f99b50300f82cafaa090aa [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));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522
523 } else {
524 EXPECT_TRUE(ti_audio == NULL);
525 }
526 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000527 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000528 EXPECT_TRUE(ti_video != NULL);
529 if (options.bundle_enabled) {
530 EXPECT_EQ(ti_audio->description.ice_ufrag,
531 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200532 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 } else {
534 if (has_current_desc) {
535 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
536 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
537 } else {
538 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
539 ti_video->description.ice_ufrag.size());
540 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
541 ti_video->description.ice_pwd.size());
542 }
543 }
zhihuang1c378ed2017-08-17 14:10:50 -0700544 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700545 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700546 EXPECT_EQ(
547 media_desc_options_it->transport_options.enable_ice_renomination,
548 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 } else {
550 EXPECT_TRUE(ti_video == NULL);
551 }
552 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
553 if (options.has_data()) {
554 EXPECT_TRUE(ti_data != NULL);
555 if (options.bundle_enabled) {
556 EXPECT_EQ(ti_audio->description.ice_ufrag,
557 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200558 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 } else {
560 if (has_current_desc) {
561 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
562 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
563 } else {
564 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
565 ti_data->description.ice_ufrag.size());
566 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
567 ti_data->description.ice_pwd.size());
568 }
569 }
zhihuang1c378ed2017-08-17 14:10:50 -0700570 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700571 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700572 EXPECT_EQ(
573 media_desc_options_it->transport_options.enable_ice_renomination,
574 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700575
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 } else {
577 EXPECT_TRUE(ti_video == NULL);
578 }
579 }
580
581 void TestCryptoWithBundle(bool offer) {
582 f1_.set_secure(SEC_ENABLED);
583 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800584 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
585 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
586 &options);
kwiberg31022942016-03-11 14:18:21 -0800587 std::unique_ptr<SessionDescription> ref_desc;
588 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589 if (offer) {
590 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800591 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800593 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 } else {
595 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800596 ref_desc = f1_.CreateOffer(options, NULL);
597 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800599 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800601 desc->GetContentDescriptionByName("audio");
602 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800604 desc->GetContentDescriptionByName("video");
605 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
607 video_media_desc->cryptos()));
608 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800609 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610 audio_media_desc->cryptos()[0].cipher_suite);
611
612 // Verify the selected crypto is one from the reference audio
613 // media content.
614 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800615 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 bool found = false;
617 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
618 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200619 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 found = true;
621 break;
622 }
623 }
624 EXPECT_TRUE(found);
625 }
626
627 // This test that the audio and video media direction is set to
628 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700629 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800631 RtpTransceiverDirection direction_in_offer,
632 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700633 MediaSessionOptions offer_opts;
634 AddAudioVideoSections(direction_in_offer, &offer_opts);
635
Steve Anton6fe1fba2018-12-11 10:15:23 -0800636 std::unique_ptr<SessionDescription> offer =
637 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700639 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700641 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643
zhihuang1c378ed2017-08-17 14:10:50 -0700644 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800645 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800646 std::unique_ptr<SessionDescription> answer =
647 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000648 const AudioContentDescription* acd_answer =
649 GetFirstAudioContentDescription(answer.get());
650 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
651 const VideoContentDescription* vcd_answer =
652 GetFirstVideoContentDescription(answer.get());
653 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
654 }
655
656 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800657 RTC_DCHECK(content);
658 RTC_CHECK(content->media_description());
659 const cricket::AudioContentDescription* audio_desc =
660 content->media_description()->as_audio();
661 RTC_CHECK(audio_desc);
662 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
663 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800665 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666 }
667 return true;
668 }
669
jbauchcb560652016-08-04 05:20:32 -0700670 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
671 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800672 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700673 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700674
jbauchcb560652016-08-04 05:20:32 -0700675 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800676 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700677 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700678
jbauchcb560652016-08-04 05:20:32 -0700679 f1_.set_secure(SEC_ENABLED);
680 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800681 std::unique_ptr<SessionDescription> offer =
682 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700683 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800684 std::unique_ptr<SessionDescription> answer =
685 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700686 const ContentInfo* ac = answer->GetContentByName("audio");
687 const ContentInfo* vc = answer->GetContentByName("video");
688 ASSERT_TRUE(ac != NULL);
689 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800690 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
691 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800692 const AudioContentDescription* acd = ac->media_description()->as_audio();
693 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700694 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800695 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700696 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700697 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700698 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
699 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700700 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700701 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700702 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700703 }
704 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800705 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200706 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
707 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700708 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700709 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700710 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700711 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700712 }
Steve Antone38a5a12018-11-21 16:05:15 -0800713 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700714 }
715
Johannes Kronce8e8672019-02-22 13:06:44 +0100716 void TestTransportSequenceNumberNegotiation(
717 const cricket::RtpHeaderExtensions& local,
718 const cricket::RtpHeaderExtensions& offered,
719 const cricket::RtpHeaderExtensions& expectedAnswer) {
720 MediaSessionOptions opts;
721 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
722 f1_.set_audio_rtp_header_extensions(offered);
723 f1_.set_video_rtp_header_extensions(offered);
724 f2_.set_audio_rtp_header_extensions(local);
725 f2_.set_video_rtp_header_extensions(local);
726
727 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
728 ASSERT_TRUE(offer.get() != NULL);
729 std::unique_ptr<SessionDescription> answer =
730 f2_.CreateAnswer(offer.get(), opts, NULL);
731
732 EXPECT_EQ(
733 expectedAnswer,
734 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
735 EXPECT_EQ(
736 expectedAnswer,
737 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
738 }
739
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000740 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800741 UniqueRandomIdGenerator ssrc_generator1;
742 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000743 MediaSessionDescriptionFactory f1_;
744 MediaSessionDescriptionFactory f2_;
745 TransportDescriptionFactory tdf1_;
746 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747};
748
749// Create a typical audio offer, and ensure it matches what we expect.
750TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
751 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800752 std::unique_ptr<SessionDescription> offer =
753 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754 ASSERT_TRUE(offer.get() != NULL);
755 const ContentInfo* ac = offer->GetContentByName("audio");
756 const ContentInfo* vc = offer->GetContentByName("video");
757 ASSERT_TRUE(ac != NULL);
758 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800759 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800760 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700762 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700763 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
765 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700766 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800767 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768}
769
770// Create a typical video offer, and ensure it matches what we expect.
771TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
772 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800773 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000776 ASSERT_TRUE(offer.get() != NULL);
777 const ContentInfo* ac = offer->GetContentByName("audio");
778 const ContentInfo* vc = offer->GetContentByName("video");
779 ASSERT_TRUE(ac != NULL);
780 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800781 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
782 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800783 const AudioContentDescription* acd = ac->media_description()->as_audio();
784 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700786 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700787 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000788 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
789 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700790 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800791 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
793 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700794 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
796 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700797 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800798 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799}
800
801// Test creating an offer with bundle where the Codecs have the same dynamic
802// RTP playlod type. The test verifies that the offer don't contain the
803// duplicate RTP payload types.
804TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
805 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700806 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200807 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
809 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
810
811 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800812 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
813 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800815 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816 const VideoContentDescription* vcd =
817 GetFirstVideoContentDescription(offer.get());
818 const AudioContentDescription* acd =
819 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200820 const RtpDataContentDescription* dcd =
821 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822 ASSERT_TRUE(NULL != vcd);
823 ASSERT_TRUE(NULL != acd);
824 ASSERT_TRUE(NULL != dcd);
825 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
826 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
827 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
828 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
829 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
830 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
831}
832
zhihuang1c378ed2017-08-17 14:10:50 -0700833// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834// after an audio only session has been negotiated.
835TEST_F(MediaSessionDescriptionFactoryTest,
836 TestCreateUpdatedVideoOfferWithBundle) {
837 f1_.set_secure(SEC_ENABLED);
838 f2_.set_secure(SEC_ENABLED);
839 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800840 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
841 RtpTransceiverDirection::kRecvOnly, kActive,
842 &opts);
843 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
844 RtpTransceiverDirection::kInactive, kStopped,
845 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 opts.data_channel_type = cricket::DCT_NONE;
847 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800848 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
849 std::unique_ptr<SessionDescription> answer =
850 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851
852 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800853 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
854 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
855 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800857 std::unique_ptr<SessionDescription> updated_offer(
858 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859
860 const AudioContentDescription* acd =
861 GetFirstAudioContentDescription(updated_offer.get());
862 const VideoContentDescription* vcd =
863 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200864 const RtpDataContentDescription* dcd =
865 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 EXPECT_TRUE(NULL != vcd);
867 EXPECT_TRUE(NULL != acd);
868 EXPECT_TRUE(NULL != dcd);
869
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700870 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800871 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700872 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800873 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700874 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800875 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876}
deadbeef44f08192015-12-15 16:20:09 -0800877
wu@webrtc.org78187522013-10-07 23:32:02 +0000878// Create a RTP data offer, and ensure it matches what we expect.
879TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800881 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
882 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800884 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000885 ASSERT_TRUE(offer.get() != NULL);
886 const ContentInfo* ac = offer->GetContentByName("audio");
887 const ContentInfo* dc = offer->GetContentByName("data");
888 ASSERT_TRUE(ac != NULL);
889 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800890 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
891 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800892 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200893 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700895 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700896 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
898 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700899 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800900 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200902 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700903 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200905 dcd->bandwidth()); // default bandwidth (auto)
906 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700907 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800908 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909}
910
wu@webrtc.org78187522013-10-07 23:32:02 +0000911// Create an SCTP data offer with bundle without error.
912TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
913 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000914 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800915 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000916 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800917 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000918 EXPECT_TRUE(offer.get() != NULL);
919 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000920 auto dcd = GetFirstSctpDataContentDescription(offer.get());
921 ASSERT_TRUE(dcd);
922 // Since this transport is insecure, the protocol should be "SCTP".
923 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
924}
925
926// Create an SCTP data offer with bundle without error.
927TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
928 MediaSessionOptions opts;
929 opts.bundle_enabled = true;
930 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
931 f1_.set_secure(SEC_ENABLED);
932 tdf1_.set_secure(SEC_ENABLED);
933 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
934 EXPECT_TRUE(offer.get() != NULL);
935 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
936 auto dcd = GetFirstSctpDataContentDescription(offer.get());
937 ASSERT_TRUE(dcd);
938 // The protocol should now be "UDP/DTLS/SCTP"
939 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000940}
941
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000942// Test creating an sctp data channel from an already generated offer.
943TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
944 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000945 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800946 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000947 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800948 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000949 ASSERT_TRUE(offer1.get() != NULL);
950 const ContentInfo* data = offer1->GetContentByName("data");
951 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800952 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000953
954 // Now set data_channel_type to 'none' (default) and make sure that the
955 // datachannel type that gets generated from the previous offer, is of the
956 // same type.
957 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800958 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000959 f1_.CreateOffer(opts, offer1.get()));
960 data = offer2->GetContentByName("data");
961 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800962 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000963}
964
Steve Anton2bed3972019-01-04 17:04:30 -0800965// Test that if BUNDLE is enabled and all media sections are rejected then the
966// BUNDLE group is not present in the re-offer.
967TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
968 MediaSessionOptions opts;
969 opts.bundle_enabled = true;
970 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
971 RtpTransceiverDirection::kSendRecv, kActive,
972 &opts);
973 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
974
975 opts.media_description_options[0].stopped = true;
976 std::unique_ptr<SessionDescription> reoffer =
977 f1_.CreateOffer(opts, offer.get());
978
979 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
980}
981
982// Test that if BUNDLE is enabled and the remote re-offer does not include a
983// BUNDLE group since all media sections are rejected, then the re-answer also
984// does not include a BUNDLE group.
985TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
986 MediaSessionOptions opts;
987 opts.bundle_enabled = true;
988 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
989 RtpTransceiverDirection::kSendRecv, kActive,
990 &opts);
991 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
992 std::unique_ptr<SessionDescription> answer =
993 f2_.CreateAnswer(offer.get(), opts, nullptr);
994
995 opts.media_description_options[0].stopped = true;
996 std::unique_ptr<SessionDescription> reoffer =
997 f1_.CreateOffer(opts, offer.get());
998 std::unique_ptr<SessionDescription> reanswer =
999 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1000
1001 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1002}
1003
1004// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1005// was rejected then the new offerer-tagged media section is the non-rejected
1006// media section.
1007TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1008 MediaSessionOptions opts;
1009 opts.bundle_enabled = true;
1010 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1011 RtpTransceiverDirection::kSendRecv, kActive,
1012 &opts);
1013 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1014
1015 // Reject the audio m= section and add a video m= section.
1016 opts.media_description_options[0].stopped = true;
1017 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1018 RtpTransceiverDirection::kSendRecv, kActive,
1019 &opts);
1020 std::unique_ptr<SessionDescription> reoffer =
1021 f1_.CreateOffer(opts, offer.get());
1022
1023 const cricket::ContentGroup* bundle_group =
1024 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1025 ASSERT_TRUE(bundle_group);
1026 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1027 EXPECT_TRUE(bundle_group->HasContentName("video"));
1028}
1029
1030// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1031// was rejected and a new media section is added, then the re-answer BUNDLE
1032// group will contain only the non-rejected media section.
1033TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1034 MediaSessionOptions opts;
1035 opts.bundle_enabled = true;
1036 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1037 RtpTransceiverDirection::kSendRecv, kActive,
1038 &opts);
1039 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1040 std::unique_ptr<SessionDescription> answer =
1041 f2_.CreateAnswer(offer.get(), opts, nullptr);
1042
1043 // Reject the audio m= section and add a video m= section.
1044 opts.media_description_options[0].stopped = true;
1045 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1046 RtpTransceiverDirection::kSendRecv, kActive,
1047 &opts);
1048 std::unique_ptr<SessionDescription> reoffer =
1049 f1_.CreateOffer(opts, offer.get());
1050 std::unique_ptr<SessionDescription> reanswer =
1051 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1052
1053 const cricket::ContentGroup* bundle_group =
1054 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1055 ASSERT_TRUE(bundle_group);
1056 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1057 EXPECT_TRUE(bundle_group->HasContentName("video"));
1058}
1059
1060// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1061// and there is still a non-rejected media section that was in the initial
1062// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1063// media section.
1064TEST_F(MediaSessionDescriptionFactoryTest,
1065 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1066 MediaSessionOptions opts;
1067 opts.bundle_enabled = true;
1068 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1069 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1070 std::unique_ptr<SessionDescription> answer =
1071 f2_.CreateAnswer(offer.get(), opts, nullptr);
1072
1073 // Reject the audio m= section.
1074 opts.media_description_options[0].stopped = true;
1075 std::unique_ptr<SessionDescription> reoffer =
1076 f1_.CreateOffer(opts, offer.get());
1077
1078 const TransportDescription* offer_tagged =
1079 offer->GetTransportDescriptionByName("audio");
1080 ASSERT_TRUE(offer_tagged);
1081 const TransportDescription* reoffer_tagged =
1082 reoffer->GetTransportDescriptionByName("video");
1083 ASSERT_TRUE(reoffer_tagged);
1084 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1085 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1086}
1087
1088// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1089// and there is still a non-rejected media section that was in the initial
1090// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1091// media section.
1092TEST_F(MediaSessionDescriptionFactoryTest,
1093 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1094 MediaSessionOptions opts;
1095 opts.bundle_enabled = true;
1096 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1097 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1098 std::unique_ptr<SessionDescription> answer =
1099 f2_.CreateAnswer(offer.get(), opts, nullptr);
1100
1101 // Reject the audio m= section.
1102 opts.media_description_options[0].stopped = true;
1103 std::unique_ptr<SessionDescription> reoffer =
1104 f1_.CreateOffer(opts, offer.get());
1105 std::unique_ptr<SessionDescription> reanswer =
1106 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1107
1108 const TransportDescription* answer_tagged =
1109 answer->GetTransportDescriptionByName("audio");
1110 ASSERT_TRUE(answer_tagged);
1111 const TransportDescription* reanswer_tagged =
1112 reanswer->GetTransportDescriptionByName("video");
1113 ASSERT_TRUE(reanswer_tagged);
1114 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1115 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1116}
1117
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001118// Create an audio, video offer without legacy StreamParams.
1119TEST_F(MediaSessionDescriptionFactoryTest,
1120 TestCreateOfferWithoutLegacyStreams) {
1121 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001122 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001123 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124 ASSERT_TRUE(offer.get() != NULL);
1125 const ContentInfo* ac = offer->GetContentByName("audio");
1126 const ContentInfo* vc = offer->GetContentByName("video");
1127 ASSERT_TRUE(ac != NULL);
1128 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001129 const AudioContentDescription* acd = ac->media_description()->as_audio();
1130 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131
Yves Gerey665174f2018-06-19 15:03:05 +02001132 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1133 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134}
1135
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001136// Creates an audio+video sendonly offer.
1137TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001138 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001139 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001140 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1141 {kMediaStream1}, 1, &opts);
1142 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1143 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001144
Steve Anton6fe1fba2018-12-11 10:15:23 -08001145 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001146 ASSERT_TRUE(offer.get() != NULL);
1147 EXPECT_EQ(2u, offer->contents().size());
1148 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1149 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1150
Steve Anton4e70a722017-11-28 14:57:10 -08001151 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1152 GetMediaDirection(&offer->contents()[0]));
1153 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1154 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001155}
1156
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001157// Verifies that the order of the media contents in the current
1158// SessionDescription is preserved in the new SessionDescription.
1159TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1160 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001161 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001162
kwiberg31022942016-03-11 14:18:21 -08001163 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001164 ASSERT_TRUE(offer1.get() != NULL);
1165 EXPECT_EQ(1u, offer1->contents().size());
1166 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1167
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001168 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1169 RtpTransceiverDirection::kRecvOnly, kActive,
1170 &opts);
kwiberg31022942016-03-11 14:18:21 -08001171 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001172 f1_.CreateOffer(opts, offer1.get()));
1173 ASSERT_TRUE(offer2.get() != NULL);
1174 EXPECT_EQ(2u, offer2->contents().size());
1175 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1176 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1177
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001178 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1179 RtpTransceiverDirection::kRecvOnly, kActive,
1180 &opts);
kwiberg31022942016-03-11 14:18:21 -08001181 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001182 f1_.CreateOffer(opts, offer2.get()));
1183 ASSERT_TRUE(offer3.get() != NULL);
1184 EXPECT_EQ(3u, offer3->contents().size());
1185 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1186 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1187 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001188}
1189
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190// Create a typical audio answer, and ensure it matches what we expect.
1191TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1192 f1_.set_secure(SEC_ENABLED);
1193 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001194 std::unique_ptr<SessionDescription> offer =
1195 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001196 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001197 std::unique_ptr<SessionDescription> answer =
1198 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001199 const ContentInfo* ac = answer->GetContentByName("audio");
1200 const ContentInfo* vc = answer->GetContentByName("video");
1201 ASSERT_TRUE(ac != NULL);
1202 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001203 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001204 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001206 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001207 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001208 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1209 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001210 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001211 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212}
1213
jbauchcb560652016-08-04 05:20:32 -07001214// Create a typical audio answer with GCM ciphers enabled, and ensure it
1215// matches what we expect.
1216TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1217 f1_.set_secure(SEC_ENABLED);
1218 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001219 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001220 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001221 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001222 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001223 std::unique_ptr<SessionDescription> answer =
1224 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001225 const ContentInfo* ac = answer->GetContentByName("audio");
1226 const ContentInfo* vc = answer->GetContentByName("video");
1227 ASSERT_TRUE(ac != NULL);
1228 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001229 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001230 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001231 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001232 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001233 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001234 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1235 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001236 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001237 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001238}
1239
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240// Create a typical video answer, and ensure it matches what we expect.
1241TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1242 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001243 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 f1_.set_secure(SEC_ENABLED);
1245 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001246 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001248 std::unique_ptr<SessionDescription> answer =
1249 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250 const ContentInfo* ac = answer->GetContentByName("audio");
1251 const ContentInfo* vc = answer->GetContentByName("video");
1252 ASSERT_TRUE(ac != NULL);
1253 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001254 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1255 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001256 const AudioContentDescription* acd = ac->media_description()->as_audio();
1257 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001259 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001261 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001263 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001265 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001266 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1267 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001268 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001269 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270}
1271
jbauchcb560652016-08-04 05:20:32 -07001272// Create a typical video answer with GCM ciphers enabled, and ensure it
1273// matches what we expect.
1274TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1275 TestVideoGcmCipher(true, true);
1276}
1277
1278// Create a typical video answer with GCM ciphers enabled for the offer only,
1279// and ensure it matches what we expect.
1280TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1281 TestVideoGcmCipher(true, false);
1282}
1283
1284// Create a typical video answer with GCM ciphers enabled for the answer only,
1285// and ensure it matches what we expect.
1286TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1287 TestVideoGcmCipher(false, true);
1288}
1289
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001290TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001291 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001292 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001293 f1_.set_secure(SEC_ENABLED);
1294 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001295 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001297 std::unique_ptr<SessionDescription> answer =
1298 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001299 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001300 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001302 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001303 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1304 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001305 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001306 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001308 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001310 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001312 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001313 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001314 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001315 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001316 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001317 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001318 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001319}
1320
jbauchcb560652016-08-04 05:20:32 -07001321TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001322 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001323 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001324 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001325 f1_.set_secure(SEC_ENABLED);
1326 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001327 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001328 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001329 std::unique_ptr<SessionDescription> answer =
1330 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001331 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001332 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001333 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001334 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001335 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1336 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001337 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001338 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001339 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001340 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001341 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001342 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001343 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001344 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001345 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001346 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001347 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001348 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001349 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001350 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001351}
1352
1353// The use_sctpmap flag should be set in a DataContentDescription by default.
1354// The answer's use_sctpmap flag should match the offer's.
1355TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1356 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001357 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001358 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001359 ASSERT_TRUE(offer.get() != NULL);
1360 ContentInfo* dc_offer = offer->GetContentByName("data");
1361 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001362 SctpDataContentDescription* dcd_offer =
1363 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001364 EXPECT_TRUE(dcd_offer->use_sctpmap());
1365
Steve Anton6fe1fba2018-12-11 10:15:23 -08001366 std::unique_ptr<SessionDescription> answer =
1367 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001368 const ContentInfo* dc_answer = answer->GetContentByName("data");
1369 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001370 const SctpDataContentDescription* dcd_answer =
1371 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001372 EXPECT_TRUE(dcd_answer->use_sctpmap());
1373}
1374
1375// The answer's use_sctpmap flag should match the offer's.
1376TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1377 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001378 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001379 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001380 ASSERT_TRUE(offer.get() != NULL);
1381 ContentInfo* dc_offer = offer->GetContentByName("data");
1382 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001383 SctpDataContentDescription* dcd_offer =
1384 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001385 dcd_offer->set_use_sctpmap(false);
1386
Steve Anton6fe1fba2018-12-11 10:15:23 -08001387 std::unique_ptr<SessionDescription> answer =
1388 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001389 const ContentInfo* dc_answer = answer->GetContentByName("data");
1390 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001391 const SctpDataContentDescription* dcd_answer =
1392 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001393 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001394}
1395
deadbeef8b7e9ad2017-05-25 09:38:55 -07001396// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1397// and "TCP/DTLS/SCTP" offers.
1398TEST_F(MediaSessionDescriptionFactoryTest,
1399 TestCreateDataAnswerToDifferentOfferedProtos) {
1400 // Need to enable DTLS offer/answer generation (disabled by default in this
1401 // test).
1402 f1_.set_secure(SEC_ENABLED);
1403 f2_.set_secure(SEC_ENABLED);
1404 tdf1_.set_secure(SEC_ENABLED);
1405 tdf2_.set_secure(SEC_ENABLED);
1406
1407 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001408 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001409 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001410 ASSERT_TRUE(offer.get() != nullptr);
1411 ContentInfo* dc_offer = offer->GetContentByName("data");
1412 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001413 SctpDataContentDescription* dcd_offer =
1414 dc_offer->media_description()->as_sctp();
1415 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001416
1417 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1418 "TCP/DTLS/SCTP"};
1419 for (const std::string& proto : protos) {
1420 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001421 std::unique_ptr<SessionDescription> answer =
1422 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001423 const ContentInfo* dc_answer = answer->GetContentByName("data");
1424 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001425 const SctpDataContentDescription* dcd_answer =
1426 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001427 EXPECT_FALSE(dc_answer->rejected);
1428 EXPECT_EQ(proto, dcd_answer->protocol());
1429 }
1430}
1431
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001432TEST_F(MediaSessionDescriptionFactoryTest,
1433 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1434 // Need to enable DTLS offer/answer generation (disabled by default in this
1435 // test).
1436 f1_.set_secure(SEC_ENABLED);
1437 f2_.set_secure(SEC_ENABLED);
1438 tdf1_.set_secure(SEC_ENABLED);
1439 tdf2_.set_secure(SEC_ENABLED);
1440
1441 MediaSessionOptions opts;
1442 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1443 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1444 ASSERT_TRUE(offer.get() != nullptr);
1445 ContentInfo* dc_offer = offer->GetContentByName("data");
1446 ASSERT_TRUE(dc_offer != nullptr);
1447 SctpDataContentDescription* dcd_offer =
1448 dc_offer->media_description()->as_sctp();
1449 ASSERT_TRUE(dcd_offer);
1450 dcd_offer->set_max_message_size(1234);
1451 std::unique_ptr<SessionDescription> answer =
1452 f2_.CreateAnswer(offer.get(), opts, nullptr);
1453 const ContentInfo* dc_answer = answer->GetContentByName("data");
1454 ASSERT_TRUE(dc_answer != nullptr);
1455 const SctpDataContentDescription* dcd_answer =
1456 dc_answer->media_description()->as_sctp();
1457 EXPECT_FALSE(dc_answer->rejected);
1458 EXPECT_EQ(1234, dcd_answer->max_message_size());
1459}
1460
1461TEST_F(MediaSessionDescriptionFactoryTest,
1462 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1463 // Need to enable DTLS offer/answer generation (disabled by default in this
1464 // test).
1465 f1_.set_secure(SEC_ENABLED);
1466 f2_.set_secure(SEC_ENABLED);
1467 tdf1_.set_secure(SEC_ENABLED);
1468 tdf2_.set_secure(SEC_ENABLED);
1469
1470 MediaSessionOptions opts;
1471 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1472 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1473 ASSERT_TRUE(offer.get() != nullptr);
1474 ContentInfo* dc_offer = offer->GetContentByName("data");
1475 ASSERT_TRUE(dc_offer != nullptr);
1476 SctpDataContentDescription* dcd_offer =
1477 dc_offer->media_description()->as_sctp();
1478 ASSERT_TRUE(dcd_offer);
1479 dcd_offer->set_max_message_size(0);
1480 std::unique_ptr<SessionDescription> answer =
1481 f2_.CreateAnswer(offer.get(), opts, nullptr);
1482 const ContentInfo* dc_answer = answer->GetContentByName("data");
1483 ASSERT_TRUE(dc_answer != nullptr);
1484 const SctpDataContentDescription* dcd_answer =
1485 dc_answer->media_description()->as_sctp();
1486 EXPECT_FALSE(dc_answer->rejected);
1487 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1488}
1489
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001490// Verifies that the order of the media contents in the offer is preserved in
1491// the answer.
1492TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1493 MediaSessionOptions opts;
1494
1495 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001496 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001497 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001498 ASSERT_TRUE(offer1.get() != NULL);
1499
1500 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001501 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1502 RtpTransceiverDirection::kRecvOnly, kActive,
1503 &opts);
kwiberg31022942016-03-11 14:18:21 -08001504 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001505 f1_.CreateOffer(opts, offer1.get()));
1506 ASSERT_TRUE(offer2.get() != NULL);
1507
1508 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001509 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1510 RtpTransceiverDirection::kRecvOnly, kActive,
1511 &opts);
kwiberg31022942016-03-11 14:18:21 -08001512 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001513 f1_.CreateOffer(opts, offer2.get()));
1514 ASSERT_TRUE(offer3.get() != NULL);
1515
Steve Anton6fe1fba2018-12-11 10:15:23 -08001516 std::unique_ptr<SessionDescription> answer =
1517 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001518 ASSERT_TRUE(answer.get() != NULL);
1519 EXPECT_EQ(3u, answer->contents().size());
1520 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1521 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1522 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1523}
1524
ossu075af922016-06-14 03:29:38 -07001525// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1526// answerer settings.
1527
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001528// This test that the media direction is set to send/receive in an answer if
1529// the offer is send receive.
1530TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001531 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1532 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001533}
1534
1535// This test that the media direction is set to receive only in an answer if
1536// the offer is send only.
1537TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001538 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1539 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001540}
1541
1542// This test that the media direction is set to send only in an answer if
1543// the offer is recv only.
1544TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001545 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1546 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001547}
1548
1549// This test that the media direction is set to inactive in an answer if
1550// the offer is inactive.
1551TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001552 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1553 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554}
1555
1556// Test that a data content with an unknown protocol is rejected in an answer.
1557TEST_F(MediaSessionDescriptionFactoryTest,
1558 CreateDataAnswerToOfferWithUnknownProtocol) {
1559 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001560 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001561 f1_.set_secure(SEC_ENABLED);
1562 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001563 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001564 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001565 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001566 RtpDataContentDescription* dcd_offer =
1567 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001569 // Offer must be acceptable as an RTP protocol in order to be set.
1570 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001571 dcd_offer->set_protocol(protocol);
1572
Steve Anton6fe1fba2018-12-11 10:15:23 -08001573 std::unique_ptr<SessionDescription> answer =
1574 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001575
1576 const ContentInfo* dc_answer = answer->GetContentByName("data");
1577 ASSERT_TRUE(dc_answer != NULL);
1578 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001579 const RtpDataContentDescription* dcd_answer =
1580 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001581 ASSERT_TRUE(dcd_answer != NULL);
1582 EXPECT_EQ(protocol, dcd_answer->protocol());
1583}
1584
1585// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1586TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001587 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001588 f1_.set_secure(SEC_DISABLED);
1589 f2_.set_secure(SEC_DISABLED);
1590 tdf1_.set_secure(SEC_DISABLED);
1591 tdf2_.set_secure(SEC_DISABLED);
1592
Steve Anton6fe1fba2018-12-11 10:15:23 -08001593 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001594 const AudioContentDescription* offer_acd =
1595 GetFirstAudioContentDescription(offer.get());
1596 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001597 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001598
Steve Anton6fe1fba2018-12-11 10:15:23 -08001599 std::unique_ptr<SessionDescription> answer =
1600 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001601
1602 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1603 ASSERT_TRUE(ac_answer != NULL);
1604 EXPECT_FALSE(ac_answer->rejected);
1605
1606 const AudioContentDescription* answer_acd =
1607 GetFirstAudioContentDescription(answer.get());
1608 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001609 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001610}
1611
1612// Create a video offer and answer and ensure the RTP header extensions
1613// matches what we expect.
1614TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1615 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001616 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001617 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1618 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1619 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1620 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1621
Steve Anton6fe1fba2018-12-11 10:15:23 -08001622 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001623 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001624 std::unique_ptr<SessionDescription> answer =
1625 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626
Yves Gerey665174f2018-06-19 15:03:05 +02001627 EXPECT_EQ(
1628 MAKE_VECTOR(kAudioRtpExtension1),
1629 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1630 EXPECT_EQ(
1631 MAKE_VECTOR(kVideoRtpExtension1),
1632 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1633 EXPECT_EQ(
1634 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1635 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1636 EXPECT_EQ(
1637 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1638 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639}
1640
Johannes Kronce8e8672019-02-22 13:06:44 +01001641// Create a audio/video offer and answer and ensure that the
1642// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1643// supported and should take precedence even though not listed among locally
1644// supported extensions.
1645TEST_F(MediaSessionDescriptionFactoryTest,
1646 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1647 TestTransportSequenceNumberNegotiation(
1648 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1649 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1650 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1651}
1652TEST_F(MediaSessionDescriptionFactoryTest,
1653 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1654 TestTransportSequenceNumberNegotiation(
1655 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1656 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1657 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1658}
1659TEST_F(MediaSessionDescriptionFactoryTest,
1660 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1661 TestTransportSequenceNumberNegotiation(
1662 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1663 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1664 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1665}
1666
jbauch5869f502017-06-29 12:31:36 -07001667TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001668 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001669 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001670 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001671
1672 f1_.set_enable_encrypted_rtp_header_extensions(true);
1673 f2_.set_enable_encrypted_rtp_header_extensions(true);
1674
Yves Gerey665174f2018-06-19 15:03:05 +02001675 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1676 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1677 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1678 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001679
Steve Anton6fe1fba2018-12-11 10:15:23 -08001680 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001681 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001682 std::unique_ptr<SessionDescription> answer =
1683 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001684
Yves Gerey665174f2018-06-19 15:03:05 +02001685 EXPECT_EQ(
1686 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1687 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1688 EXPECT_EQ(
1689 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1690 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1691 EXPECT_EQ(
1692 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1693 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1694 EXPECT_EQ(
1695 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1696 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001697}
1698
1699TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001700 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001701 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001702 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001703
1704 f1_.set_enable_encrypted_rtp_header_extensions(true);
1705
Yves Gerey665174f2018-06-19 15:03:05 +02001706 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1707 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1708 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1709 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001710
Steve Anton6fe1fba2018-12-11 10:15:23 -08001711 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001712 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001713 std::unique_ptr<SessionDescription> answer =
1714 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001715
Yves Gerey665174f2018-06-19 15:03:05 +02001716 EXPECT_EQ(
1717 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1718 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1719 EXPECT_EQ(
1720 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1721 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1722 EXPECT_EQ(
1723 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1724 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1725 EXPECT_EQ(
1726 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1727 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001728}
1729
1730TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001731 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001732 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001733 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001734
1735 f2_.set_enable_encrypted_rtp_header_extensions(true);
1736
Yves Gerey665174f2018-06-19 15:03:05 +02001737 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1738 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1739 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1740 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001741
Steve Anton6fe1fba2018-12-11 10:15:23 -08001742 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001743 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001744 std::unique_ptr<SessionDescription> answer =
1745 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001746
Yves Gerey665174f2018-06-19 15:03:05 +02001747 EXPECT_EQ(
1748 MAKE_VECTOR(kAudioRtpExtension1),
1749 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1750 EXPECT_EQ(
1751 MAKE_VECTOR(kVideoRtpExtension1),
1752 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1753 EXPECT_EQ(
1754 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1755 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1756 EXPECT_EQ(
1757 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1758 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001759}
1760
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001761// Create an audio, video, data answer without legacy StreamParams.
1762TEST_F(MediaSessionDescriptionFactoryTest,
1763 TestCreateAnswerWithoutLegacyStreams) {
1764 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001765 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1766 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001767 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001768 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001769 std::unique_ptr<SessionDescription> answer =
1770 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001771 const ContentInfo* ac = answer->GetContentByName("audio");
1772 const ContentInfo* vc = answer->GetContentByName("video");
1773 const ContentInfo* dc = answer->GetContentByName("data");
1774 ASSERT_TRUE(ac != NULL);
1775 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001776 const AudioContentDescription* acd = ac->media_description()->as_audio();
1777 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001778 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001779
1780 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1781 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1782 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1783}
1784
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001785// Create a typical video answer, and ensure it matches what we expect.
1786TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1787 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001788 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1789 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1790 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001791
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001792 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001793 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1794 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1795 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001796
kwiberg31022942016-03-11 14:18:21 -08001797 std::unique_ptr<SessionDescription> offer;
1798 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001799
1800 offer_opts.rtcp_mux_enabled = true;
1801 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001802 offer = f1_.CreateOffer(offer_opts, NULL);
1803 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001804 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1805 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001806 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001807 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1808 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001809 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001810 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1811 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001812 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001813 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1814 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001815 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001816
1817 offer_opts.rtcp_mux_enabled = true;
1818 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001819 offer = f1_.CreateOffer(offer_opts, NULL);
1820 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001821 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1822 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001823 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001824 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1825 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001826 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001827 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1828 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001829 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001830 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1831 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001832 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001833
1834 offer_opts.rtcp_mux_enabled = false;
1835 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001836 offer = f1_.CreateOffer(offer_opts, NULL);
1837 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001838 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1839 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001840 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001841 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1842 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001843 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001844 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1845 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001846 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1848 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001849 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001850
1851 offer_opts.rtcp_mux_enabled = false;
1852 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001853 offer = f1_.CreateOffer(offer_opts, NULL);
1854 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001855 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1856 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001857 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001858 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1859 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001860 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001861 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1862 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001863 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001864 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1865 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001866 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001867}
1868
1869// Create an audio-only answer to a video offer.
1870TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1871 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001872 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1873 RtpTransceiverDirection::kRecvOnly, kActive,
1874 &opts);
1875 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1876 RtpTransceiverDirection::kRecvOnly, kActive,
1877 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001878 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001879 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001880
1881 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001882 std::unique_ptr<SessionDescription> answer =
1883 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884 const ContentInfo* ac = answer->GetContentByName("audio");
1885 const ContentInfo* vc = answer->GetContentByName("video");
1886 ASSERT_TRUE(ac != NULL);
1887 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001888 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001889 EXPECT_TRUE(vc->rejected);
1890}
1891
1892// Create an audio-only answer to an offer with data.
1893TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001894 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001895 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001896 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1897 RtpTransceiverDirection::kRecvOnly, kActive,
1898 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001899 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001900 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001901
1902 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001903 std::unique_ptr<SessionDescription> answer =
1904 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001905 const ContentInfo* ac = answer->GetContentByName("audio");
1906 const ContentInfo* dc = answer->GetContentByName("data");
1907 ASSERT_TRUE(ac != NULL);
1908 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001909 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001910 EXPECT_TRUE(dc->rejected);
1911}
1912
1913// Create an answer that rejects the contents which are rejected in the offer.
1914TEST_F(MediaSessionDescriptionFactoryTest,
1915 CreateAnswerToOfferWithRejectedMedia) {
1916 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001917 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1918 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001919 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001920 ASSERT_TRUE(offer.get() != NULL);
1921 ContentInfo* ac = offer->GetContentByName("audio");
1922 ContentInfo* vc = offer->GetContentByName("video");
1923 ContentInfo* dc = offer->GetContentByName("data");
1924 ASSERT_TRUE(ac != NULL);
1925 ASSERT_TRUE(vc != NULL);
1926 ASSERT_TRUE(dc != NULL);
1927 ac->rejected = true;
1928 vc->rejected = true;
1929 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001930 std::unique_ptr<SessionDescription> answer =
1931 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001932 ac = answer->GetContentByName("audio");
1933 vc = answer->GetContentByName("video");
1934 dc = answer->GetContentByName("data");
1935 ASSERT_TRUE(ac != NULL);
1936 ASSERT_TRUE(vc != NULL);
1937 ASSERT_TRUE(dc != NULL);
1938 EXPECT_TRUE(ac->rejected);
1939 EXPECT_TRUE(vc->rejected);
1940 EXPECT_TRUE(dc->rejected);
1941}
1942
Johannes Kron0854eb62018-10-10 22:33:20 +02001943TEST_F(MediaSessionDescriptionFactoryTest,
1944 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1945 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001946 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001947 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001948 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001949 ASSERT_TRUE(offer.get() != NULL);
1950 std::unique_ptr<SessionDescription> answer_no_support(
1951 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001952 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001953
1954 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001955 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001956 ASSERT_TRUE(offer.get() != NULL);
1957 std::unique_ptr<SessionDescription> answer_support(
1958 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001959 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001960}
1961
1962TEST_F(MediaSessionDescriptionFactoryTest,
1963 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1964 MediaSessionOptions opts;
1965 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001966 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001967 MediaContentDescription* video_offer =
1968 offer->GetContentDescriptionByName("video");
1969 ASSERT_TRUE(video_offer);
1970 MediaContentDescription* audio_offer =
1971 offer->GetContentDescriptionByName("audio");
1972 ASSERT_TRUE(audio_offer);
1973
1974 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001975 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1976 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001977
1978 ASSERT_TRUE(offer.get() != NULL);
1979 std::unique_ptr<SessionDescription> answer_no_support(
1980 f2_.CreateAnswer(offer.get(), opts, NULL));
1981 MediaContentDescription* video_answer =
1982 answer_no_support->GetContentDescriptionByName("video");
1983 MediaContentDescription* audio_answer =
1984 answer_no_support->GetContentDescriptionByName("audio");
1985 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001986 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001987 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001988 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001989
1990 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001991 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1992 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001993 ASSERT_TRUE(offer.get() != NULL);
1994 std::unique_ptr<SessionDescription> answer_support(
1995 f2_.CreateAnswer(offer.get(), opts, NULL));
1996 video_answer = answer_support->GetContentDescriptionByName("video");
1997 audio_answer = answer_support->GetContentDescriptionByName("audio");
1998 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001999 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002000 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002001 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002002}
2003
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002004// Create an audio and video offer with:
2005// - one video track
2006// - two audio tracks
2007// - two data tracks
2008// and ensure it matches what we expect. Also updates the initial offer by
2009// adding a new video track and replaces one of the audio tracks.
2010TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2011 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002012 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002013 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2014 {kMediaStream1}, 1, &opts);
2015 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2016 {kMediaStream1}, 1, &opts);
2017 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2018 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002019
Steve Anton4e70a722017-11-28 14:57:10 -08002020 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002021 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2022 {kMediaStream1}, 1, &opts);
2023 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2024 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025
2026 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002027 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028
2029 ASSERT_TRUE(offer.get() != NULL);
2030 const ContentInfo* ac = offer->GetContentByName("audio");
2031 const ContentInfo* vc = offer->GetContentByName("video");
2032 const ContentInfo* dc = offer->GetContentByName("data");
2033 ASSERT_TRUE(ac != NULL);
2034 ASSERT_TRUE(vc != NULL);
2035 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002036 const AudioContentDescription* acd = ac->media_description()->as_audio();
2037 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002038 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002039 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002040 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002041
2042 const StreamParamsVec& audio_streams = acd->streams();
2043 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002044 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002045 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2046 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2047 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2048 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2049 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2050 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2051
2052 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2053 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002054 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002055
2056 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
2057 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002058 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002059
2060 const StreamParamsVec& video_streams = vcd->streams();
2061 ASSERT_EQ(1U, video_streams.size());
2062 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2063 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2064 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2065 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2066
2067 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002068 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002069 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002070
2071 const StreamParamsVec& data_streams = dcd->streams();
2072 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002073 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002074 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2075 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2076 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2077 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2078 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2079 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2080
2081 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002082 dcd->bandwidth()); // default bandwidth (auto)
2083 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002084 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002085
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002086 // Update the offer. Add a new video track that is not synched to the
2087 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002088 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2089 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002090 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002091 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2092 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002093 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002094 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2095 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002096 std::unique_ptr<SessionDescription> updated_offer(
2097 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002098
2099 ASSERT_TRUE(updated_offer.get() != NULL);
2100 ac = updated_offer->GetContentByName("audio");
2101 vc = updated_offer->GetContentByName("video");
2102 dc = updated_offer->GetContentByName("data");
2103 ASSERT_TRUE(ac != NULL);
2104 ASSERT_TRUE(vc != NULL);
2105 ASSERT_TRUE(dc != NULL);
2106 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002107 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002108 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002109 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002110 const RtpDataContentDescription* updated_dcd =
2111 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002112
2113 EXPECT_EQ(acd->type(), updated_acd->type());
2114 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2115 EXPECT_EQ(vcd->type(), updated_vcd->type());
2116 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2117 EXPECT_EQ(dcd->type(), updated_dcd->type());
2118 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002119 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002120 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002121 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002122 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002123 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002124 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2125
2126 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2127 ASSERT_EQ(2U, updated_audio_streams.size());
2128 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2129 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2130 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2131 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2132 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2133
2134 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2135 ASSERT_EQ(2U, updated_video_streams.size());
2136 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2137 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002138 // All the media streams in one PeerConnection share one RTCP CNAME.
2139 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002140
2141 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2142 ASSERT_EQ(2U, updated_data_streams.size());
2143 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2144 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2145 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2146 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2147 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002148 // The stream correctly got the CNAME from the MediaSessionOptions.
2149 // The Expected RTCP CNAME is the default one as we are using the default
2150 // MediaSessionOptions.
2151 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002152}
2153
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002154// Create an offer with simulcast video stream.
2155TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2156 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002157 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2158 RtpTransceiverDirection::kRecvOnly, kActive,
2159 &opts);
2160 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2161 RtpTransceiverDirection::kSendRecv, kActive,
2162 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002163 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002164 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2165 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002166 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002167
2168 ASSERT_TRUE(offer.get() != NULL);
2169 const ContentInfo* vc = offer->GetContentByName("video");
2170 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002171 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002172
2173 const StreamParamsVec& video_streams = vcd->streams();
2174 ASSERT_EQ(1U, video_streams.size());
2175 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2176 const SsrcGroup* sim_ssrc_group =
2177 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2178 ASSERT_TRUE(sim_ssrc_group != NULL);
2179 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2180}
2181
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002182MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2183 const RidDescription& rid1 = ::testing::get<0>(arg);
2184 const RidDescription& rid2 = ::testing::get<1>(arg);
2185 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2186}
2187
2188static void CheckSimulcastInSessionDescription(
2189 const SessionDescription* description,
2190 const std::string& content_name,
2191 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002192 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002193 ASSERT_NE(description, nullptr);
2194 const ContentInfo* content = description->GetContentByName(content_name);
2195 ASSERT_NE(content, nullptr);
2196 const MediaContentDescription* cd = content->media_description();
2197 ASSERT_NE(cd, nullptr);
2198 const StreamParamsVec& streams = cd->streams();
2199 ASSERT_THAT(streams, SizeIs(1));
2200 const StreamParams& stream = streams[0];
2201 ASSERT_THAT(stream.ssrcs, IsEmpty());
2202 EXPECT_TRUE(stream.has_rids());
2203 const std::vector<RidDescription> rids = stream.rids();
2204
2205 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2206
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002207 EXPECT_TRUE(cd->HasSimulcast());
2208 const SimulcastDescription& simulcast = cd->simulcast_description();
2209 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2210 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2211
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002212 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002213}
2214
2215// Create an offer with spec-compliant simulcast video stream.
2216TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2217 MediaSessionOptions opts;
2218 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2219 RtpTransceiverDirection::kSendRecv, kActive,
2220 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002221 std::vector<RidDescription> send_rids;
2222 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2223 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2224 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2225 SimulcastLayerList simulcast_layers;
2226 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2227 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2228 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2229 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2230 {kMediaStream1}, send_rids,
2231 simulcast_layers, 0, &opts);
2232 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2233
2234 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002235 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002236}
2237
2238// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2239// In this scenario, RIDs do not need to be negotiated (there is only one).
2240TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2241 MediaSessionOptions opts;
2242 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2243 RtpTransceiverDirection::kSendRecv, kActive,
2244 &opts);
2245 RidDescription rid("f", RidDirection::kSend);
2246 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2247 {kMediaStream1}, {rid},
2248 SimulcastLayerList(), 0, &opts);
2249 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2250
2251 ASSERT_NE(offer.get(), nullptr);
2252 const ContentInfo* content = offer->GetContentByName("video");
2253 ASSERT_NE(content, nullptr);
2254 const MediaContentDescription* cd = content->media_description();
2255 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002256 const StreamParamsVec& streams = cd->streams();
2257 ASSERT_THAT(streams, SizeIs(1));
2258 const StreamParams& stream = streams[0];
2259 ASSERT_THAT(stream.ssrcs, IsEmpty());
2260 EXPECT_FALSE(stream.has_rids());
2261 EXPECT_FALSE(cd->HasSimulcast());
2262}
2263
2264// Create an answer with spec-compliant simulcast video stream.
2265// In this scenario, the SFU is the caller requesting that we send Simulcast.
2266TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2267 MediaSessionOptions offer_opts;
2268 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2269 RtpTransceiverDirection::kSendRecv, kActive,
2270 &offer_opts);
2271 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2272 {kMediaStream1}, 1, &offer_opts);
2273 std::unique_ptr<SessionDescription> offer =
2274 f1_.CreateOffer(offer_opts, nullptr);
2275
2276 MediaSessionOptions answer_opts;
2277 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2278 RtpTransceiverDirection::kSendRecv, kActive,
2279 &answer_opts);
2280
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002281 std::vector<RidDescription> rid_descriptions{
2282 RidDescription("f", RidDirection::kSend),
2283 RidDescription("h", RidDirection::kSend),
2284 RidDescription("q", RidDirection::kSend),
2285 };
2286 SimulcastLayerList simulcast_layers;
2287 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2288 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2289 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2290 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2291 {kMediaStream1}, rid_descriptions,
2292 simulcast_layers, 0, &answer_opts);
2293 std::unique_ptr<SessionDescription> answer =
2294 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2295
2296 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002297 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002298}
2299
2300// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2301// In this scenario, RIDs do not need to be negotiated (there is only one).
2302// Note that RID Direction is not the same as the transceiver direction.
2303TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2304 MediaSessionOptions offer_opts;
2305 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2306 RtpTransceiverDirection::kSendRecv, kActive,
2307 &offer_opts);
2308 RidDescription rid_offer("f", RidDirection::kSend);
2309 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2310 {kMediaStream1}, {rid_offer},
2311 SimulcastLayerList(), 0, &offer_opts);
2312 std::unique_ptr<SessionDescription> offer =
2313 f1_.CreateOffer(offer_opts, nullptr);
2314
2315 MediaSessionOptions answer_opts;
2316 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2317 RtpTransceiverDirection::kSendRecv, kActive,
2318 &answer_opts);
2319
2320 RidDescription rid_answer("f", RidDirection::kReceive);
2321 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2322 {kMediaStream1}, {rid_answer},
2323 SimulcastLayerList(), 0, &answer_opts);
2324 std::unique_ptr<SessionDescription> answer =
2325 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2326
2327 ASSERT_NE(answer.get(), nullptr);
2328 const ContentInfo* content = offer->GetContentByName("video");
2329 ASSERT_NE(content, nullptr);
2330 const MediaContentDescription* cd = content->media_description();
2331 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002332 const StreamParamsVec& streams = cd->streams();
2333 ASSERT_THAT(streams, SizeIs(1));
2334 const StreamParams& stream = streams[0];
2335 ASSERT_THAT(stream.ssrcs, IsEmpty());
2336 EXPECT_FALSE(stream.has_rids());
2337 EXPECT_FALSE(cd->HasSimulcast());
2338}
2339
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340// Create an audio and video answer to a standard video offer with:
2341// - one video track
2342// - two audio tracks
2343// - two data tracks
2344// and ensure it matches what we expect. Also updates the initial answer by
2345// adding a new video track and removes one of the audio tracks.
2346TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2347 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002348 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2349 RtpTransceiverDirection::kRecvOnly, kActive,
2350 &offer_opts);
2351 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2352 RtpTransceiverDirection::kRecvOnly, kActive,
2353 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002354 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002355 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2356 RtpTransceiverDirection::kRecvOnly, kActive,
2357 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002358 f1_.set_secure(SEC_ENABLED);
2359 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002360 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002361
zhihuang1c378ed2017-08-17 14:10:50 -07002362 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002363 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2364 RtpTransceiverDirection::kSendRecv, kActive,
2365 &answer_opts);
2366 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2367 RtpTransceiverDirection::kSendRecv, kActive,
2368 &answer_opts);
2369 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2370 {kMediaStream1}, 1, &answer_opts);
2371 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2372 {kMediaStream1}, 1, &answer_opts);
2373 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2374 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002375
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002376 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2377 RtpTransceiverDirection::kSendRecv, kActive,
2378 &answer_opts);
2379 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2380 {kMediaStream1}, 1, &answer_opts);
2381 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2382 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002383 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002384
Steve Anton6fe1fba2018-12-11 10:15:23 -08002385 std::unique_ptr<SessionDescription> answer =
2386 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387
2388 ASSERT_TRUE(answer.get() != NULL);
2389 const ContentInfo* ac = answer->GetContentByName("audio");
2390 const ContentInfo* vc = answer->GetContentByName("video");
2391 const ContentInfo* dc = answer->GetContentByName("data");
2392 ASSERT_TRUE(ac != NULL);
2393 ASSERT_TRUE(vc != NULL);
2394 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002395 const AudioContentDescription* acd = ac->media_description()->as_audio();
2396 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002397 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002398 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2399 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2400 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002401
2402 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002403 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002404
2405 const StreamParamsVec& audio_streams = acd->streams();
2406 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002407 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002408 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2409 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2410 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2411 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2412 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2413 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2414
2415 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2416 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2417
2418 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002419 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002420
2421 const StreamParamsVec& video_streams = vcd->streams();
2422 ASSERT_EQ(1U, video_streams.size());
2423 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2424 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2425 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2426 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2427
2428 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002429 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002430
2431 const StreamParamsVec& data_streams = dcd->streams();
2432 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002433 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002434 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2435 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2436 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2437 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2438 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2439 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2440
2441 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002442 dcd->bandwidth()); // default bandwidth (auto)
2443 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002444
2445 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002446 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002447 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2448 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002449 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2450 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002451 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002452 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002453
2454 ASSERT_TRUE(updated_answer.get() != NULL);
2455 ac = updated_answer->GetContentByName("audio");
2456 vc = updated_answer->GetContentByName("video");
2457 dc = updated_answer->GetContentByName("data");
2458 ASSERT_TRUE(ac != NULL);
2459 ASSERT_TRUE(vc != NULL);
2460 ASSERT_TRUE(dc != NULL);
2461 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002462 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002463 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002464 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002465 const RtpDataContentDescription* updated_dcd =
2466 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002467
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002468 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002469 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002470 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002471 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002472 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002473 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2474
2475 EXPECT_EQ(acd->type(), updated_acd->type());
2476 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2477 EXPECT_EQ(vcd->type(), updated_vcd->type());
2478 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2479 EXPECT_EQ(dcd->type(), updated_dcd->type());
2480 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2481
2482 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2483 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002484 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002485
2486 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2487 ASSERT_EQ(2U, updated_video_streams.size());
2488 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2489 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002490 // All media streams in one PeerConnection share one CNAME.
2491 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002492
2493 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2494 ASSERT_EQ(1U, updated_data_streams.size());
2495 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2496}
2497
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002498// Create an updated offer after creating an answer to the original offer and
2499// verify that the codecs that were part of the original answer are not changed
2500// in the updated offer.
2501TEST_F(MediaSessionDescriptionFactoryTest,
2502 RespondentCreatesOfferAfterCreatingAnswer) {
2503 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002504 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002505
Steve Anton6fe1fba2018-12-11 10:15:23 -08002506 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2507 std::unique_ptr<SessionDescription> answer =
2508 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002509
2510 const AudioContentDescription* acd =
2511 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002512 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002513
2514 const VideoContentDescription* vcd =
2515 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002516 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002517
kwiberg31022942016-03-11 14:18:21 -08002518 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002519 f2_.CreateOffer(opts, answer.get()));
2520
2521 // The expected audio codecs are the common audio codecs from the first
2522 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2523 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002524 // TODO(wu): |updated_offer| should not include the codec
2525 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002527 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528 };
2529
2530 // The expected video codecs are the common video codecs from the first
2531 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2532 // preference order.
2533 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002534 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002535 };
2536
2537 const AudioContentDescription* updated_acd =
2538 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002539 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002540
2541 const VideoContentDescription* updated_vcd =
2542 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002543 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002544}
2545
Steve Anton5c72e712018-12-10 14:25:30 -08002546// Test that a reoffer does not reuse audio codecs from a previous media section
2547// that is being recycled.
2548TEST_F(MediaSessionDescriptionFactoryTest,
2549 ReOfferDoesNotReUseRecycledAudioCodecs) {
2550 f1_.set_video_codecs({});
2551 f2_.set_video_codecs({});
2552
2553 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002554 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2555 RtpTransceiverDirection::kSendRecv, kActive,
2556 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002557 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2558 std::unique_ptr<SessionDescription> answer =
2559 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002560
2561 // Recycle the media section by changing its mid.
2562 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002563 std::unique_ptr<SessionDescription> reoffer =
2564 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002565
2566 // Expect that the results of the first negotiation are ignored. If the m=
2567 // section was not recycled the payload types would match the initial offerer.
2568 const AudioContentDescription* acd =
2569 GetFirstAudioContentDescription(reoffer.get());
2570 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2571}
2572
2573// Test that a reoffer does not reuse video codecs from a previous media section
2574// that is being recycled.
2575TEST_F(MediaSessionDescriptionFactoryTest,
2576 ReOfferDoesNotReUseRecycledVideoCodecs) {
2577 f1_.set_audio_codecs({}, {});
2578 f2_.set_audio_codecs({}, {});
2579
2580 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002581 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2582 RtpTransceiverDirection::kSendRecv, kActive,
2583 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002584 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2585 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002586
2587 // Recycle the media section by changing its mid.
2588 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002589 std::unique_ptr<SessionDescription> reoffer =
2590 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002591
2592 // Expect that the results of the first negotiation are ignored. If the m=
2593 // section was not recycled the payload types would match the initial offerer.
2594 const VideoContentDescription* vcd =
2595 GetFirstVideoContentDescription(reoffer.get());
2596 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2597}
2598
2599// Test that a reanswer does not reuse audio codecs from a previous media
2600// section that is being recycled.
2601TEST_F(MediaSessionDescriptionFactoryTest,
2602 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2603 f1_.set_video_codecs({});
2604 f2_.set_video_codecs({});
2605
2606 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2607 // second offer/answer is forward (|f1_| as offerer).
2608 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002609 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2610 RtpTransceiverDirection::kSendRecv, kActive,
2611 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002612 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2613 std::unique_ptr<SessionDescription> answer =
2614 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002615
2616 // Recycle the media section by changing its mid.
2617 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002618 std::unique_ptr<SessionDescription> reoffer =
2619 f1_.CreateOffer(opts, answer.get());
2620 std::unique_ptr<SessionDescription> reanswer =
2621 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002622
2623 // Expect that the results of the first negotiation are ignored. If the m=
2624 // section was not recycled the payload types would match the initial offerer.
2625 const AudioContentDescription* acd =
2626 GetFirstAudioContentDescription(reanswer.get());
2627 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2628}
2629
2630// Test that a reanswer does not reuse video codecs from a previous media
2631// section that is being recycled.
2632TEST_F(MediaSessionDescriptionFactoryTest,
2633 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2634 f1_.set_audio_codecs({}, {});
2635 f2_.set_audio_codecs({}, {});
2636
2637 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2638 // second offer/answer is forward (|f1_| as offerer).
2639 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002640 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2641 RtpTransceiverDirection::kSendRecv, kActive,
2642 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002643 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2644 std::unique_ptr<SessionDescription> answer =
2645 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002646
2647 // Recycle the media section by changing its mid.
2648 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002649 std::unique_ptr<SessionDescription> reoffer =
2650 f1_.CreateOffer(opts, answer.get());
2651 std::unique_ptr<SessionDescription> reanswer =
2652 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002653
2654 // Expect that the results of the first negotiation are ignored. If the m=
2655 // section was not recycled the payload types would match the initial offerer.
2656 const VideoContentDescription* vcd =
2657 GetFirstVideoContentDescription(reanswer.get());
2658 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2659}
2660
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661// Create an updated offer after creating an answer to the original offer and
2662// verify that the codecs that were part of the original answer are not changed
2663// in the updated offer. In this test Rtx is enabled.
2664TEST_F(MediaSessionDescriptionFactoryTest,
2665 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2666 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002667 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2668 RtpTransceiverDirection::kRecvOnly, kActive,
2669 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002671 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002672 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002673 f1_.set_video_codecs(f1_codecs);
2674
2675 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002676 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002677 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002678 f2_.set_video_codecs(f2_codecs);
2679
Steve Anton6fe1fba2018-12-11 10:15:23 -08002680 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002681 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002682 std::unique_ptr<SessionDescription> answer =
2683 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684
2685 const VideoContentDescription* vcd =
2686 GetFirstVideoContentDescription(answer.get());
2687
2688 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002689 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2690 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002691
2692 EXPECT_EQ(expected_codecs, vcd->codecs());
2693
deadbeef67cf2c12016-04-13 10:07:16 -07002694 // Now, make sure we get same result (except for the order) if |f2_| creates
2695 // an updated offer even though the default payload types between |f1_| and
2696 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002697 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002698 f2_.CreateOffer(opts, answer.get()));
2699 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002700 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002701 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2702
2703 const VideoContentDescription* updated_vcd =
2704 GetFirstVideoContentDescription(updated_answer.get());
2705
2706 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2707}
2708
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002709// Regression test for:
2710// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2711// Existing codecs should always appear before new codecs in re-offers. But
2712// under a specific set of circumstances, the existing RTX codec was ending up
2713// added to the end of the list.
2714TEST_F(MediaSessionDescriptionFactoryTest,
2715 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2716 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002717 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2718 RtpTransceiverDirection::kRecvOnly, kActive,
2719 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002720 // We specifically choose different preferred payload types for VP8 to
2721 // trigger the issue.
2722 cricket::VideoCodec vp8_offerer(100, "VP8");
2723 cricket::VideoCodec vp8_offerer_rtx =
2724 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2725 cricket::VideoCodec vp8_answerer(110, "VP8");
2726 cricket::VideoCodec vp8_answerer_rtx =
2727 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2728 cricket::VideoCodec vp9(120, "VP9");
2729 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2730
2731 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2732 // We also specifically cause the answerer to prefer VP9, such that if it
2733 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2734 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2735 vp8_answerer_rtx};
2736
2737 f1_.set_video_codecs(f1_codecs);
2738 f2_.set_video_codecs(f2_codecs);
2739 std::vector<AudioCodec> audio_codecs;
2740 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2741 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2742
2743 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002744 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002745 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002746 std::unique_ptr<SessionDescription> answer =
2747 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002748
2749 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2750 // But if the bug is triggered, RTX for VP8 ends up last.
2751 std::unique_ptr<SessionDescription> updated_offer(
2752 f2_.CreateOffer(opts, answer.get()));
2753
2754 const VideoContentDescription* vcd =
2755 GetFirstVideoContentDescription(updated_offer.get());
2756 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2757 ASSERT_EQ(4u, codecs.size());
2758 EXPECT_EQ(vp8_offerer, codecs[0]);
2759 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2760 EXPECT_EQ(vp9, codecs[2]);
2761 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002762}
2763
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002764// Create an updated offer that adds video after creating an audio only answer
2765// to the original offer. This test verifies that if a video codec and the RTX
2766// codec have the same default payload type as an audio codec that is already in
2767// use, the added codecs payload types are changed.
2768TEST_F(MediaSessionDescriptionFactoryTest,
2769 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2770 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002771 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002772 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002773 f1_.set_video_codecs(f1_codecs);
2774
2775 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002776 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2777 RtpTransceiverDirection::kRecvOnly, kActive,
2778 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002779
Steve Anton6fe1fba2018-12-11 10:15:23 -08002780 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2781 std::unique_ptr<SessionDescription> answer =
2782 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783
2784 const AudioContentDescription* acd =
2785 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002786 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002787
2788 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2789 // reference be the same as an audio codec that was negotiated in the
2790 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002791 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002792 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793
2794 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2795 int used_pl_type = acd->codecs()[0].id;
2796 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002797 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002798 f2_.set_video_codecs(f2_codecs);
2799
kwiberg31022942016-03-11 14:18:21 -08002800 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002801 f2_.CreateOffer(opts, answer.get()));
2802 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002803 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002804 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2805
2806 const AudioContentDescription* updated_acd =
2807 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002808 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002809
2810 const VideoContentDescription* updated_vcd =
2811 GetFirstVideoContentDescription(updated_answer.get());
2812
2813 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002814 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002815 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002816 EXPECT_NE(used_pl_type, new_h264_pl_type);
2817 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002818 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002819 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2820 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2821}
2822
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002823// Create an updated offer with RTX after creating an answer to an offer
2824// without RTX, and with different default payload types.
2825// Verify that the added RTX codec references the correct payload type.
2826TEST_F(MediaSessionDescriptionFactoryTest,
2827 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2828 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002829 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002830
2831 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2832 // This creates rtx for H264 with the payload type |f2_| uses.
2833 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2834 f2_.set_video_codecs(f2_codecs);
2835
Steve Anton6fe1fba2018-12-11 10:15:23 -08002836 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002837 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002838 std::unique_ptr<SessionDescription> answer =
2839 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002840
2841 const VideoContentDescription* vcd =
2842 GetFirstVideoContentDescription(answer.get());
2843
2844 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2845 EXPECT_EQ(expected_codecs, vcd->codecs());
2846
2847 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2848 // updated offer, even though the default payload types are different from
2849 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002850 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002851 f2_.CreateOffer(opts, answer.get()));
2852 ASSERT_TRUE(updated_offer);
2853
2854 const VideoContentDescription* updated_vcd =
2855 GetFirstVideoContentDescription(updated_offer.get());
2856
2857 // New offer should attempt to add H263, and RTX for H264.
2858 expected_codecs.push_back(kVideoCodecs2[1]);
2859 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2860 &expected_codecs);
2861 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2862}
2863
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002864// Test that RTX is ignored when there is no associated payload type parameter.
2865TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2866 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002867 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2868 RtpTransceiverDirection::kRecvOnly, kActive,
2869 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002870 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002871 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002872 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002873 f1_.set_video_codecs(f1_codecs);
2874
2875 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002876 // This creates RTX for H264 with the payload type |f2_| uses.
2877 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002878 f2_.set_video_codecs(f2_codecs);
2879
Steve Anton6fe1fba2018-12-11 10:15:23 -08002880 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002881 ASSERT_TRUE(offer.get() != NULL);
2882 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2883 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2884 // is possible to test that that RTX is dropped when
2885 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002886 MediaContentDescription* media_desc =
2887 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2888 ASSERT_TRUE(media_desc);
2889 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002890 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002891 for (VideoCodec& codec : codecs) {
2892 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2893 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002894 }
2895 }
2896 desc->set_codecs(codecs);
2897
Steve Anton6fe1fba2018-12-11 10:15:23 -08002898 std::unique_ptr<SessionDescription> answer =
2899 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002900
Steve Anton64b626b2019-01-28 17:25:26 -08002901 EXPECT_THAT(
2902 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2903 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002904}
2905
2906// Test that RTX will be filtered out in the answer if its associated payload
2907// type doesn't match the local value.
2908TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2909 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002910 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2911 RtpTransceiverDirection::kRecvOnly, kActive,
2912 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002913 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2914 // This creates RTX for H264 in sender.
2915 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2916 f1_.set_video_codecs(f1_codecs);
2917
2918 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2919 // This creates RTX for H263 in receiver.
2920 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2921 f2_.set_video_codecs(f2_codecs);
2922
Steve Anton6fe1fba2018-12-11 10:15:23 -08002923 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002924 ASSERT_TRUE(offer.get() != NULL);
2925 // Associated payload type doesn't match, therefore, RTX codec is removed in
2926 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002927 std::unique_ptr<SessionDescription> answer =
2928 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002929
Steve Anton64b626b2019-01-28 17:25:26 -08002930 EXPECT_THAT(
2931 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2932 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002933}
2934
2935// Test that when multiple RTX codecs are offered, only the matched RTX codec
2936// is added in the answer, and the unsupported RTX codec is filtered out.
2937TEST_F(MediaSessionDescriptionFactoryTest,
2938 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2939 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002940 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2941 RtpTransceiverDirection::kRecvOnly, kActive,
2942 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002943 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2944 // This creates RTX for H264-SVC in sender.
2945 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2946 f1_.set_video_codecs(f1_codecs);
2947
2948 // This creates RTX for H264 in sender.
2949 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2950 f1_.set_video_codecs(f1_codecs);
2951
2952 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2953 // This creates RTX for H264 in receiver.
2954 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2955 f2_.set_video_codecs(f2_codecs);
2956
2957 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2958 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002959 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002960 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002961 std::unique_ptr<SessionDescription> answer =
2962 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002963 const VideoContentDescription* vcd =
2964 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002965 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2966 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2967 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002968
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002969 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002970}
2971
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002972// Test that after one RTX codec has been negotiated, a new offer can attempt
2973// to add another.
2974TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2975 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002976 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2977 RtpTransceiverDirection::kRecvOnly, kActive,
2978 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002979 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2980 // This creates RTX for H264 for the offerer.
2981 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2982 f1_.set_video_codecs(f1_codecs);
2983
Steve Anton6fe1fba2018-12-11 10:15:23 -08002984 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002985 ASSERT_TRUE(offer);
2986 const VideoContentDescription* vcd =
2987 GetFirstVideoContentDescription(offer.get());
2988
2989 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2990 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2991 &expected_codecs);
2992 EXPECT_EQ(expected_codecs, vcd->codecs());
2993
2994 // Now, attempt to add RTX for H264-SVC.
2995 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2996 f1_.set_video_codecs(f1_codecs);
2997
kwiberg31022942016-03-11 14:18:21 -08002998 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002999 f1_.CreateOffer(opts, offer.get()));
3000 ASSERT_TRUE(updated_offer);
3001 vcd = GetFirstVideoContentDescription(updated_offer.get());
3002
3003 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3004 &expected_codecs);
3005 EXPECT_EQ(expected_codecs, vcd->codecs());
3006}
3007
Noah Richards2e7a0982015-05-18 14:02:54 -07003008// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3009// generated for each simulcast ssrc and correctly grouped.
3010TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3011 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003012 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3013 RtpTransceiverDirection::kSendRecv, kActive,
3014 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003015 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003016 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3017 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003018
3019 // Use a single real codec, and then add RTX for it.
3020 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003021 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003022 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
3023 f1_.set_video_codecs(f1_codecs);
3024
3025 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3026 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003027 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003028 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003029 MediaContentDescription* media_desc =
3030 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3031 ASSERT_TRUE(media_desc);
3032 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003033 const StreamParamsVec& streams = desc->streams();
3034 // Single stream.
3035 ASSERT_EQ(1u, streams.size());
3036 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3037 EXPECT_EQ(6u, streams[0].ssrcs.size());
3038 // And should have a SIM group for the simulcast.
3039 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3040 // And a FID group for RTX.
3041 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003042 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003043 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3044 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003045 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003046 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3047 EXPECT_EQ(3u, fid_ssrcs.size());
3048}
3049
brandtr03d5fb12016-11-22 03:37:59 -08003050// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3051// together with a FEC-FR grouping.
3052TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3053 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003054 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3055 RtpTransceiverDirection::kSendRecv, kActive,
3056 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003057 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003058 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3059 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003060
3061 // Use a single real codec, and then add FlexFEC for it.
3062 std::vector<VideoCodec> f1_codecs;
3063 f1_codecs.push_back(VideoCodec(97, "H264"));
3064 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3065 f1_.set_video_codecs(f1_codecs);
3066
3067 // Ensure that the offer has a single FlexFEC ssrc and that
3068 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003069 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003070 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003071 MediaContentDescription* media_desc =
3072 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3073 ASSERT_TRUE(media_desc);
3074 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003075 const StreamParamsVec& streams = desc->streams();
3076 // Single stream.
3077 ASSERT_EQ(1u, streams.size());
3078 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3079 EXPECT_EQ(2u, streams[0].ssrcs.size());
3080 // And should have a FEC-FR group for FlexFEC.
3081 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3082 std::vector<uint32_t> primary_ssrcs;
3083 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3084 ASSERT_EQ(1u, primary_ssrcs.size());
3085 uint32_t flexfec_ssrc;
3086 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3087 EXPECT_NE(flexfec_ssrc, 0u);
3088}
3089
3090// Test that FlexFEC is disabled for simulcast.
3091// TODO(brandtr): Remove this test when we support simulcast, either through
3092// multiple FlexfecSenders, or through multistream protection.
3093TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3094 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003095 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3096 RtpTransceiverDirection::kSendRecv, kActive,
3097 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003098 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003099 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3100 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003101
3102 // Use a single real codec, and then add FlexFEC for it.
3103 std::vector<VideoCodec> f1_codecs;
3104 f1_codecs.push_back(VideoCodec(97, "H264"));
3105 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3106 f1_.set_video_codecs(f1_codecs);
3107
3108 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3109 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003110 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003111 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003112 MediaContentDescription* media_desc =
3113 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3114 ASSERT_TRUE(media_desc);
3115 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003116 const StreamParamsVec& streams = desc->streams();
3117 // Single stream.
3118 ASSERT_EQ(1u, streams.size());
3119 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3120 EXPECT_EQ(3u, streams[0].ssrcs.size());
3121 // And should have a SIM group for the simulcast.
3122 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3123 // And not a FEC-FR group for FlexFEC.
3124 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3125 std::vector<uint32_t> primary_ssrcs;
3126 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3127 EXPECT_EQ(3u, primary_ssrcs.size());
3128 for (uint32_t primary_ssrc : primary_ssrcs) {
3129 uint32_t flexfec_ssrc;
3130 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3131 }
3132}
3133
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003134// Create an updated offer after creating an answer to the original offer and
3135// verify that the RTP header extensions that were part of the original answer
3136// are not changed in the updated offer.
3137TEST_F(MediaSessionDescriptionFactoryTest,
3138 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3139 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003140 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003141
3142 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3143 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3144 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3145 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3146
Steve Anton6fe1fba2018-12-11 10:15:23 -08003147 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3148 std::unique_ptr<SessionDescription> answer =
3149 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003150
Yves Gerey665174f2018-06-19 15:03:05 +02003151 EXPECT_EQ(
3152 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3153 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3154 EXPECT_EQ(
3155 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3156 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003157
kwiberg31022942016-03-11 14:18:21 -08003158 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003159 f2_.CreateOffer(opts, answer.get()));
3160
3161 // The expected RTP header extensions in the new offer are the resulting
3162 // extensions from the first offer/answer exchange plus the extensions only
3163 // |f2_| offer.
3164 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003165 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003166 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3167 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3168 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003169 };
3170
3171 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003172 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003173 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3174 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3175 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003176 };
3177
3178 const AudioContentDescription* updated_acd =
3179 GetFirstAudioContentDescription(updated_offer.get());
3180 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3181 updated_acd->rtp_header_extensions());
3182
3183 const VideoContentDescription* updated_vcd =
3184 GetFirstVideoContentDescription(updated_offer.get());
3185 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3186 updated_vcd->rtp_header_extensions());
3187}
3188
deadbeefa5b273a2015-08-20 17:30:13 -07003189// Verify that if the same RTP extension URI is used for audio and video, the
3190// same ID is used. Also verify that the ID isn't changed when creating an
3191// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003192TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003193 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003194 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003195
3196 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3197 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3198
Steve Anton6fe1fba2018-12-11 10:15:23 -08003199 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003200
3201 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3202 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003203 const RtpExtension kExpectedVideoRtpExtension[] = {
3204 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003205 };
3206
Yves Gerey665174f2018-06-19 15:03:05 +02003207 EXPECT_EQ(
3208 MAKE_VECTOR(kAudioRtpExtension3),
3209 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3210 EXPECT_EQ(
3211 MAKE_VECTOR(kExpectedVideoRtpExtension),
3212 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003213
3214 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003215 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003216 f1_.CreateOffer(opts, offer.get()));
3217
3218 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003219 GetFirstAudioContentDescription(updated_offer.get())
3220 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003221 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003222 GetFirstVideoContentDescription(updated_offer.get())
3223 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003224}
3225
jbauch5869f502017-06-29 12:31:36 -07003226// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3227TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3228 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003229 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003230
3231 f1_.set_enable_encrypted_rtp_header_extensions(true);
3232 f2_.set_enable_encrypted_rtp_header_extensions(true);
3233
3234 f1_.set_audio_rtp_header_extensions(
3235 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3236 f1_.set_video_rtp_header_extensions(
3237 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3238
Steve Anton6fe1fba2018-12-11 10:15:23 -08003239 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003240
3241 // The extensions that are shared between audio and video should use the same
3242 // id.
3243 const RtpExtension kExpectedVideoRtpExtension[] = {
3244 kVideoRtpExtension3ForEncryption[0],
3245 kAudioRtpExtension3ForEncryptionOffer[1],
3246 kAudioRtpExtension3ForEncryptionOffer[2],
3247 };
3248
Yves Gerey665174f2018-06-19 15:03:05 +02003249 EXPECT_EQ(
3250 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3251 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3252 EXPECT_EQ(
3253 MAKE_VECTOR(kExpectedVideoRtpExtension),
3254 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003255
3256 // Nothing should change when creating a new offer
3257 std::unique_ptr<SessionDescription> updated_offer(
3258 f1_.CreateOffer(opts, offer.get()));
3259
3260 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003261 GetFirstAudioContentDescription(updated_offer.get())
3262 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003263 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003264 GetFirstVideoContentDescription(updated_offer.get())
3265 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003266}
3267
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003268TEST(MediaSessionDescription, CopySessionDescription) {
3269 SessionDescription source;
3270 cricket::ContentGroup group(cricket::CN_AUDIO);
3271 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003272 std::unique_ptr<AudioContentDescription> acd =
3273 absl::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003274 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3275 acd->AddLegacyStream(1);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003276 std::unique_ptr<AudioContentDescription> acd_passed =
3277 absl::WrapUnique(acd->Copy());
3278 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp,
3279 std::move(acd_passed));
3280 std::unique_ptr<VideoContentDescription> vcd =
3281 absl::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003282 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3283 vcd->AddLegacyStream(2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003284 std::unique_ptr<VideoContentDescription> vcd_passed =
3285 absl::WrapUnique(vcd->Copy());
3286 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp,
3287 std::move(vcd_passed));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003288
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003289 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003290 ASSERT_TRUE(copy.get() != NULL);
3291 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3292 const ContentInfo* ac = copy->GetContentByName("audio");
3293 const ContentInfo* vc = copy->GetContentByName("video");
3294 ASSERT_TRUE(ac != NULL);
3295 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003296 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003297 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003298 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3299 EXPECT_EQ(1u, acd->first_ssrc());
3300
Steve Anton5adfafd2017-12-20 16:34:00 -08003301 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003302 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003303 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3304 EXPECT_EQ(2u, vcd->first_ssrc());
3305}
3306
3307// The below TestTransportInfoXXX tests create different offers/answers, and
3308// ensure the TransportInfo in the SessionDescription matches what we expect.
3309TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3310 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003311 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3312 RtpTransceiverDirection::kRecvOnly, kActive,
3313 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003314 TestTransportInfo(true, options, false);
3315}
3316
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003317TEST_F(MediaSessionDescriptionFactoryTest,
3318 TestTransportInfoOfferIceRenomination) {
3319 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003320 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3321 RtpTransceiverDirection::kRecvOnly, kActive,
3322 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003323 options.media_description_options[0]
3324 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003325 TestTransportInfo(true, options, false);
3326}
3327
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003328TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3329 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003330 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3331 RtpTransceiverDirection::kRecvOnly, kActive,
3332 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003333 TestTransportInfo(true, options, true);
3334}
3335
3336TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3337 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003338 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3339 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3340 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003341 TestTransportInfo(true, options, false);
3342}
3343
3344TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003345 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003346 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003347 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3348 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3349 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003350 TestTransportInfo(true, options, true);
3351}
3352
3353TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3354 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003355 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3356 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3357 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003358 options.bundle_enabled = true;
3359 TestTransportInfo(true, options, false);
3360}
3361
3362TEST_F(MediaSessionDescriptionFactoryTest,
3363 TestTransportInfoOfferBundleCurrent) {
3364 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003365 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3366 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3367 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003368 options.bundle_enabled = true;
3369 TestTransportInfo(true, options, true);
3370}
3371
3372TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3373 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003374 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3375 RtpTransceiverDirection::kRecvOnly, kActive,
3376 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003377 TestTransportInfo(false, options, false);
3378}
3379
3380TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003381 TestTransportInfoAnswerIceRenomination) {
3382 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003383 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3384 RtpTransceiverDirection::kRecvOnly, kActive,
3385 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003386 options.media_description_options[0]
3387 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003388 TestTransportInfo(false, options, false);
3389}
3390
3391TEST_F(MediaSessionDescriptionFactoryTest,
3392 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003393 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003394 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3395 RtpTransceiverDirection::kRecvOnly, kActive,
3396 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003397 TestTransportInfo(false, options, true);
3398}
3399
3400TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3401 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003402 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3403 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3404 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003405 TestTransportInfo(false, options, false);
3406}
3407
3408TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003409 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003410 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003411 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3412 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3413 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003414 TestTransportInfo(false, options, true);
3415}
3416
3417TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3418 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003419 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3420 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3421 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003422 options.bundle_enabled = true;
3423 TestTransportInfo(false, options, false);
3424}
3425
3426TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003427 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003428 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003429 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3430 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3431 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003432 options.bundle_enabled = true;
3433 TestTransportInfo(false, options, true);
3434}
3435
3436// Create an offer with bundle enabled and verify the crypto parameters are
3437// the common set of the available cryptos.
3438TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3439 TestCryptoWithBundle(true);
3440}
3441
3442// Create an answer with bundle enabled and verify the crypto parameters are
3443// the common set of the available cryptos.
3444TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3445 TestCryptoWithBundle(false);
3446}
3447
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003448// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3449// DTLS is not enabled locally.
3450TEST_F(MediaSessionDescriptionFactoryTest,
3451 TestOfferDtlsSavpfWithoutDtlsFailed) {
3452 f1_.set_secure(SEC_ENABLED);
3453 f2_.set_secure(SEC_ENABLED);
3454 tdf1_.set_secure(SEC_DISABLED);
3455 tdf2_.set_secure(SEC_DISABLED);
3456
Steve Anton6fe1fba2018-12-11 10:15:23 -08003457 std::unique_ptr<SessionDescription> offer =
3458 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003459 ASSERT_TRUE(offer.get() != NULL);
3460 ContentInfo* offer_content = offer->GetContentByName("audio");
3461 ASSERT_TRUE(offer_content != NULL);
3462 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003463 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003464 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3465
Steve Anton6fe1fba2018-12-11 10:15:23 -08003466 std::unique_ptr<SessionDescription> answer =
3467 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003468 ASSERT_TRUE(answer != NULL);
3469 ContentInfo* answer_content = answer->GetContentByName("audio");
3470 ASSERT_TRUE(answer_content != NULL);
3471
3472 ASSERT_TRUE(answer_content->rejected);
3473}
3474
3475// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3476// UDP/TLS/RTP/SAVPF.
3477TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3478 f1_.set_secure(SEC_ENABLED);
3479 f2_.set_secure(SEC_ENABLED);
3480 tdf1_.set_secure(SEC_ENABLED);
3481 tdf2_.set_secure(SEC_ENABLED);
3482
Steve Anton6fe1fba2018-12-11 10:15:23 -08003483 std::unique_ptr<SessionDescription> offer =
3484 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003485 ASSERT_TRUE(offer.get() != NULL);
3486 ContentInfo* offer_content = offer->GetContentByName("audio");
3487 ASSERT_TRUE(offer_content != NULL);
3488 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003489 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003490 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3491
Steve Anton6fe1fba2018-12-11 10:15:23 -08003492 std::unique_ptr<SessionDescription> answer =
3493 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003494 ASSERT_TRUE(answer != NULL);
3495
3496 const ContentInfo* answer_content = answer->GetContentByName("audio");
3497 ASSERT_TRUE(answer_content != NULL);
3498 ASSERT_FALSE(answer_content->rejected);
3499
3500 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003501 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003502 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003503}
3504
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003505// Test that we include both SDES and DTLS in the offer, but only include SDES
3506// in the answer if DTLS isn't negotiated.
3507TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3508 f1_.set_secure(SEC_ENABLED);
3509 f2_.set_secure(SEC_ENABLED);
3510 tdf1_.set_secure(SEC_ENABLED);
3511 tdf2_.set_secure(SEC_DISABLED);
3512 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003513 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003514 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003515 const cricket::MediaContentDescription* audio_media_desc;
3516 const cricket::MediaContentDescription* video_media_desc;
3517 const cricket::TransportDescription* audio_trans_desc;
3518 const cricket::TransportDescription* video_trans_desc;
3519
3520 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003521 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003522 ASSERT_TRUE(offer.get() != NULL);
3523
Steve Antonb1c1de12017-12-21 15:14:30 -08003524 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003525 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003526 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003527 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003528 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003529 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3530
3531 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3532 ASSERT_TRUE(audio_trans_desc != NULL);
3533 video_trans_desc = offer->GetTransportDescriptionByName("video");
3534 ASSERT_TRUE(video_trans_desc != NULL);
3535 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3536 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3537
3538 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003539 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003540 ASSERT_TRUE(answer.get() != NULL);
3541
Steve Antonb1c1de12017-12-21 15:14:30 -08003542 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003543 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003544 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003545 ASSERT_TRUE(video_media_desc != NULL);
3546 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3547 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3548
3549 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3550 ASSERT_TRUE(audio_trans_desc != NULL);
3551 video_trans_desc = answer->GetTransportDescriptionByName("video");
3552 ASSERT_TRUE(video_trans_desc != NULL);
3553 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3554 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3555
3556 // Enable DTLS; the answer should now only have DTLS support.
3557 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003558 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003559 ASSERT_TRUE(answer.get() != NULL);
3560
Steve Antonb1c1de12017-12-21 15:14:30 -08003561 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003562 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003563 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003564 ASSERT_TRUE(video_media_desc != NULL);
3565 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3566 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003567 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3568 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003569
3570 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3571 ASSERT_TRUE(audio_trans_desc != NULL);
3572 video_trans_desc = answer->GetTransportDescriptionByName("video");
3573 ASSERT_TRUE(video_trans_desc != NULL);
3574 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3575 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003576
3577 // Try creating offer again. DTLS enabled now, crypto's should be empty
3578 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003579 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003580 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003581 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003582 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003583 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003584 ASSERT_TRUE(video_media_desc != NULL);
3585 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3586 EXPECT_TRUE(video_media_desc->cryptos().empty());
3587
3588 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3589 ASSERT_TRUE(audio_trans_desc != NULL);
3590 video_trans_desc = offer->GetTransportDescriptionByName("video");
3591 ASSERT_TRUE(video_trans_desc != NULL);
3592 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3593 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003594}
3595
3596// Test that an answer can't be created if cryptos are required but the offer is
3597// unsecure.
3598TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003599 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003600 f1_.set_secure(SEC_DISABLED);
3601 tdf1_.set_secure(SEC_DISABLED);
3602 f2_.set_secure(SEC_REQUIRED);
3603 tdf1_.set_secure(SEC_ENABLED);
3604
Steve Anton6fe1fba2018-12-11 10:15:23 -08003605 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003606 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003607 std::unique_ptr<SessionDescription> answer =
3608 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003609 EXPECT_TRUE(answer.get() == NULL);
3610}
3611
3612// Test that we accept a DTLS offer without SDES and create an appropriate
3613// answer.
3614TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3615 f1_.set_secure(SEC_DISABLED);
3616 f2_.set_secure(SEC_ENABLED);
3617 tdf1_.set_secure(SEC_ENABLED);
3618 tdf2_.set_secure(SEC_ENABLED);
3619 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003620 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3621 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3622 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003623
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003624 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003625 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003626 ASSERT_TRUE(offer.get() != NULL);
3627
3628 const AudioContentDescription* audio_offer =
3629 GetFirstAudioContentDescription(offer.get());
3630 ASSERT_TRUE(audio_offer->cryptos().empty());
3631 const VideoContentDescription* video_offer =
3632 GetFirstVideoContentDescription(offer.get());
3633 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003634 const RtpDataContentDescription* data_offer =
3635 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003636 ASSERT_TRUE(data_offer->cryptos().empty());
3637
3638 const cricket::TransportDescription* audio_offer_trans_desc =
3639 offer->GetTransportDescriptionByName("audio");
3640 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3641 const cricket::TransportDescription* video_offer_trans_desc =
3642 offer->GetTransportDescriptionByName("video");
3643 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3644 const cricket::TransportDescription* data_offer_trans_desc =
3645 offer->GetTransportDescriptionByName("data");
3646 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3647
3648 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003649 std::unique_ptr<SessionDescription> answer =
3650 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003651 ASSERT_TRUE(answer.get() != NULL);
3652
3653 const cricket::TransportDescription* audio_answer_trans_desc =
3654 answer->GetTransportDescriptionByName("audio");
3655 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3656 const cricket::TransportDescription* video_answer_trans_desc =
3657 answer->GetTransportDescriptionByName("video");
3658 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3659 const cricket::TransportDescription* data_answer_trans_desc =
3660 answer->GetTransportDescriptionByName("data");
3661 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3662}
3663
3664// Verifies if vad_enabled option is set to false, CN codecs are not present in
3665// offer or answer.
3666TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3667 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003668 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003669 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003670 ASSERT_TRUE(offer.get() != NULL);
3671 const ContentInfo* audio_content = offer->GetContentByName("audio");
3672 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3673
3674 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003675 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003676 ASSERT_TRUE(offer.get() != NULL);
3677 audio_content = offer->GetContentByName("audio");
3678 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003679 std::unique_ptr<SessionDescription> answer =
3680 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003681 ASSERT_TRUE(answer.get() != NULL);
3682 audio_content = answer->GetContentByName("audio");
3683 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3684}
deadbeef44f08192015-12-15 16:20:09 -08003685
zhihuang1c378ed2017-08-17 14:10:50 -07003686// Test that the generated MIDs match the existing offer.
3687TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003688 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003689 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3690 RtpTransceiverDirection::kRecvOnly, kActive,
3691 &opts);
3692 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3693 RtpTransceiverDirection::kRecvOnly, kActive,
3694 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003695 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003696 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3697 RtpTransceiverDirection::kSendRecv, kActive,
3698 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003699 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003700 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003701 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003702 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003703
deadbeef44f08192015-12-15 16:20:09 -08003704 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3705 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3706 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3707 ASSERT_TRUE(audio_content != nullptr);
3708 ASSERT_TRUE(video_content != nullptr);
3709 ASSERT_TRUE(data_content != nullptr);
3710 EXPECT_EQ("audio_modified", audio_content->name);
3711 EXPECT_EQ("video_modified", video_content->name);
3712 EXPECT_EQ("data_modified", data_content->name);
3713}
zhihuangcf5b37c2016-05-05 11:44:35 -07003714
zhihuang1c378ed2017-08-17 14:10:50 -07003715// The following tests verify that the unified plan SDP is supported.
3716// Test that we can create an offer with multiple media sections of same media
3717// type.
3718TEST_F(MediaSessionDescriptionFactoryTest,
3719 CreateOfferWithMultipleAVMediaSections) {
3720 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003721 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3722 RtpTransceiverDirection::kSendRecv, kActive,
3723 &opts);
3724 AttachSenderToMediaDescriptionOptions(
3725 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003726
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003727 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3728 RtpTransceiverDirection::kSendRecv, kActive,
3729 &opts);
3730 AttachSenderToMediaDescriptionOptions(
3731 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003732
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003733 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3734 RtpTransceiverDirection::kSendRecv, kActive,
3735 &opts);
3736 AttachSenderToMediaDescriptionOptions(
3737 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003738
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003739 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3740 RtpTransceiverDirection::kSendRecv, kActive,
3741 &opts);
3742 AttachSenderToMediaDescriptionOptions(
3743 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003744 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003745 ASSERT_TRUE(offer);
3746
3747 ASSERT_EQ(4u, offer->contents().size());
3748 EXPECT_FALSE(offer->contents()[0].rejected);
3749 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003750 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003751 ASSERT_EQ(1u, acd->streams().size());
3752 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003753 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003754
3755 EXPECT_FALSE(offer->contents()[1].rejected);
3756 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003757 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003758 ASSERT_EQ(1u, vcd->streams().size());
3759 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003760 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003761
3762 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003763 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003764 ASSERT_EQ(1u, acd->streams().size());
3765 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003766 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003767
3768 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003769 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003770 ASSERT_EQ(1u, vcd->streams().size());
3771 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003772 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003773}
3774
3775// Test that we can create an answer with multiple media sections of same media
3776// type.
3777TEST_F(MediaSessionDescriptionFactoryTest,
3778 CreateAnswerWithMultipleAVMediaSections) {
3779 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003780 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3781 RtpTransceiverDirection::kSendRecv, kActive,
3782 &opts);
3783 AttachSenderToMediaDescriptionOptions(
3784 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003785
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003786 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3787 RtpTransceiverDirection::kSendRecv, kActive,
3788 &opts);
3789 AttachSenderToMediaDescriptionOptions(
3790 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003791
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003792 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3793 RtpTransceiverDirection::kSendRecv, kActive,
3794 &opts);
3795 AttachSenderToMediaDescriptionOptions(
3796 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003797
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003798 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3799 RtpTransceiverDirection::kSendRecv, kActive,
3800 &opts);
3801 AttachSenderToMediaDescriptionOptions(
3802 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003803
Steve Anton6fe1fba2018-12-11 10:15:23 -08003804 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003805 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003806 std::unique_ptr<SessionDescription> answer =
3807 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003808
3809 ASSERT_EQ(4u, answer->contents().size());
3810 EXPECT_FALSE(answer->contents()[0].rejected);
3811 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003812 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003813 ASSERT_EQ(1u, acd->streams().size());
3814 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003815 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003816
3817 EXPECT_FALSE(answer->contents()[1].rejected);
3818 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003819 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003820 ASSERT_EQ(1u, vcd->streams().size());
3821 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003822 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003823
3824 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003825 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003826 ASSERT_EQ(1u, acd->streams().size());
3827 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003828 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003829
3830 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003831 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003832 ASSERT_EQ(1u, vcd->streams().size());
3833 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003834 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003835}
3836
3837// Test that the media section will be rejected in offer if the corresponding
3838// MediaDescriptionOptions is stopped by the offerer.
3839TEST_F(MediaSessionDescriptionFactoryTest,
3840 CreateOfferWithMediaSectionStoppedByOfferer) {
3841 // Create an offer with two audio sections and one of them is stopped.
3842 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003843 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3844 RtpTransceiverDirection::kSendRecv, kActive,
3845 &offer_opts);
3846 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3847 RtpTransceiverDirection::kInactive, kStopped,
3848 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003849 std::unique_ptr<SessionDescription> offer =
3850 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003851 ASSERT_TRUE(offer);
3852 ASSERT_EQ(2u, offer->contents().size());
3853 EXPECT_FALSE(offer->contents()[0].rejected);
3854 EXPECT_TRUE(offer->contents()[1].rejected);
3855}
3856
3857// Test that the media section will be rejected in answer if the corresponding
3858// MediaDescriptionOptions is stopped by the offerer.
3859TEST_F(MediaSessionDescriptionFactoryTest,
3860 CreateAnswerWithMediaSectionStoppedByOfferer) {
3861 // Create an offer with two audio sections and one of them is stopped.
3862 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003863 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3864 RtpTransceiverDirection::kSendRecv, kActive,
3865 &offer_opts);
3866 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3867 RtpTransceiverDirection::kInactive, kStopped,
3868 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003869 std::unique_ptr<SessionDescription> offer =
3870 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003871 ASSERT_TRUE(offer);
3872 ASSERT_EQ(2u, offer->contents().size());
3873 EXPECT_FALSE(offer->contents()[0].rejected);
3874 EXPECT_TRUE(offer->contents()[1].rejected);
3875
3876 // Create an answer based on the offer.
3877 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003878 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3879 RtpTransceiverDirection::kSendRecv, kActive,
3880 &answer_opts);
3881 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3882 RtpTransceiverDirection::kSendRecv, kActive,
3883 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003884 std::unique_ptr<SessionDescription> answer =
3885 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003886 ASSERT_EQ(2u, answer->contents().size());
3887 EXPECT_FALSE(answer->contents()[0].rejected);
3888 EXPECT_TRUE(answer->contents()[1].rejected);
3889}
3890
3891// Test that the media section will be rejected in answer if the corresponding
3892// MediaDescriptionOptions is stopped by the answerer.
3893TEST_F(MediaSessionDescriptionFactoryTest,
3894 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3895 // Create an offer with two audio sections.
3896 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003897 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3898 RtpTransceiverDirection::kSendRecv, kActive,
3899 &offer_opts);
3900 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3901 RtpTransceiverDirection::kSendRecv, kActive,
3902 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003903 std::unique_ptr<SessionDescription> offer =
3904 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003905 ASSERT_TRUE(offer);
3906 ASSERT_EQ(2u, offer->contents().size());
3907 ASSERT_FALSE(offer->contents()[0].rejected);
3908 ASSERT_FALSE(offer->contents()[1].rejected);
3909
3910 // The answerer rejects one of the audio sections.
3911 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003912 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3913 RtpTransceiverDirection::kSendRecv, kActive,
3914 &answer_opts);
3915 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3916 RtpTransceiverDirection::kInactive, kStopped,
3917 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003918 std::unique_ptr<SessionDescription> answer =
3919 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003920 ASSERT_EQ(2u, answer->contents().size());
3921 EXPECT_FALSE(answer->contents()[0].rejected);
3922 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003923
3924 // The TransportInfo of the rejected m= section is expected to be added in the
3925 // answer.
3926 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003927}
3928
3929// Test the generated media sections has the same order of the
3930// corresponding MediaDescriptionOptions.
3931TEST_F(MediaSessionDescriptionFactoryTest,
3932 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3933 MediaSessionOptions opts;
3934 // This tests put video section first because normally audio comes first by
3935 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003936 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3937 RtpTransceiverDirection::kSendRecv, kActive,
3938 &opts);
3939 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3940 RtpTransceiverDirection::kSendRecv, kActive,
3941 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003942 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003943
3944 ASSERT_TRUE(offer);
3945 ASSERT_EQ(2u, offer->contents().size());
3946 EXPECT_EQ("video", offer->contents()[0].name);
3947 EXPECT_EQ("audio", offer->contents()[1].name);
3948}
3949
3950// Test that different media sections using the same codec have same payload
3951// type.
3952TEST_F(MediaSessionDescriptionFactoryTest,
3953 PayloadTypesSharedByMediaSectionsOfSameType) {
3954 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003955 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3956 RtpTransceiverDirection::kSendRecv, kActive,
3957 &opts);
3958 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3959 RtpTransceiverDirection::kSendRecv, kActive,
3960 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003961 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003962 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003963 ASSERT_TRUE(offer);
3964 ASSERT_EQ(2u, offer->contents().size());
3965 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003966 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003967 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003968 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003969 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3970 ASSERT_EQ(2u, vcd1->codecs().size());
3971 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3972 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3973 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3974 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3975
3976 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003977 std::unique_ptr<SessionDescription> answer =
3978 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003979 ASSERT_TRUE(answer);
3980 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003981 vcd1 = answer->contents()[0].media_description()->as_video();
3982 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003983 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3984 ASSERT_EQ(1u, vcd1->codecs().size());
3985 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3986 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3987}
3988
3989// Test that the codec preference order per media section is respected in
3990// subsequent offer.
3991TEST_F(MediaSessionDescriptionFactoryTest,
3992 CreateOfferRespectsCodecPreferenceOrder) {
3993 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003994 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3995 RtpTransceiverDirection::kSendRecv, kActive,
3996 &opts);
3997 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3998 RtpTransceiverDirection::kSendRecv, kActive,
3999 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004000 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004001 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004002 ASSERT_TRUE(offer);
4003 ASSERT_EQ(2u, offer->contents().size());
4004 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004005 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004006 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004007 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004008 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4009 EXPECT_EQ(video_codecs, vcd1->codecs());
4010 EXPECT_EQ(video_codecs, vcd2->codecs());
4011
4012 // Change the codec preference of the first video section and create a
4013 // follow-up offer.
4014 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4015 vcd1->set_codecs(video_codecs_reverse);
4016 std::unique_ptr<SessionDescription> updated_offer(
4017 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004018 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4019 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004020 // The video codec preference order should be respected.
4021 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4022 EXPECT_EQ(video_codecs, vcd2->codecs());
4023}
4024
4025// Test that the codec preference order per media section is respected in
4026// the answer.
4027TEST_F(MediaSessionDescriptionFactoryTest,
4028 CreateAnswerRespectsCodecPreferenceOrder) {
4029 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004030 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4031 RtpTransceiverDirection::kSendRecv, kActive,
4032 &opts);
4033 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4034 RtpTransceiverDirection::kSendRecv, kActive,
4035 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004036 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004037 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004038 ASSERT_TRUE(offer);
4039 ASSERT_EQ(2u, offer->contents().size());
4040 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004041 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004042 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004043 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004044 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4045 EXPECT_EQ(video_codecs, vcd1->codecs());
4046 EXPECT_EQ(video_codecs, vcd2->codecs());
4047
4048 // Change the codec preference of the first video section and create an
4049 // answer.
4050 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4051 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004052 std::unique_ptr<SessionDescription> answer =
4053 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004054 vcd1 = answer->contents()[0].media_description()->as_video();
4055 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004056 // The video codec preference order should be respected.
4057 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4058 EXPECT_EQ(video_codecs, vcd2->codecs());
4059}
4060
Zhi Huang6f367472017-11-22 13:20:02 -08004061// Test that when creating an answer, the codecs use local parameters instead of
4062// the remote ones.
4063TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4064 const std::string audio_param_name = "audio_param";
4065 const std::string audio_value1 = "audio_v1";
4066 const std::string audio_value2 = "audio_v2";
4067 const std::string video_param_name = "video_param";
4068 const std::string video_value1 = "video_v1";
4069 const std::string video_value2 = "video_v2";
4070
4071 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4072 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4073 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4074 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4075
4076 // Set the parameters for codecs.
4077 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4078 video_codecs1[0].SetParam(video_param_name, video_value1);
4079 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4080 video_codecs2[0].SetParam(video_param_name, video_value2);
4081
4082 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
4083 f1_.set_video_codecs(video_codecs1);
4084 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
4085 f2_.set_video_codecs(video_codecs2);
4086
4087 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004088 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4089 RtpTransceiverDirection::kSendRecv, kActive,
4090 &opts);
4091 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4092 RtpTransceiverDirection::kSendRecv, kActive,
4093 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004094
Steve Anton6fe1fba2018-12-11 10:15:23 -08004095 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004096 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004097 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4098 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004099 std::string value;
4100 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4101 EXPECT_EQ(audio_value1, value);
4102 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4103 EXPECT_EQ(video_value1, value);
4104
Steve Anton6fe1fba2018-12-11 10:15:23 -08004105 std::unique_ptr<SessionDescription> answer =
4106 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004107 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004108 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4109 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004110 // Use the parameters from the local codecs.
4111 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4112 EXPECT_EQ(audio_value2, value);
4113 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4114 EXPECT_EQ(video_value2, value);
4115}
4116
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004117// Test that matching packetization-mode is part of the criteria for matching
4118// H264 codecs (in addition to profile-level-id). Previously, this was not the
4119// case, so the first H264 codec with the same profile-level-id would match and
4120// the payload type in the answer would be incorrect.
4121// This is a regression test for bugs.webrtc.org/8808
4122TEST_F(MediaSessionDescriptionFactoryTest,
4123 H264MatchCriteriaIncludesPacketizationMode) {
4124 // Create two H264 codecs with the same profile level ID and different
4125 // packetization modes.
4126 VideoCodec h264_pm0(96, "H264");
4127 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4128 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4129 VideoCodec h264_pm1(97, "H264");
4130 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4131 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4132
4133 // Offerer will send both codecs, answerer should choose the one with matching
4134 // packetization mode (and not the first one it sees).
4135 f1_.set_video_codecs({h264_pm0, h264_pm1});
4136 f2_.set_video_codecs({h264_pm1});
4137
4138 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004139 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4140 RtpTransceiverDirection::kSendRecv, kActive,
4141 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004142
Steve Anton6fe1fba2018-12-11 10:15:23 -08004143 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004144 ASSERT_TRUE(offer);
4145
Steve Anton6fe1fba2018-12-11 10:15:23 -08004146 std::unique_ptr<SessionDescription> answer =
4147 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004148 ASSERT_TRUE(answer);
4149
4150 // Answer should have one negotiated codec with packetization-mode=1 using the
4151 // offered payload type.
4152 ASSERT_EQ(1u, answer->contents().size());
4153 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4154 ASSERT_EQ(1u, answer_vcd->codecs().size());
4155 auto answer_codec = answer_vcd->codecs()[0];
4156 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4157}
4158
zhihuangcf5b37c2016-05-05 11:44:35 -07004159class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4160 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004161 MediaProtocolTest()
4162 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004163 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4164 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004165 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004166 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004167 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4168 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004169 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004170 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004171 f1_.set_secure(SEC_ENABLED);
4172 f2_.set_secure(SEC_ENABLED);
4173 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004174 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004175 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004176 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004177 tdf1_.set_secure(SEC_ENABLED);
4178 tdf2_.set_secure(SEC_ENABLED);
4179 }
4180
4181 protected:
4182 MediaSessionDescriptionFactory f1_;
4183 MediaSessionDescriptionFactory f2_;
4184 TransportDescriptionFactory tdf1_;
4185 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004186 UniqueRandomIdGenerator ssrc_generator1;
4187 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004188};
4189
4190TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4191 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004192 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004193 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004194 ASSERT_TRUE(offer.get() != nullptr);
4195 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004196 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004197 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004198 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004199 std::unique_ptr<SessionDescription> answer =
4200 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004201 const ContentInfo* ac = answer->GetContentByName("audio");
4202 const ContentInfo* vc = answer->GetContentByName("video");
4203 ASSERT_TRUE(ac != nullptr);
4204 ASSERT_TRUE(vc != nullptr);
4205 EXPECT_FALSE(ac->rejected); // the offer is accepted
4206 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004207 const AudioContentDescription* acd = ac->media_description()->as_audio();
4208 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004209 EXPECT_EQ(GetParam(), acd->protocol());
4210 EXPECT_EQ(GetParam(), vcd->protocol());
4211}
4212
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004213INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4214 MediaProtocolTest,
4215 ::testing::ValuesIn(kMediaProtocols));
4216INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4217 MediaProtocolTest,
4218 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004219
4220TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4221 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004222 UniqueRandomIdGenerator ssrc_generator;
4223 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004224 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4225 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4226
4227 // The merged list of codecs should contain any send codecs that are also
4228 // nominally in the recieve codecs list. Payload types should be picked from
4229 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4230 // (set to 1). This equals what happens when the send codecs are used in an
4231 // offer and the receive codecs are used in the following answer.
4232 const std::vector<AudioCodec> sendrecv_codecs =
4233 MAKE_VECTOR(kAudioCodecsAnswer);
4234 const std::vector<AudioCodec> no_codecs;
4235
4236 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4237 << "Please don't change shared test data!";
4238 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4239 << "Please don't change shared test data!";
4240 // Alter iLBC send codec to have zero channels, to test that that is handled
4241 // properly.
4242 send_codecs[1].channels = 0;
4243
4244 // Alther iLBC receive codec to be lowercase, to test that case conversions
4245 // are handled properly.
4246 recv_codecs[2].name = "ilbc";
4247
4248 // Test proper merge
4249 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004250 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4251 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4252 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004253
4254 // Test empty send codecs list
4255 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004256 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4257 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4258 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004259
4260 // Test empty recv codecs list
4261 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004262 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4263 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4264 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004265
4266 // Test all empty codec lists
4267 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004268 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4269 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4270 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004271}
4272
Amit Hilbuch77938e62018-12-21 09:23:38 -08004273// Checks that the RID extensions are added to the video RTP header extensions.
4274// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4275// not very well defined, as calling set() and immediately get() will yield
4276// an object that is not semantically equivalent to the set object.
4277TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4278 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004279 UniqueRandomIdGenerator ssrc_generator;
4280 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004281 sf.set_is_unified_plan(true);
4282 cricket::RtpHeaderExtensions extensions;
4283 sf.set_video_rtp_header_extensions(extensions);
4284 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4285 // Check to see that RID extensions were added to the extension list
4286 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004287 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004288 RtpExtension::kMidUri)));
4289 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004290 RtpExtension::kRidUri)));
4291 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4292 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004293}
4294
4295// Checks that the RID extensions are added to the audio RTP header extensions.
4296// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4297// not very well defined, as calling set() and immediately get() will yield
4298// an object that is not semantically equivalent to the set object.
4299TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4300 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004301 UniqueRandomIdGenerator ssrc_generator;
4302 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004303 sf.set_is_unified_plan(true);
4304 cricket::RtpHeaderExtensions extensions;
4305 sf.set_audio_rtp_header_extensions(extensions);
4306 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4307 // Check to see that RID extensions were added to the extension list
4308 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004309 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004310 RtpExtension::kMidUri)));
4311 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004312 RtpExtension::kRidUri)));
4313 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4314 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004315}
4316
ossu075af922016-06-14 03:29:38 -07004317namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004318// Compare the two vectors of codecs ignoring the payload type.
4319template <class Codec>
4320bool CodecsMatch(const std::vector<Codec>& codecs1,
4321 const std::vector<Codec>& codecs2) {
4322 if (codecs1.size() != codecs2.size()) {
4323 return false;
4324 }
4325
4326 for (size_t i = 0; i < codecs1.size(); ++i) {
4327 if (!codecs1[i].Matches(codecs2[i])) {
4328 return false;
4329 }
4330 }
4331 return true;
4332}
4333
Steve Anton4e70a722017-11-28 14:57:10 -08004334void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004335 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004336 UniqueRandomIdGenerator ssrc_generator;
4337 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004338 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4339 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4340 const std::vector<AudioCodec> sendrecv_codecs =
4341 MAKE_VECTOR(kAudioCodecsAnswer);
4342 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004343
4344 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004345 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4346 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004347
Steve Anton4e70a722017-11-28 14:57:10 -08004348 if (direction == RtpTransceiverDirection::kSendRecv ||
4349 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004350 AttachSenderToMediaDescriptionOptions(
4351 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004352 }
ossu075af922016-06-14 03:29:38 -07004353
Steve Anton6fe1fba2018-12-11 10:15:23 -08004354 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004355 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004356 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004357
4358 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004359 // that the codecs put in are right. This happens when we neither want to
4360 // send nor receive audio. The checks are still in place if at some point
4361 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004362 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004363 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004364 // sendrecv and inactive should both present lists as if the channel was
4365 // to be used for sending and receiving. Inactive essentially means it
4366 // might eventually be used anything, but we don't know more at this
4367 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004368 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004369 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004370 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004371 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004372 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004373 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004374 }
4375 }
4376}
4377
4378static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004379 AudioCodec(0, "codec0", 16000, -1, 1),
4380 AudioCodec(1, "codec1", 8000, 13300, 1),
4381 AudioCodec(2, "codec2", 8000, 64000, 1),
4382 AudioCodec(3, "codec3", 8000, 64000, 1),
4383 AudioCodec(4, "codec4", 8000, 0, 2),
4384 AudioCodec(5, "codec5", 32000, 0, 1),
4385 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004386
zhihuang1c378ed2017-08-17 14:10:50 -07004387/* The codecs groups below are chosen as per the matrix below. The objective
4388 * is to have different sets of codecs in the inputs, to get unique sets of
4389 * codecs after negotiation, depending on offer and answer communication
4390 * directions. One-way directions in the offer should either result in the
4391 * opposite direction in the answer, or an inactive answer. Regardless, the
4392 * choice of codecs should be as if the answer contained the opposite
4393 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004394 *
4395 * | Offer | Answer | Result
4396 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4397 * 0 | x - - | - x - | x - - - -
4398 * 1 | x x x | - x - | x - - x -
4399 * 2 | - x - | x - - | - x - - -
4400 * 3 | x x x | x - - | - x x - -
4401 * 4 | - x - | x x x | - x - - -
4402 * 5 | x - - | x x x | x - - - -
4403 * 6 | x x x | x x x | x x x x x
4404 */
4405// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004406static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4407static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004408// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4409// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004410static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4411static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004412// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004413static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4414static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4415static const int kResultSendrecv_SendCodecs[] = {3, 6};
4416static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4417static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004418
4419template <typename T, int IDXS>
4420std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4421 std::vector<T> out;
4422 out.reserve(IDXS);
4423 for (int idx : indices)
4424 out.push_back(array[idx]);
4425
4426 return out;
4427}
4428
Steve Anton4e70a722017-11-28 14:57:10 -08004429void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4430 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004431 bool add_legacy_stream) {
4432 TransportDescriptionFactory offer_tdf;
4433 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004434 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4435 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4436 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004437 offer_factory.set_audio_codecs(
4438 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4439 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4440 answer_factory.set_audio_codecs(
4441 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4442 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4443
ossu075af922016-06-14 03:29:38 -07004444 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004445 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4446 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004447
Steve Anton4e70a722017-11-28 14:57:10 -08004448 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004449 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4450 kAudioTrack1, {kMediaStream1}, 1,
4451 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004452 }
4453
Steve Anton6fe1fba2018-12-11 10:15:23 -08004454 std::unique_ptr<SessionDescription> offer =
4455 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004456 ASSERT_TRUE(offer.get() != NULL);
4457
4458 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004459 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4460 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004461
Steve Anton4e70a722017-11-28 14:57:10 -08004462 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004463 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4464 kAudioTrack1, {kMediaStream1}, 1,
4465 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004466 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004467 std::unique_ptr<SessionDescription> answer =
4468 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004469 const ContentInfo* ac = answer->GetContentByName("audio");
4470
zhihuang1c378ed2017-08-17 14:10:50 -07004471 // If the factory didn't add any audio content to the answer, we cannot
4472 // check that the codecs put in are right. This happens when we neither want
4473 // to send nor receive audio. The checks are still in place if at some point
4474 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004475 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004476 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4477 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004478
ossu075af922016-06-14 03:29:38 -07004479 std::vector<AudioCodec> target_codecs;
4480 // For offers with sendrecv or inactive, we should never reply with more
4481 // codecs than offered, with these codec sets.
4482 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004483 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004484 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4485 kResultSendrecv_SendrecvCodecs);
4486 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004487 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004488 target_codecs =
4489 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004490 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004491 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004492 target_codecs =
4493 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004494 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004495 case RtpTransceiverDirection::kSendRecv:
4496 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004497 target_codecs =
4498 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004499 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004500 target_codecs =
4501 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004502 } else {
4503 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4504 kResultSendrecv_SendrecvCodecs);
4505 }
4506 break;
4507 }
4508
zhihuang1c378ed2017-08-17 14:10:50 -07004509 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004510 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004511 bool first = true;
4512 os << "{";
4513 for (const auto& c : codecs) {
4514 os << (first ? " " : ", ") << c.id;
4515 first = false;
4516 }
4517 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004518 return os.Release();
ossu075af922016-06-14 03:29:38 -07004519 };
4520
4521 EXPECT_TRUE(acd->codecs() == target_codecs)
4522 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004523 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4524 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004525 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004526 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4527 << "; got: "
4528 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004529 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004530 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004531 << "Only inactive offers are allowed to not generate any audio "
4532 "content";
ossu075af922016-06-14 03:29:38 -07004533 }
4534}
brandtr03d5fb12016-11-22 03:37:59 -08004535
4536} // namespace
ossu075af922016-06-14 03:29:38 -07004537
4538class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004539 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004540
4541TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004542 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004543}
4544
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004545INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4546 AudioCodecsOfferTest,
4547 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4548 RtpTransceiverDirection::kRecvOnly,
4549 RtpTransceiverDirection::kSendRecv,
4550 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004551
4552class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004553 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4554 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004555 bool>> {};
ossu075af922016-06-14 03:29:38 -07004556
4557TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004558 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4559 ::testing::get<1>(GetParam()),
4560 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004561}
4562
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004563INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004564 MediaSessionDescriptionFactoryTest,
4565 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004566 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4567 RtpTransceiverDirection::kRecvOnly,
4568 RtpTransceiverDirection::kSendRecv,
4569 RtpTransceiverDirection::kInactive),
4570 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4571 RtpTransceiverDirection::kRecvOnly,
4572 RtpTransceiverDirection::kSendRecv,
4573 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004574 ::testing::Bool()));