blob: b69ded3e1fd357a33ced1fcfdf39bd417a9ee6cf [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Amit Hilbuch77938e62018-12-21 09:23:38 -080011#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080012#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000013#include <string>
14#include <vector>
15
Steve Anton64b626b2019-01-28 17:25:26 -080016#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080017#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "media/base/test_utils.h"
20#include "p2p/base/p2p_constants.h"
21#include "p2p/base/transport_description.h"
22#include "p2p/base/transport_info.h"
23#include "pc/media_session.h"
24#include "pc/rtp_media_utils.h"
25#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/message_digest.h"
30#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020031#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080032#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080033#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034
Yves Gerey665174f2018-06-19 15:03:05 +020035#define ASSERT_CRYPTO(cd, s, cs) \
36 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080037 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038
39typedef std::vector<cricket::Candidate> Candidates;
40
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080041using cricket::AudioCodec;
42using cricket::AudioContentDescription;
43using cricket::ContentInfo;
44using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080045using cricket::GetFirstAudioContent;
46using cricket::GetFirstAudioContentDescription;
47using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020048using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080049using cricket::GetFirstVideoContent;
50using cricket::GetFirstVideoContentDescription;
51using cricket::kAutoBandwidth;
52using cricket::MEDIA_TYPE_AUDIO;
53using cricket::MEDIA_TYPE_DATA;
54using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070056using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080057using cricket::MediaProtocolType;
58using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059using cricket::MediaSessionOptions;
60using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080061using cricket::RidDescription;
62using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020063using cricket::RtpDataCodec;
64using cricket::RtpDataContentDescription;
65using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080066using cricket::SEC_DISABLED;
67using cricket::SEC_ENABLED;
68using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080070using cricket::SimulcastDescription;
71using cricket::SimulcastLayer;
72using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073using cricket::SsrcGroup;
74using cricket::StreamParams;
75using cricket::StreamParamsVec;
76using cricket::TransportDescription;
77using cricket::TransportDescriptionFactory;
78using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080080using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070081using rtc::CS_AEAD_AES_128_GCM;
82using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080083using rtc::CS_AES_CM_128_HMAC_SHA1_32;
84using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080085using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020086using ::testing::Contains;
87using ::testing::Each;
88using ::testing::ElementsAreArray;
89using ::testing::Eq;
90using ::testing::Field;
91using ::testing::IsEmpty;
92using ::testing::IsFalse;
93using ::testing::Ne;
94using ::testing::Not;
95using ::testing::Pointwise;
96using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070097using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080098using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099
100static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700101 AudioCodec(103, "ISAC", 16000, -1, 1),
102 AudioCodec(102, "iLBC", 8000, 13300, 1),
103 AudioCodec(0, "PCMU", 8000, 64000, 1),
104 AudioCodec(8, "PCMA", 8000, 64000, 1),
105 AudioCodec(117, "red", 8000, 0, 1),
106 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107
108static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200109 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700110 AudioCodec(0, "PCMU", 8000, 64000, 1),
111 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112};
113
114static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700115 AudioCodec(102, "iLBC", 8000, 13300, 1),
116 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117};
118
perkj26752742016-10-24 01:21:16 -0700119static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
120 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121
zhihuang1c378ed2017-08-17 14:10:50 -0700122static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
123 VideoCodec(96, "H264-SVC")};
124
perkj26752742016-10-24 01:21:16 -0700125static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
126 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127
perkj26752742016-10-24 01:21:16 -0700128static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000129
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200130static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
131 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200133static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
134 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200136static const RtpDataCodec kDataCodecsAnswer[] = {
137 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138
isheriff6f8d6862016-05-26 11:24:55 -0700139static const RtpExtension kAudioRtpExtension1[] = {
140 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
141 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142};
143
jbauch5869f502017-06-29 12:31:36 -0700144static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
145 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
146 RtpExtension("http://google.com/testing/audio_something", 10),
147 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
148};
149
isheriff6f8d6862016-05-26 11:24:55 -0700150static const RtpExtension kAudioRtpExtension2[] = {
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
152 RtpExtension("http://google.com/testing/audio_something_else", 8),
153 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154};
155
isheriff6f8d6862016-05-26 11:24:55 -0700156static const RtpExtension kAudioRtpExtension3[] = {
157 RtpExtension("http://google.com/testing/audio_something", 2),
158 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700159};
160
jbauch5869f502017-06-29 12:31:36 -0700161static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 // Use RTP extension that supports encryption.
164 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
165};
166
167static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
168 RtpExtension("http://google.com/testing/audio_something", 2),
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
170 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
171};
172
isheriff6f8d6862016-05-26 11:24:55 -0700173static const RtpExtension kAudioRtpExtensionAnswer[] = {
174 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175};
176
jbauch5869f502017-06-29 12:31:36 -0700177static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
178 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
179};
180
isheriff6f8d6862016-05-26 11:24:55 -0700181static const RtpExtension kVideoRtpExtension1[] = {
182 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
183 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000184};
185
jbauch5869f502017-06-29 12:31:36 -0700186static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
188 RtpExtension("http://google.com/testing/video_something", 13),
189 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
190};
191
isheriff6f8d6862016-05-26 11:24:55 -0700192static const RtpExtension kVideoRtpExtension2[] = {
193 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
194 RtpExtension("http://google.com/testing/video_something_else", 14),
195 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000196};
197
isheriff6f8d6862016-05-26 11:24:55 -0700198static const RtpExtension kVideoRtpExtension3[] = {
199 RtpExtension("http://google.com/testing/video_something", 4),
200 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700201};
202
jbauch5869f502017-06-29 12:31:36 -0700203static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
204 RtpExtension("http://google.com/testing/video_something", 4),
205 // Use RTP extension that supports encryption.
206 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
207};
208
isheriff6f8d6862016-05-26 11:24:55 -0700209static const RtpExtension kVideoRtpExtensionAnswer[] = {
210 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211};
212
jbauch5869f502017-06-29 12:31:36 -0700213static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
214 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
215};
216
Johannes Kronce8e8672019-02-22 13:06:44 +0100217static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
218 RtpExtension("http://www.ietf.org/id/"
219 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
220 1),
221};
222
223static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
224 RtpExtension("http://www.ietf.org/id/"
225 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
226 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100227 RtpExtension(
228 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
229 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100230};
231
232static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100233 RtpExtension(
234 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
235 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100236};
237
Peter Boström0c4e06b2015-10-07 12:23:21 +0200238static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
239static const uint32_t kSimSsrc[] = {10, 20, 30};
240static const uint32_t kFec1Ssrc[] = {10, 11};
241static const uint32_t kFec2Ssrc[] = {20, 21};
242static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243
244static const char kMediaStream1[] = "stream_1";
245static const char kMediaStream2[] = "stream_2";
246static const char kVideoTrack1[] = "video_1";
247static const char kVideoTrack2[] = "video_2";
248static const char kAudioTrack1[] = "audio_1";
249static const char kAudioTrack2[] = "audio_2";
250static const char kAudioTrack3[] = "audio_3";
251static const char kDataTrack1[] = "data_1";
252static const char kDataTrack2[] = "data_2";
253static const char kDataTrack3[] = "data_3";
254
zhihuangcf5b37c2016-05-05 11:44:35 -0700255static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
256 "RTP/SAVPF"};
257static const char* kMediaProtocolsDtls[] = {
258 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
259 "UDP/TLS/RTP/SAVP"};
260
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700261// SRTP cipher name negotiated by the tests. This must be updated if the
262// default changes.
263static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
264static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
265
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800266// These constants are used to make the code using "AddMediaDescriptionOptions"
267// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700268static constexpr bool kStopped = true;
269static constexpr bool kActive = false;
270
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000271static bool IsMediaContentOfType(const ContentInfo* content,
272 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800273 RTC_DCHECK(content);
274 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000275}
276
Steve Anton4e70a722017-11-28 14:57:10 -0800277static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800278 RTC_DCHECK(content);
279 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000280}
281
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000282static void AddRtxCodec(const VideoCodec& rtx_codec,
283 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800284 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000285 codecs->push_back(rtx_codec);
286}
287
288template <class T>
289static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
290 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100291 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000292 for (const auto& codec : codecs) {
293 codec_names.push_back(codec.name);
294 }
295 return codec_names;
296}
297
zhihuang1c378ed2017-08-17 14:10:50 -0700298// This is used for test only. MIDs are not the identification of the
299// MediaDescriptionOptions since some end points may not support MID and the SDP
300// may not contain 'mid'.
301std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
302 const std::string& mid,
303 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800304 return absl::c_find_if(
305 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700306 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
307}
308
309std::vector<MediaDescriptionOptions>::const_iterator
310FindFirstMediaDescriptionByMid(const std::string& mid,
311 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800312 return absl::c_find_if(
313 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700314 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700315}
316
317// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800318static void AddMediaDescriptionOptions(MediaType type,
319 const std::string& mid,
320 RtpTransceiverDirection direction,
321 bool stopped,
322 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800323 opts->media_description_options.push_back(
324 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700325}
326
Steve Anton4e70a722017-11-28 14:57:10 -0800327static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700328 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800329 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
330 opts);
331 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
332 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700333}
334
335static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800336 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700337 MediaSessionOptions* opts) {
338 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800339 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700340}
341
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800342static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700343 const std::string& mid,
344 MediaType type,
345 const std::string& track_id,
346 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800347 const std::vector<RidDescription>& rids,
348 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700349 int num_sim_layer,
350 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700351 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
352 switch (type) {
353 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700354 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700355 break;
356 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800357 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
358 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700359 break;
360 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700361 RTC_CHECK(stream_ids.size() == 1U);
362 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700363 break;
364 default:
365 RTC_NOTREACHED();
366 }
367}
368
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800369static void AttachSenderToMediaDescriptionOptions(
370 const std::string& mid,
371 MediaType type,
372 const std::string& track_id,
373 const std::vector<std::string>& stream_ids,
374 int num_sim_layer,
375 MediaSessionOptions* session_options) {
376 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
377 SimulcastLayerList(), num_sim_layer,
378 session_options);
379}
380
zhihuang1c378ed2017-08-17 14:10:50 -0700381static void DetachSenderFromMediaSection(const std::string& mid,
382 const std::string& track_id,
383 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700384 std::vector<cricket::SenderOptions>& sender_options_list =
385 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
386 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800387 absl::c_find_if(sender_options_list,
388 [track_id](const cricket::SenderOptions& sender_options) {
389 return sender_options.track_id == track_id;
390 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700391 RTC_DCHECK(sender_it != sender_options_list.end());
392 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700393}
394
395// Helper function used to create a default MediaSessionOptions for Plan B SDP.
396// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
397static MediaSessionOptions CreatePlanBMediaSessionOptions() {
398 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800399 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
400 RtpTransceiverDirection::kRecvOnly, kActive,
401 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700402 return session_options;
403}
404
405// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
406// was designed for Plan B SDP, where only one audio "m=" section and one video
407// "m=" section could be generated, and ordering couldn't be controlled. Many of
408// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200409class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800411 MediaSessionDescriptionFactoryTest()
412 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700413 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
414 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200416 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700417 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
418 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200420 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200421 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700422 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200423 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700424 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 }
426
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000427 // Create a video StreamParamsVec object with:
428 // - one video stream with 3 simulcast streams and FEC,
429 StreamParamsVec CreateComplexVideoStreamParamsVec() {
430 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
431 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
432 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
433 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
434
435 std::vector<SsrcGroup> ssrc_groups;
436 ssrc_groups.push_back(sim_group);
437 ssrc_groups.push_back(fec_group1);
438 ssrc_groups.push_back(fec_group2);
439 ssrc_groups.push_back(fec_group3);
440
441 StreamParams simulcast_params;
442 simulcast_params.id = kVideoTrack1;
443 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
444 simulcast_params.ssrc_groups = ssrc_groups;
445 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800446 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000447
448 StreamParamsVec video_streams;
449 video_streams.push_back(simulcast_params);
450
451 return video_streams;
452 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453
454 bool CompareCryptoParams(const CryptoParamsVec& c1,
455 const CryptoParamsVec& c2) {
456 if (c1.size() != c2.size())
457 return false;
458 for (size_t i = 0; i < c1.size(); ++i)
459 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
460 c1[i].key_params != c2[i].key_params ||
461 c1[i].session_params != c2[i].session_params)
462 return false;
463 return true;
464 }
465
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700466 // Returns true if the transport info contains "renomination" as an
467 // ICE option.
468 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800469 return absl::c_linear_search(transport_info->description.transport_options,
470 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700471 }
472
zhihuang1c378ed2017-08-17 14:10:50 -0700473 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700474 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475 bool has_current_desc) {
476 const std::string current_audio_ufrag = "current_audio_ufrag";
477 const std::string current_audio_pwd = "current_audio_pwd";
478 const std::string current_video_ufrag = "current_video_ufrag";
479 const std::string current_video_pwd = "current_video_pwd";
480 const std::string current_data_ufrag = "current_data_ufrag";
481 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800482 std::unique_ptr<SessionDescription> current_desc;
483 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800485 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800486 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200487 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800488 TransportDescription(current_audio_ufrag, current_audio_pwd)));
489 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200490 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800491 TransportDescription(current_video_ufrag, current_video_pwd)));
492 current_desc->AddTransportInfo(TransportInfo(
493 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000494 }
495 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800496 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497 } else {
kwiberg31022942016-03-11 14:18:21 -0800498 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800499 offer = f1_.CreateOffer(options, NULL);
500 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 }
502 ASSERT_TRUE(desc.get() != NULL);
503 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000504 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 EXPECT_TRUE(ti_audio != NULL);
506 if (has_current_desc) {
507 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
508 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
509 } else {
510 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
511 ti_audio->description.ice_ufrag.size());
512 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
513 ti_audio->description.ice_pwd.size());
514 }
zhihuang1c378ed2017-08-17 14:10:50 -0700515 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700516 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700517 EXPECT_EQ(
518 media_desc_options_it->transport_options.enable_ice_renomination,
519 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520
521 } else {
522 EXPECT_TRUE(ti_audio == NULL);
523 }
524 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000525 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 EXPECT_TRUE(ti_video != NULL);
527 if (options.bundle_enabled) {
528 EXPECT_EQ(ti_audio->description.ice_ufrag,
529 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200530 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 } else {
532 if (has_current_desc) {
533 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
534 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
535 } else {
536 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
537 ti_video->description.ice_ufrag.size());
538 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
539 ti_video->description.ice_pwd.size());
540 }
541 }
zhihuang1c378ed2017-08-17 14:10:50 -0700542 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700543 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700544 EXPECT_EQ(
545 media_desc_options_it->transport_options.enable_ice_renomination,
546 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 } else {
548 EXPECT_TRUE(ti_video == NULL);
549 }
550 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
551 if (options.has_data()) {
552 EXPECT_TRUE(ti_data != NULL);
553 if (options.bundle_enabled) {
554 EXPECT_EQ(ti_audio->description.ice_ufrag,
555 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200556 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 } else {
558 if (has_current_desc) {
559 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
560 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
561 } else {
562 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
563 ti_data->description.ice_ufrag.size());
564 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
565 ti_data->description.ice_pwd.size());
566 }
567 }
zhihuang1c378ed2017-08-17 14:10:50 -0700568 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700569 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700570 EXPECT_EQ(
571 media_desc_options_it->transport_options.enable_ice_renomination,
572 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700573
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 } else {
575 EXPECT_TRUE(ti_video == NULL);
576 }
577 }
578
579 void TestCryptoWithBundle(bool offer) {
580 f1_.set_secure(SEC_ENABLED);
581 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800582 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
583 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
584 &options);
kwiberg31022942016-03-11 14:18:21 -0800585 std::unique_ptr<SessionDescription> ref_desc;
586 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 if (offer) {
588 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800589 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800591 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 } else {
593 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800594 ref_desc = f1_.CreateOffer(options, NULL);
595 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800597 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800599 desc->GetContentDescriptionByName("audio");
600 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800602 desc->GetContentDescriptionByName("video");
603 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
605 video_media_desc->cryptos()));
606 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800607 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 audio_media_desc->cryptos()[0].cipher_suite);
609
610 // Verify the selected crypto is one from the reference audio
611 // media content.
612 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800613 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 bool found = false;
615 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
616 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200617 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000618 found = true;
619 break;
620 }
621 }
622 EXPECT_TRUE(found);
623 }
624
625 // This test that the audio and video media direction is set to
626 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700627 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800629 RtpTransceiverDirection direction_in_offer,
630 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700631 MediaSessionOptions offer_opts;
632 AddAudioVideoSections(direction_in_offer, &offer_opts);
633
Steve Anton6fe1fba2018-12-11 10:15:23 -0800634 std::unique_ptr<SessionDescription> offer =
635 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700637 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700639 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641
zhihuang1c378ed2017-08-17 14:10:50 -0700642 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800643 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800644 std::unique_ptr<SessionDescription> answer =
645 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646 const AudioContentDescription* acd_answer =
647 GetFirstAudioContentDescription(answer.get());
648 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
649 const VideoContentDescription* vcd_answer =
650 GetFirstVideoContentDescription(answer.get());
651 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
652 }
653
654 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800655 RTC_DCHECK(content);
656 RTC_CHECK(content->media_description());
657 const cricket::AudioContentDescription* audio_desc =
658 content->media_description()->as_audio();
659 RTC_CHECK(audio_desc);
660 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
661 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800663 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 }
665 return true;
666 }
667
jbauchcb560652016-08-04 05:20:32 -0700668 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
669 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800670 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700671 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700672
jbauchcb560652016-08-04 05:20:32 -0700673 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800674 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700675 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700676
jbauchcb560652016-08-04 05:20:32 -0700677 f1_.set_secure(SEC_ENABLED);
678 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800679 std::unique_ptr<SessionDescription> offer =
680 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700681 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800682 std::unique_ptr<SessionDescription> answer =
683 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700684 const ContentInfo* ac = answer->GetContentByName("audio");
685 const ContentInfo* vc = answer->GetContentByName("video");
686 ASSERT_TRUE(ac != NULL);
687 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800688 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
689 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800690 const AudioContentDescription* acd = ac->media_description()->as_audio();
691 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700692 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800693 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700694 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700695 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700696 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
697 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700698 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700699 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700700 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700701 }
702 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800703 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200704 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
705 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700706 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700707 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700708 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700709 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700710 }
Steve Antone38a5a12018-11-21 16:05:15 -0800711 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700712 }
713
Johannes Kronce8e8672019-02-22 13:06:44 +0100714 void TestTransportSequenceNumberNegotiation(
715 const cricket::RtpHeaderExtensions& local,
716 const cricket::RtpHeaderExtensions& offered,
717 const cricket::RtpHeaderExtensions& expectedAnswer) {
718 MediaSessionOptions opts;
719 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
720 f1_.set_audio_rtp_header_extensions(offered);
721 f1_.set_video_rtp_header_extensions(offered);
722 f2_.set_audio_rtp_header_extensions(local);
723 f2_.set_video_rtp_header_extensions(local);
724
725 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
726 ASSERT_TRUE(offer.get() != NULL);
727 std::unique_ptr<SessionDescription> answer =
728 f2_.CreateAnswer(offer.get(), opts, NULL);
729
730 EXPECT_EQ(
731 expectedAnswer,
732 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
733 EXPECT_EQ(
734 expectedAnswer,
735 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
736 }
737
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800739 UniqueRandomIdGenerator ssrc_generator1;
740 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 MediaSessionDescriptionFactory f1_;
742 MediaSessionDescriptionFactory f2_;
743 TransportDescriptionFactory tdf1_;
744 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745};
746
747// Create a typical audio offer, and ensure it matches what we expect.
748TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
749 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800750 std::unique_ptr<SessionDescription> offer =
751 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752 ASSERT_TRUE(offer.get() != NULL);
753 const ContentInfo* ac = offer->GetContentByName("audio");
754 const ContentInfo* vc = offer->GetContentByName("video");
755 ASSERT_TRUE(ac != NULL);
756 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800757 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800758 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700760 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700761 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000762 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
763 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700764 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800765 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766}
767
768// Create a typical video offer, and ensure it matches what we expect.
769TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
770 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800771 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800773 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774 ASSERT_TRUE(offer.get() != NULL);
775 const ContentInfo* ac = offer->GetContentByName("audio");
776 const ContentInfo* vc = offer->GetContentByName("video");
777 ASSERT_TRUE(ac != NULL);
778 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800779 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
780 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800781 const AudioContentDescription* acd = ac->media_description()->as_audio();
782 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700784 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700785 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
787 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700788 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800789 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
791 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700792 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
794 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700795 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800796 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797}
798
799// Test creating an offer with bundle where the Codecs have the same dynamic
800// RTP playlod type. The test verifies that the offer don't contain the
801// duplicate RTP payload types.
802TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
803 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700804 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200805 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
807 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
808
809 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800810 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
811 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800813 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 const VideoContentDescription* vcd =
815 GetFirstVideoContentDescription(offer.get());
816 const AudioContentDescription* acd =
817 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200818 const RtpDataContentDescription* dcd =
819 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 ASSERT_TRUE(NULL != vcd);
821 ASSERT_TRUE(NULL != acd);
822 ASSERT_TRUE(NULL != dcd);
823 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
824 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
825 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
826 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
827 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
828 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
829}
830
zhihuang1c378ed2017-08-17 14:10:50 -0700831// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832// after an audio only session has been negotiated.
833TEST_F(MediaSessionDescriptionFactoryTest,
834 TestCreateUpdatedVideoOfferWithBundle) {
835 f1_.set_secure(SEC_ENABLED);
836 f2_.set_secure(SEC_ENABLED);
837 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800838 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
839 RtpTransceiverDirection::kRecvOnly, kActive,
840 &opts);
841 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
842 RtpTransceiverDirection::kInactive, kStopped,
843 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000844 opts.data_channel_type = cricket::DCT_NONE;
845 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800846 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
847 std::unique_ptr<SessionDescription> answer =
848 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849
850 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800851 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
852 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
853 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800855 std::unique_ptr<SessionDescription> updated_offer(
856 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857
858 const AudioContentDescription* acd =
859 GetFirstAudioContentDescription(updated_offer.get());
860 const VideoContentDescription* vcd =
861 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200862 const RtpDataContentDescription* dcd =
863 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 EXPECT_TRUE(NULL != vcd);
865 EXPECT_TRUE(NULL != acd);
866 EXPECT_TRUE(NULL != dcd);
867
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700868 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800869 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700870 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800871 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700872 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800873 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874}
deadbeef44f08192015-12-15 16:20:09 -0800875
wu@webrtc.org78187522013-10-07 23:32:02 +0000876// Create a RTP data offer, and ensure it matches what we expect.
877TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000878 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800879 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
880 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800882 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 ASSERT_TRUE(offer.get() != NULL);
884 const ContentInfo* ac = offer->GetContentByName("audio");
885 const ContentInfo* dc = offer->GetContentByName("data");
886 ASSERT_TRUE(ac != NULL);
887 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800888 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
889 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800890 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200891 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700893 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700894 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000895 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
896 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700897 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800898 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200900 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700901 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200903 dcd->bandwidth()); // default bandwidth (auto)
904 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700905 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800906 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907}
908
wu@webrtc.org78187522013-10-07 23:32:02 +0000909// Create an SCTP data offer with bundle without error.
910TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
911 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000912 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800913 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000914 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800915 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000916 EXPECT_TRUE(offer.get() != NULL);
917 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
918}
919
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000920// Test creating an sctp data channel from an already generated offer.
921TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
922 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000923 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800924 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000925 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800926 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000927 ASSERT_TRUE(offer1.get() != NULL);
928 const ContentInfo* data = offer1->GetContentByName("data");
929 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800930 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000931
932 // Now set data_channel_type to 'none' (default) and make sure that the
933 // datachannel type that gets generated from the previous offer, is of the
934 // same type.
935 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800936 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000937 f1_.CreateOffer(opts, offer1.get()));
938 data = offer2->GetContentByName("data");
939 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800940 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000941}
942
Steve Anton2bed3972019-01-04 17:04:30 -0800943// Test that if BUNDLE is enabled and all media sections are rejected then the
944// BUNDLE group is not present in the re-offer.
945TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
946 MediaSessionOptions opts;
947 opts.bundle_enabled = true;
948 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
949 RtpTransceiverDirection::kSendRecv, kActive,
950 &opts);
951 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
952
953 opts.media_description_options[0].stopped = true;
954 std::unique_ptr<SessionDescription> reoffer =
955 f1_.CreateOffer(opts, offer.get());
956
957 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
958}
959
960// Test that if BUNDLE is enabled and the remote re-offer does not include a
961// BUNDLE group since all media sections are rejected, then the re-answer also
962// does not include a BUNDLE group.
963TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
964 MediaSessionOptions opts;
965 opts.bundle_enabled = true;
966 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
967 RtpTransceiverDirection::kSendRecv, kActive,
968 &opts);
969 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
970 std::unique_ptr<SessionDescription> answer =
971 f2_.CreateAnswer(offer.get(), opts, nullptr);
972
973 opts.media_description_options[0].stopped = true;
974 std::unique_ptr<SessionDescription> reoffer =
975 f1_.CreateOffer(opts, offer.get());
976 std::unique_ptr<SessionDescription> reanswer =
977 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
978
979 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
980}
981
982// Test that if BUNDLE is enabled and the previous offerer-tagged media section
983// was rejected then the new offerer-tagged media section is the non-rejected
984// media section.
985TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
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
993 // Reject the audio m= section and add a video m= section.
994 opts.media_description_options[0].stopped = true;
995 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
996 RtpTransceiverDirection::kSendRecv, kActive,
997 &opts);
998 std::unique_ptr<SessionDescription> reoffer =
999 f1_.CreateOffer(opts, offer.get());
1000
1001 const cricket::ContentGroup* bundle_group =
1002 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1003 ASSERT_TRUE(bundle_group);
1004 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1005 EXPECT_TRUE(bundle_group->HasContentName("video"));
1006}
1007
1008// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1009// was rejected and a new media section is added, then the re-answer BUNDLE
1010// group will contain only the non-rejected media section.
1011TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1012 MediaSessionOptions opts;
1013 opts.bundle_enabled = true;
1014 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1015 RtpTransceiverDirection::kSendRecv, kActive,
1016 &opts);
1017 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1018 std::unique_ptr<SessionDescription> answer =
1019 f2_.CreateAnswer(offer.get(), opts, nullptr);
1020
1021 // Reject the audio m= section and add a video m= section.
1022 opts.media_description_options[0].stopped = true;
1023 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1024 RtpTransceiverDirection::kSendRecv, kActive,
1025 &opts);
1026 std::unique_ptr<SessionDescription> reoffer =
1027 f1_.CreateOffer(opts, offer.get());
1028 std::unique_ptr<SessionDescription> reanswer =
1029 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1030
1031 const cricket::ContentGroup* bundle_group =
1032 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1033 ASSERT_TRUE(bundle_group);
1034 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1035 EXPECT_TRUE(bundle_group->HasContentName("video"));
1036}
1037
1038// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1039// and there is still a non-rejected media section that was in the initial
1040// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1041// media section.
1042TEST_F(MediaSessionDescriptionFactoryTest,
1043 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1044 MediaSessionOptions opts;
1045 opts.bundle_enabled = true;
1046 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1047 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1048 std::unique_ptr<SessionDescription> answer =
1049 f2_.CreateAnswer(offer.get(), opts, nullptr);
1050
1051 // Reject the audio m= section.
1052 opts.media_description_options[0].stopped = true;
1053 std::unique_ptr<SessionDescription> reoffer =
1054 f1_.CreateOffer(opts, offer.get());
1055
1056 const TransportDescription* offer_tagged =
1057 offer->GetTransportDescriptionByName("audio");
1058 ASSERT_TRUE(offer_tagged);
1059 const TransportDescription* reoffer_tagged =
1060 reoffer->GetTransportDescriptionByName("video");
1061 ASSERT_TRUE(reoffer_tagged);
1062 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1063 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1064}
1065
1066// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1067// and there is still a non-rejected media section that was in the initial
1068// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1069// media section.
1070TEST_F(MediaSessionDescriptionFactoryTest,
1071 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1072 MediaSessionOptions opts;
1073 opts.bundle_enabled = true;
1074 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1075 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1076 std::unique_ptr<SessionDescription> answer =
1077 f2_.CreateAnswer(offer.get(), opts, nullptr);
1078
1079 // Reject the audio m= section.
1080 opts.media_description_options[0].stopped = true;
1081 std::unique_ptr<SessionDescription> reoffer =
1082 f1_.CreateOffer(opts, offer.get());
1083 std::unique_ptr<SessionDescription> reanswer =
1084 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1085
1086 const TransportDescription* answer_tagged =
1087 answer->GetTransportDescriptionByName("audio");
1088 ASSERT_TRUE(answer_tagged);
1089 const TransportDescription* reanswer_tagged =
1090 reanswer->GetTransportDescriptionByName("video");
1091 ASSERT_TRUE(reanswer_tagged);
1092 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1093 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1094}
1095
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001096// Create an audio, video offer without legacy StreamParams.
1097TEST_F(MediaSessionDescriptionFactoryTest,
1098 TestCreateOfferWithoutLegacyStreams) {
1099 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001100 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001101 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001102 ASSERT_TRUE(offer.get() != NULL);
1103 const ContentInfo* ac = offer->GetContentByName("audio");
1104 const ContentInfo* vc = offer->GetContentByName("video");
1105 ASSERT_TRUE(ac != NULL);
1106 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001107 const AudioContentDescription* acd = ac->media_description()->as_audio();
1108 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001109
Yves Gerey665174f2018-06-19 15:03:05 +02001110 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1111 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001112}
1113
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001114// Creates an audio+video sendonly offer.
1115TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001116 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001117 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001118 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1119 {kMediaStream1}, 1, &opts);
1120 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1121 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001122
Steve Anton6fe1fba2018-12-11 10:15:23 -08001123 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001124 ASSERT_TRUE(offer.get() != NULL);
1125 EXPECT_EQ(2u, offer->contents().size());
1126 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1127 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1128
Steve Anton4e70a722017-11-28 14:57:10 -08001129 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1130 GetMediaDirection(&offer->contents()[0]));
1131 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1132 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001133}
1134
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001135// Verifies that the order of the media contents in the current
1136// SessionDescription is preserved in the new SessionDescription.
1137TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1138 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001139 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001140
kwiberg31022942016-03-11 14:18:21 -08001141 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001142 ASSERT_TRUE(offer1.get() != NULL);
1143 EXPECT_EQ(1u, offer1->contents().size());
1144 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1145
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001146 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1147 RtpTransceiverDirection::kRecvOnly, kActive,
1148 &opts);
kwiberg31022942016-03-11 14:18:21 -08001149 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001150 f1_.CreateOffer(opts, offer1.get()));
1151 ASSERT_TRUE(offer2.get() != NULL);
1152 EXPECT_EQ(2u, offer2->contents().size());
1153 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1154 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1155
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001156 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1157 RtpTransceiverDirection::kRecvOnly, kActive,
1158 &opts);
kwiberg31022942016-03-11 14:18:21 -08001159 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001160 f1_.CreateOffer(opts, offer2.get()));
1161 ASSERT_TRUE(offer3.get() != NULL);
1162 EXPECT_EQ(3u, offer3->contents().size());
1163 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1164 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1165 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001166}
1167
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001168// Create a typical audio answer, and ensure it matches what we expect.
1169TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1170 f1_.set_secure(SEC_ENABLED);
1171 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001172 std::unique_ptr<SessionDescription> offer =
1173 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001174 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001175 std::unique_ptr<SessionDescription> answer =
1176 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177 const ContentInfo* ac = answer->GetContentByName("audio");
1178 const ContentInfo* vc = answer->GetContentByName("video");
1179 ASSERT_TRUE(ac != NULL);
1180 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001181 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001182 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001184 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001185 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001186 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1187 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001188 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001189 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190}
1191
jbauchcb560652016-08-04 05:20:32 -07001192// Create a typical audio answer with GCM ciphers enabled, and ensure it
1193// matches what we expect.
1194TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1195 f1_.set_secure(SEC_ENABLED);
1196 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001197 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001198 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001199 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001200 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001201 std::unique_ptr<SessionDescription> answer =
1202 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001203 const ContentInfo* ac = answer->GetContentByName("audio");
1204 const ContentInfo* vc = answer->GetContentByName("video");
1205 ASSERT_TRUE(ac != NULL);
1206 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001207 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001208 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001209 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001210 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001211 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001212 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1213 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001214 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001215 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001216}
1217
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218// Create a typical video answer, and ensure it matches what we expect.
1219TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1220 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001221 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 f1_.set_secure(SEC_ENABLED);
1223 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001224 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001226 std::unique_ptr<SessionDescription> answer =
1227 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228 const ContentInfo* ac = answer->GetContentByName("audio");
1229 const ContentInfo* vc = answer->GetContentByName("video");
1230 ASSERT_TRUE(ac != NULL);
1231 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001232 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1233 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001234 const AudioContentDescription* acd = ac->media_description()->as_audio();
1235 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001236 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001237 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001239 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001241 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001243 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001244 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1245 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001246 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001247 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248}
1249
jbauchcb560652016-08-04 05:20:32 -07001250// Create a typical video answer with GCM ciphers enabled, and ensure it
1251// matches what we expect.
1252TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1253 TestVideoGcmCipher(true, true);
1254}
1255
1256// Create a typical video answer with GCM ciphers enabled for the offer only,
1257// and ensure it matches what we expect.
1258TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1259 TestVideoGcmCipher(true, false);
1260}
1261
1262// Create a typical video answer with GCM ciphers enabled for the answer only,
1263// and ensure it matches what we expect.
1264TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1265 TestVideoGcmCipher(false, true);
1266}
1267
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001269 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001270 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 f1_.set_secure(SEC_ENABLED);
1272 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001273 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001275 std::unique_ptr<SessionDescription> answer =
1276 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001277 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001278 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001279 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001280 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001281 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1282 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001283 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001284 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001285 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001286 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001288 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001290 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001291 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001292 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001293 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001294 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001295 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001296 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297}
1298
jbauchcb560652016-08-04 05:20:32 -07001299TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001300 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001301 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001302 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001303 f1_.set_secure(SEC_ENABLED);
1304 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001305 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001306 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001307 std::unique_ptr<SessionDescription> answer =
1308 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001309 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001310 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001311 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001312 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001313 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1314 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001315 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001316 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001317 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001318 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001319 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001320 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001321 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001322 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001323 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001324 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001325 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001326 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001327 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001328 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001329}
1330
1331// The use_sctpmap flag should be set in a DataContentDescription by default.
1332// The answer's use_sctpmap flag should match the offer's.
1333TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1334 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001335 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001336 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001337 ASSERT_TRUE(offer.get() != NULL);
1338 ContentInfo* dc_offer = offer->GetContentByName("data");
1339 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001340 SctpDataContentDescription* dcd_offer =
1341 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001342 EXPECT_TRUE(dcd_offer->use_sctpmap());
1343
Steve Anton6fe1fba2018-12-11 10:15:23 -08001344 std::unique_ptr<SessionDescription> answer =
1345 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001346 const ContentInfo* dc_answer = answer->GetContentByName("data");
1347 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001348 const SctpDataContentDescription* dcd_answer =
1349 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001350 EXPECT_TRUE(dcd_answer->use_sctpmap());
1351}
1352
1353// The answer's use_sctpmap flag should match the offer's.
1354TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1355 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001356 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001357 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001358 ASSERT_TRUE(offer.get() != NULL);
1359 ContentInfo* dc_offer = offer->GetContentByName("data");
1360 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001361 SctpDataContentDescription* dcd_offer =
1362 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001363 dcd_offer->set_use_sctpmap(false);
1364
Steve Anton6fe1fba2018-12-11 10:15:23 -08001365 std::unique_ptr<SessionDescription> answer =
1366 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001367 const ContentInfo* dc_answer = answer->GetContentByName("data");
1368 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001369 const SctpDataContentDescription* dcd_answer =
1370 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001371 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001372}
1373
deadbeef8b7e9ad2017-05-25 09:38:55 -07001374// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1375// and "TCP/DTLS/SCTP" offers.
1376TEST_F(MediaSessionDescriptionFactoryTest,
1377 TestCreateDataAnswerToDifferentOfferedProtos) {
1378 // Need to enable DTLS offer/answer generation (disabled by default in this
1379 // test).
1380 f1_.set_secure(SEC_ENABLED);
1381 f2_.set_secure(SEC_ENABLED);
1382 tdf1_.set_secure(SEC_ENABLED);
1383 tdf2_.set_secure(SEC_ENABLED);
1384
1385 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001386 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001387 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001388 ASSERT_TRUE(offer.get() != nullptr);
1389 ContentInfo* dc_offer = offer->GetContentByName("data");
1390 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001391 SctpDataContentDescription* dcd_offer =
1392 dc_offer->media_description()->as_sctp();
1393 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001394
1395 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1396 "TCP/DTLS/SCTP"};
1397 for (const std::string& proto : protos) {
1398 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001399 std::unique_ptr<SessionDescription> answer =
1400 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001401 const ContentInfo* dc_answer = answer->GetContentByName("data");
1402 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001403 const SctpDataContentDescription* dcd_answer =
1404 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001405 EXPECT_FALSE(dc_answer->rejected);
1406 EXPECT_EQ(proto, dcd_answer->protocol());
1407 }
1408}
1409
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001410// Verifies that the order of the media contents in the offer is preserved in
1411// the answer.
1412TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1413 MediaSessionOptions opts;
1414
1415 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001416 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001417 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001418 ASSERT_TRUE(offer1.get() != NULL);
1419
1420 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001421 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1422 RtpTransceiverDirection::kRecvOnly, kActive,
1423 &opts);
kwiberg31022942016-03-11 14:18:21 -08001424 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001425 f1_.CreateOffer(opts, offer1.get()));
1426 ASSERT_TRUE(offer2.get() != NULL);
1427
1428 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001429 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1430 RtpTransceiverDirection::kRecvOnly, kActive,
1431 &opts);
kwiberg31022942016-03-11 14:18:21 -08001432 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001433 f1_.CreateOffer(opts, offer2.get()));
1434 ASSERT_TRUE(offer3.get() != NULL);
1435
Steve Anton6fe1fba2018-12-11 10:15:23 -08001436 std::unique_ptr<SessionDescription> answer =
1437 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001438 ASSERT_TRUE(answer.get() != NULL);
1439 EXPECT_EQ(3u, answer->contents().size());
1440 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1441 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1442 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1443}
1444
ossu075af922016-06-14 03:29:38 -07001445// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1446// answerer settings.
1447
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001448// This test that the media direction is set to send/receive in an answer if
1449// the offer is send receive.
1450TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001451 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1452 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001453}
1454
1455// This test that the media direction is set to receive only in an answer if
1456// the offer is send only.
1457TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001458 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1459 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001460}
1461
1462// This test that the media direction is set to send only in an answer if
1463// the offer is recv only.
1464TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001465 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1466 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001467}
1468
1469// This test that the media direction is set to inactive in an answer if
1470// the offer is inactive.
1471TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001472 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1473 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001474}
1475
1476// Test that a data content with an unknown protocol is rejected in an answer.
1477TEST_F(MediaSessionDescriptionFactoryTest,
1478 CreateDataAnswerToOfferWithUnknownProtocol) {
1479 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001480 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001481 f1_.set_secure(SEC_ENABLED);
1482 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001483 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001484 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001485 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001486 RtpDataContentDescription* dcd_offer =
1487 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001488 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001489 // Offer must be acceptable as an RTP protocol in order to be set.
1490 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001491 dcd_offer->set_protocol(protocol);
1492
Steve Anton6fe1fba2018-12-11 10:15:23 -08001493 std::unique_ptr<SessionDescription> answer =
1494 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001495
1496 const ContentInfo* dc_answer = answer->GetContentByName("data");
1497 ASSERT_TRUE(dc_answer != NULL);
1498 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001499 const RtpDataContentDescription* dcd_answer =
1500 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001501 ASSERT_TRUE(dcd_answer != NULL);
1502 EXPECT_EQ(protocol, dcd_answer->protocol());
1503}
1504
1505// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1506TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001507 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001508 f1_.set_secure(SEC_DISABLED);
1509 f2_.set_secure(SEC_DISABLED);
1510 tdf1_.set_secure(SEC_DISABLED);
1511 tdf2_.set_secure(SEC_DISABLED);
1512
Steve Anton6fe1fba2018-12-11 10:15:23 -08001513 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001514 const AudioContentDescription* offer_acd =
1515 GetFirstAudioContentDescription(offer.get());
1516 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001517 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001518
Steve Anton6fe1fba2018-12-11 10:15:23 -08001519 std::unique_ptr<SessionDescription> answer =
1520 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001521
1522 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1523 ASSERT_TRUE(ac_answer != NULL);
1524 EXPECT_FALSE(ac_answer->rejected);
1525
1526 const AudioContentDescription* answer_acd =
1527 GetFirstAudioContentDescription(answer.get());
1528 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001529 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001530}
1531
1532// Create a video offer and answer and ensure the RTP header extensions
1533// matches what we expect.
1534TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1535 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001536 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1538 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1539 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1540 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1541
Steve Anton6fe1fba2018-12-11 10:15:23 -08001542 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001543 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001544 std::unique_ptr<SessionDescription> answer =
1545 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001546
Yves Gerey665174f2018-06-19 15:03:05 +02001547 EXPECT_EQ(
1548 MAKE_VECTOR(kAudioRtpExtension1),
1549 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1550 EXPECT_EQ(
1551 MAKE_VECTOR(kVideoRtpExtension1),
1552 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1553 EXPECT_EQ(
1554 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1555 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1556 EXPECT_EQ(
1557 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1558 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001559}
1560
Johannes Kronce8e8672019-02-22 13:06:44 +01001561// Create a audio/video offer and answer and ensure that the
1562// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1563// supported and should take precedence even though not listed among locally
1564// supported extensions.
1565TEST_F(MediaSessionDescriptionFactoryTest,
1566 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1567 TestTransportSequenceNumberNegotiation(
1568 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1569 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1570 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1571}
1572TEST_F(MediaSessionDescriptionFactoryTest,
1573 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1574 TestTransportSequenceNumberNegotiation(
1575 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1576 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1577 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1578}
1579TEST_F(MediaSessionDescriptionFactoryTest,
1580 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1581 TestTransportSequenceNumberNegotiation(
1582 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1583 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1584 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1585}
1586
jbauch5869f502017-06-29 12:31:36 -07001587TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001588 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001589 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001590 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001591
1592 f1_.set_enable_encrypted_rtp_header_extensions(true);
1593 f2_.set_enable_encrypted_rtp_header_extensions(true);
1594
Yves Gerey665174f2018-06-19 15:03:05 +02001595 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1596 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1597 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1598 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001599
Steve Anton6fe1fba2018-12-11 10:15:23 -08001600 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001601 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001602 std::unique_ptr<SessionDescription> answer =
1603 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001604
Yves Gerey665174f2018-06-19 15:03:05 +02001605 EXPECT_EQ(
1606 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1607 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1608 EXPECT_EQ(
1609 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1610 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1611 EXPECT_EQ(
1612 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1613 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1614 EXPECT_EQ(
1615 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1616 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001617}
1618
1619TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001620 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001621 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001622 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001623
1624 f1_.set_enable_encrypted_rtp_header_extensions(true);
1625
Yves Gerey665174f2018-06-19 15:03:05 +02001626 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1627 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1628 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1629 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001630
Steve Anton6fe1fba2018-12-11 10:15:23 -08001631 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001632 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001633 std::unique_ptr<SessionDescription> answer =
1634 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001635
Yves Gerey665174f2018-06-19 15:03:05 +02001636 EXPECT_EQ(
1637 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1638 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1639 EXPECT_EQ(
1640 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1641 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1642 EXPECT_EQ(
1643 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1644 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1645 EXPECT_EQ(
1646 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1647 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001648}
1649
1650TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001651 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001652 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001653 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001654
1655 f2_.set_enable_encrypted_rtp_header_extensions(true);
1656
Yves Gerey665174f2018-06-19 15:03:05 +02001657 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1658 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1659 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1660 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001661
Steve Anton6fe1fba2018-12-11 10:15:23 -08001662 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001663 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001664 std::unique_ptr<SessionDescription> answer =
1665 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001666
Yves Gerey665174f2018-06-19 15:03:05 +02001667 EXPECT_EQ(
1668 MAKE_VECTOR(kAudioRtpExtension1),
1669 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1670 EXPECT_EQ(
1671 MAKE_VECTOR(kVideoRtpExtension1),
1672 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1673 EXPECT_EQ(
1674 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1675 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1676 EXPECT_EQ(
1677 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1678 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001679}
1680
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001681// Create an audio, video, data answer without legacy StreamParams.
1682TEST_F(MediaSessionDescriptionFactoryTest,
1683 TestCreateAnswerWithoutLegacyStreams) {
1684 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001685 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1686 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001687 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001688 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001689 std::unique_ptr<SessionDescription> answer =
1690 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001691 const ContentInfo* ac = answer->GetContentByName("audio");
1692 const ContentInfo* vc = answer->GetContentByName("video");
1693 const ContentInfo* dc = answer->GetContentByName("data");
1694 ASSERT_TRUE(ac != NULL);
1695 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001696 const AudioContentDescription* acd = ac->media_description()->as_audio();
1697 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001698 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001699
1700 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1701 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1702 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1703}
1704
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001705// Create a typical video answer, and ensure it matches what we expect.
1706TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1707 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001708 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1709 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1710 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001711
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001712 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001713 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1714 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1715 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001716
kwiberg31022942016-03-11 14:18:21 -08001717 std::unique_ptr<SessionDescription> offer;
1718 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001719
1720 offer_opts.rtcp_mux_enabled = true;
1721 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001722 offer = f1_.CreateOffer(offer_opts, NULL);
1723 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001724 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1725 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001726 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1728 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001729 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1731 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001732 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001733 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1734 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001735 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001736
1737 offer_opts.rtcp_mux_enabled = true;
1738 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001739 offer = f1_.CreateOffer(offer_opts, NULL);
1740 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001741 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1742 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001743 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1745 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001746 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1748 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001749 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001750 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1751 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001752 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753
1754 offer_opts.rtcp_mux_enabled = false;
1755 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001756 offer = f1_.CreateOffer(offer_opts, NULL);
1757 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001758 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1759 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001760 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001761 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1762 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001763 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001764 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1765 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001766 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1768 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001769 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001770
1771 offer_opts.rtcp_mux_enabled = false;
1772 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001773 offer = f1_.CreateOffer(offer_opts, NULL);
1774 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1776 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001777 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001778 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1779 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001780 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001781 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1782 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001783 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1785 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001786 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001787}
1788
1789// Create an audio-only answer to a video offer.
1790TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1791 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001792 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1793 RtpTransceiverDirection::kRecvOnly, kActive,
1794 &opts);
1795 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1796 RtpTransceiverDirection::kRecvOnly, kActive,
1797 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001798 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001799 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001800
1801 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001802 std::unique_ptr<SessionDescription> answer =
1803 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001804 const ContentInfo* ac = answer->GetContentByName("audio");
1805 const ContentInfo* vc = answer->GetContentByName("video");
1806 ASSERT_TRUE(ac != NULL);
1807 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001808 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809 EXPECT_TRUE(vc->rejected);
1810}
1811
1812// Create an audio-only answer to an offer with data.
1813TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001814 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001815 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001816 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1817 RtpTransceiverDirection::kRecvOnly, kActive,
1818 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001819 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001820 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001821
1822 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001823 std::unique_ptr<SessionDescription> answer =
1824 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825 const ContentInfo* ac = answer->GetContentByName("audio");
1826 const ContentInfo* dc = answer->GetContentByName("data");
1827 ASSERT_TRUE(ac != NULL);
1828 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001829 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001830 EXPECT_TRUE(dc->rejected);
1831}
1832
1833// Create an answer that rejects the contents which are rejected in the offer.
1834TEST_F(MediaSessionDescriptionFactoryTest,
1835 CreateAnswerToOfferWithRejectedMedia) {
1836 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001837 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1838 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001839 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 ASSERT_TRUE(offer.get() != NULL);
1841 ContentInfo* ac = offer->GetContentByName("audio");
1842 ContentInfo* vc = offer->GetContentByName("video");
1843 ContentInfo* dc = offer->GetContentByName("data");
1844 ASSERT_TRUE(ac != NULL);
1845 ASSERT_TRUE(vc != NULL);
1846 ASSERT_TRUE(dc != NULL);
1847 ac->rejected = true;
1848 vc->rejected = true;
1849 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001850 std::unique_ptr<SessionDescription> answer =
1851 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001852 ac = answer->GetContentByName("audio");
1853 vc = answer->GetContentByName("video");
1854 dc = answer->GetContentByName("data");
1855 ASSERT_TRUE(ac != NULL);
1856 ASSERT_TRUE(vc != NULL);
1857 ASSERT_TRUE(dc != NULL);
1858 EXPECT_TRUE(ac->rejected);
1859 EXPECT_TRUE(vc->rejected);
1860 EXPECT_TRUE(dc->rejected);
1861}
1862
Johannes Kron0854eb62018-10-10 22:33:20 +02001863TEST_F(MediaSessionDescriptionFactoryTest,
1864 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1865 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001866 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001867 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001868 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001869 ASSERT_TRUE(offer.get() != NULL);
1870 std::unique_ptr<SessionDescription> answer_no_support(
1871 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001872 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001873
1874 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001875 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001876 ASSERT_TRUE(offer.get() != NULL);
1877 std::unique_ptr<SessionDescription> answer_support(
1878 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001879 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001880}
1881
1882TEST_F(MediaSessionDescriptionFactoryTest,
1883 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1884 MediaSessionOptions opts;
1885 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001886 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001887 MediaContentDescription* video_offer =
1888 offer->GetContentDescriptionByName("video");
1889 ASSERT_TRUE(video_offer);
1890 MediaContentDescription* audio_offer =
1891 offer->GetContentDescriptionByName("audio");
1892 ASSERT_TRUE(audio_offer);
1893
1894 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001895 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1896 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001897
1898 ASSERT_TRUE(offer.get() != NULL);
1899 std::unique_ptr<SessionDescription> answer_no_support(
1900 f2_.CreateAnswer(offer.get(), opts, NULL));
1901 MediaContentDescription* video_answer =
1902 answer_no_support->GetContentDescriptionByName("video");
1903 MediaContentDescription* audio_answer =
1904 answer_no_support->GetContentDescriptionByName("audio");
1905 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001906 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001907 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001908 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001909
1910 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001911 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1912 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001913 ASSERT_TRUE(offer.get() != NULL);
1914 std::unique_ptr<SessionDescription> answer_support(
1915 f2_.CreateAnswer(offer.get(), opts, NULL));
1916 video_answer = answer_support->GetContentDescriptionByName("video");
1917 audio_answer = answer_support->GetContentDescriptionByName("audio");
1918 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001919 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001920 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001921 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001922}
1923
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001924// Create an audio and video offer with:
1925// - one video track
1926// - two audio tracks
1927// - two data tracks
1928// and ensure it matches what we expect. Also updates the initial offer by
1929// adding a new video track and replaces one of the audio tracks.
1930TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1931 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001932 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001933 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1934 {kMediaStream1}, 1, &opts);
1935 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1936 {kMediaStream1}, 1, &opts);
1937 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1938 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001939
Steve Anton4e70a722017-11-28 14:57:10 -08001940 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001941 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1942 {kMediaStream1}, 1, &opts);
1943 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1944 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001945
1946 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001947 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001948
1949 ASSERT_TRUE(offer.get() != NULL);
1950 const ContentInfo* ac = offer->GetContentByName("audio");
1951 const ContentInfo* vc = offer->GetContentByName("video");
1952 const ContentInfo* dc = offer->GetContentByName("data");
1953 ASSERT_TRUE(ac != NULL);
1954 ASSERT_TRUE(vc != NULL);
1955 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001956 const AudioContentDescription* acd = ac->media_description()->as_audio();
1957 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001958 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001959 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001960 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001961
1962 const StreamParamsVec& audio_streams = acd->streams();
1963 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001964 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1966 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1967 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1968 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1969 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1970 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1971
1972 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1973 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001974 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001975
1976 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1977 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001978 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001979
1980 const StreamParamsVec& video_streams = vcd->streams();
1981 ASSERT_EQ(1U, video_streams.size());
1982 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1983 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1984 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1985 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1986
1987 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001988 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001989 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990
1991 const StreamParamsVec& data_streams = dcd->streams();
1992 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001993 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1995 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1996 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1997 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1998 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1999 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2000
2001 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002002 dcd->bandwidth()); // default bandwidth (auto)
2003 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002004 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002005
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002006 // Update the offer. Add a new video track that is not synched to the
2007 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002008 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2009 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002010 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002011 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2012 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002013 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002014 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2015 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002016 std::unique_ptr<SessionDescription> updated_offer(
2017 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002018
2019 ASSERT_TRUE(updated_offer.get() != NULL);
2020 ac = updated_offer->GetContentByName("audio");
2021 vc = updated_offer->GetContentByName("video");
2022 dc = updated_offer->GetContentByName("data");
2023 ASSERT_TRUE(ac != NULL);
2024 ASSERT_TRUE(vc != NULL);
2025 ASSERT_TRUE(dc != NULL);
2026 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002027 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002029 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002030 const RtpDataContentDescription* updated_dcd =
2031 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032
2033 EXPECT_EQ(acd->type(), updated_acd->type());
2034 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2035 EXPECT_EQ(vcd->type(), updated_vcd->type());
2036 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2037 EXPECT_EQ(dcd->type(), updated_dcd->type());
2038 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002039 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002040 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002041 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002042 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002043 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002044 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2045
2046 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2047 ASSERT_EQ(2U, updated_audio_streams.size());
2048 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2049 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2050 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2051 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2052 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2053
2054 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2055 ASSERT_EQ(2U, updated_video_streams.size());
2056 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2057 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002058 // All the media streams in one PeerConnection share one RTCP CNAME.
2059 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002060
2061 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2062 ASSERT_EQ(2U, updated_data_streams.size());
2063 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2064 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2065 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2066 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2067 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002068 // The stream correctly got the CNAME from the MediaSessionOptions.
2069 // The Expected RTCP CNAME is the default one as we are using the default
2070 // MediaSessionOptions.
2071 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072}
2073
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002074// Create an offer with simulcast video stream.
2075TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2076 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002077 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2078 RtpTransceiverDirection::kRecvOnly, kActive,
2079 &opts);
2080 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2081 RtpTransceiverDirection::kSendRecv, kActive,
2082 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002083 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002084 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2085 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002086 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002087
2088 ASSERT_TRUE(offer.get() != NULL);
2089 const ContentInfo* vc = offer->GetContentByName("video");
2090 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002091 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002092
2093 const StreamParamsVec& video_streams = vcd->streams();
2094 ASSERT_EQ(1U, video_streams.size());
2095 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2096 const SsrcGroup* sim_ssrc_group =
2097 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2098 ASSERT_TRUE(sim_ssrc_group != NULL);
2099 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2100}
2101
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002102MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2103 const RidDescription& rid1 = ::testing::get<0>(arg);
2104 const RidDescription& rid2 = ::testing::get<1>(arg);
2105 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2106}
2107
2108static void CheckSimulcastInSessionDescription(
2109 const SessionDescription* description,
2110 const std::string& content_name,
2111 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002112 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002113 ASSERT_NE(description, nullptr);
2114 const ContentInfo* content = description->GetContentByName(content_name);
2115 ASSERT_NE(content, nullptr);
2116 const MediaContentDescription* cd = content->media_description();
2117 ASSERT_NE(cd, nullptr);
2118 const StreamParamsVec& streams = cd->streams();
2119 ASSERT_THAT(streams, SizeIs(1));
2120 const StreamParams& stream = streams[0];
2121 ASSERT_THAT(stream.ssrcs, IsEmpty());
2122 EXPECT_TRUE(stream.has_rids());
2123 const std::vector<RidDescription> rids = stream.rids();
2124
2125 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2126
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002127 EXPECT_TRUE(cd->HasSimulcast());
2128 const SimulcastDescription& simulcast = cd->simulcast_description();
2129 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2130 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2131
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002132 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002133}
2134
2135// Create an offer with spec-compliant simulcast video stream.
2136TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2137 MediaSessionOptions opts;
2138 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2139 RtpTransceiverDirection::kSendRecv, kActive,
2140 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002141 std::vector<RidDescription> send_rids;
2142 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2143 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2144 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2145 SimulcastLayerList simulcast_layers;
2146 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2147 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2148 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2149 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2150 {kMediaStream1}, send_rids,
2151 simulcast_layers, 0, &opts);
2152 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2153
2154 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002155 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002156}
2157
2158// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2159// In this scenario, RIDs do not need to be negotiated (there is only one).
2160TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2161 MediaSessionOptions opts;
2162 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2163 RtpTransceiverDirection::kSendRecv, kActive,
2164 &opts);
2165 RidDescription rid("f", RidDirection::kSend);
2166 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2167 {kMediaStream1}, {rid},
2168 SimulcastLayerList(), 0, &opts);
2169 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2170
2171 ASSERT_NE(offer.get(), nullptr);
2172 const ContentInfo* content = offer->GetContentByName("video");
2173 ASSERT_NE(content, nullptr);
2174 const MediaContentDescription* cd = content->media_description();
2175 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002176 const StreamParamsVec& streams = cd->streams();
2177 ASSERT_THAT(streams, SizeIs(1));
2178 const StreamParams& stream = streams[0];
2179 ASSERT_THAT(stream.ssrcs, IsEmpty());
2180 EXPECT_FALSE(stream.has_rids());
2181 EXPECT_FALSE(cd->HasSimulcast());
2182}
2183
2184// Create an answer with spec-compliant simulcast video stream.
2185// In this scenario, the SFU is the caller requesting that we send Simulcast.
2186TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2187 MediaSessionOptions offer_opts;
2188 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2189 RtpTransceiverDirection::kSendRecv, kActive,
2190 &offer_opts);
2191 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2192 {kMediaStream1}, 1, &offer_opts);
2193 std::unique_ptr<SessionDescription> offer =
2194 f1_.CreateOffer(offer_opts, nullptr);
2195
2196 MediaSessionOptions answer_opts;
2197 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2198 RtpTransceiverDirection::kSendRecv, kActive,
2199 &answer_opts);
2200
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002201 std::vector<RidDescription> rid_descriptions{
2202 RidDescription("f", RidDirection::kSend),
2203 RidDescription("h", RidDirection::kSend),
2204 RidDescription("q", RidDirection::kSend),
2205 };
2206 SimulcastLayerList simulcast_layers;
2207 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2208 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2209 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2210 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2211 {kMediaStream1}, rid_descriptions,
2212 simulcast_layers, 0, &answer_opts);
2213 std::unique_ptr<SessionDescription> answer =
2214 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2215
2216 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002217 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002218}
2219
2220// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2221// In this scenario, RIDs do not need to be negotiated (there is only one).
2222// Note that RID Direction is not the same as the transceiver direction.
2223TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2224 MediaSessionOptions offer_opts;
2225 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2226 RtpTransceiverDirection::kSendRecv, kActive,
2227 &offer_opts);
2228 RidDescription rid_offer("f", RidDirection::kSend);
2229 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2230 {kMediaStream1}, {rid_offer},
2231 SimulcastLayerList(), 0, &offer_opts);
2232 std::unique_ptr<SessionDescription> offer =
2233 f1_.CreateOffer(offer_opts, nullptr);
2234
2235 MediaSessionOptions answer_opts;
2236 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2237 RtpTransceiverDirection::kSendRecv, kActive,
2238 &answer_opts);
2239
2240 RidDescription rid_answer("f", RidDirection::kReceive);
2241 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2242 {kMediaStream1}, {rid_answer},
2243 SimulcastLayerList(), 0, &answer_opts);
2244 std::unique_ptr<SessionDescription> answer =
2245 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2246
2247 ASSERT_NE(answer.get(), nullptr);
2248 const ContentInfo* content = offer->GetContentByName("video");
2249 ASSERT_NE(content, nullptr);
2250 const MediaContentDescription* cd = content->media_description();
2251 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002252 const StreamParamsVec& streams = cd->streams();
2253 ASSERT_THAT(streams, SizeIs(1));
2254 const StreamParams& stream = streams[0];
2255 ASSERT_THAT(stream.ssrcs, IsEmpty());
2256 EXPECT_FALSE(stream.has_rids());
2257 EXPECT_FALSE(cd->HasSimulcast());
2258}
2259
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002260// Create an audio and video answer to a standard video offer with:
2261// - one video track
2262// - two audio tracks
2263// - two data tracks
2264// and ensure it matches what we expect. Also updates the initial answer by
2265// adding a new video track and removes one of the audio tracks.
2266TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2267 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002268 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2269 RtpTransceiverDirection::kRecvOnly, kActive,
2270 &offer_opts);
2271 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2272 RtpTransceiverDirection::kRecvOnly, kActive,
2273 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002274 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002275 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2276 RtpTransceiverDirection::kRecvOnly, kActive,
2277 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002278 f1_.set_secure(SEC_ENABLED);
2279 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002280 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002281
zhihuang1c378ed2017-08-17 14:10:50 -07002282 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002283 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2284 RtpTransceiverDirection::kSendRecv, kActive,
2285 &answer_opts);
2286 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2287 RtpTransceiverDirection::kSendRecv, kActive,
2288 &answer_opts);
2289 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2290 {kMediaStream1}, 1, &answer_opts);
2291 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2292 {kMediaStream1}, 1, &answer_opts);
2293 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2294 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002295
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002296 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2297 RtpTransceiverDirection::kSendRecv, kActive,
2298 &answer_opts);
2299 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2300 {kMediaStream1}, 1, &answer_opts);
2301 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2302 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002303 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002304
Steve Anton6fe1fba2018-12-11 10:15:23 -08002305 std::unique_ptr<SessionDescription> answer =
2306 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002307
2308 ASSERT_TRUE(answer.get() != NULL);
2309 const ContentInfo* ac = answer->GetContentByName("audio");
2310 const ContentInfo* vc = answer->GetContentByName("video");
2311 const ContentInfo* dc = answer->GetContentByName("data");
2312 ASSERT_TRUE(ac != NULL);
2313 ASSERT_TRUE(vc != NULL);
2314 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002315 const AudioContentDescription* acd = ac->media_description()->as_audio();
2316 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002317 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002318 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2319 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2320 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002321
2322 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002323 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002324
2325 const StreamParamsVec& audio_streams = acd->streams();
2326 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002327 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002328 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2329 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2330 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2331 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2332 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2333 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2334
2335 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2336 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2337
2338 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002339 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340
2341 const StreamParamsVec& video_streams = vcd->streams();
2342 ASSERT_EQ(1U, video_streams.size());
2343 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2344 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2345 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2346 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2347
2348 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002349 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002350
2351 const StreamParamsVec& data_streams = dcd->streams();
2352 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002353 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002354 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2355 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2356 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2357 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2358 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2359 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2360
2361 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002362 dcd->bandwidth()); // default bandwidth (auto)
2363 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002364
2365 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002366 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002367 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2368 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002369 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2370 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002371 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002372 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002373
2374 ASSERT_TRUE(updated_answer.get() != NULL);
2375 ac = updated_answer->GetContentByName("audio");
2376 vc = updated_answer->GetContentByName("video");
2377 dc = updated_answer->GetContentByName("data");
2378 ASSERT_TRUE(ac != NULL);
2379 ASSERT_TRUE(vc != NULL);
2380 ASSERT_TRUE(dc != NULL);
2381 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002382 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002384 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002385 const RtpDataContentDescription* updated_dcd =
2386 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002388 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002389 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002390 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002391 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002392 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002393 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2394
2395 EXPECT_EQ(acd->type(), updated_acd->type());
2396 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2397 EXPECT_EQ(vcd->type(), updated_vcd->type());
2398 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2399 EXPECT_EQ(dcd->type(), updated_dcd->type());
2400 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2401
2402 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2403 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002404 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002405
2406 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2407 ASSERT_EQ(2U, updated_video_streams.size());
2408 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2409 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002410 // All media streams in one PeerConnection share one CNAME.
2411 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002412
2413 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2414 ASSERT_EQ(1U, updated_data_streams.size());
2415 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2416}
2417
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002418// Create an updated offer after creating an answer to the original offer and
2419// verify that the codecs that were part of the original answer are not changed
2420// in the updated offer.
2421TEST_F(MediaSessionDescriptionFactoryTest,
2422 RespondentCreatesOfferAfterCreatingAnswer) {
2423 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002424 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002425
Steve Anton6fe1fba2018-12-11 10:15:23 -08002426 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2427 std::unique_ptr<SessionDescription> answer =
2428 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002429
2430 const AudioContentDescription* acd =
2431 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002432 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002433
2434 const VideoContentDescription* vcd =
2435 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002436 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002437
kwiberg31022942016-03-11 14:18:21 -08002438 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002439 f2_.CreateOffer(opts, answer.get()));
2440
2441 // The expected audio codecs are the common audio codecs from the first
2442 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2443 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002444 // TODO(wu): |updated_offer| should not include the codec
2445 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002446 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002447 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002448 };
2449
2450 // The expected video codecs are the common video codecs from the first
2451 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2452 // preference order.
2453 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002454 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002455 };
2456
2457 const AudioContentDescription* updated_acd =
2458 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002459 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002460
2461 const VideoContentDescription* updated_vcd =
2462 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002463 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002464}
2465
Steve Anton5c72e712018-12-10 14:25:30 -08002466// Test that a reoffer does not reuse audio codecs from a previous media section
2467// that is being recycled.
2468TEST_F(MediaSessionDescriptionFactoryTest,
2469 ReOfferDoesNotReUseRecycledAudioCodecs) {
2470 f1_.set_video_codecs({});
2471 f2_.set_video_codecs({});
2472
2473 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002474 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2475 RtpTransceiverDirection::kSendRecv, kActive,
2476 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002477 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2478 std::unique_ptr<SessionDescription> answer =
2479 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002480
2481 // Recycle the media section by changing its mid.
2482 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002483 std::unique_ptr<SessionDescription> reoffer =
2484 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002485
2486 // Expect that the results of the first negotiation are ignored. If the m=
2487 // section was not recycled the payload types would match the initial offerer.
2488 const AudioContentDescription* acd =
2489 GetFirstAudioContentDescription(reoffer.get());
2490 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2491}
2492
2493// Test that a reoffer does not reuse video codecs from a previous media section
2494// that is being recycled.
2495TEST_F(MediaSessionDescriptionFactoryTest,
2496 ReOfferDoesNotReUseRecycledVideoCodecs) {
2497 f1_.set_audio_codecs({}, {});
2498 f2_.set_audio_codecs({}, {});
2499
2500 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002501 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2502 RtpTransceiverDirection::kSendRecv, kActive,
2503 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002504 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2505 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002506
2507 // Recycle the media section by changing its mid.
2508 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002509 std::unique_ptr<SessionDescription> reoffer =
2510 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002511
2512 // Expect that the results of the first negotiation are ignored. If the m=
2513 // section was not recycled the payload types would match the initial offerer.
2514 const VideoContentDescription* vcd =
2515 GetFirstVideoContentDescription(reoffer.get());
2516 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2517}
2518
2519// Test that a reanswer does not reuse audio codecs from a previous media
2520// section that is being recycled.
2521TEST_F(MediaSessionDescriptionFactoryTest,
2522 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2523 f1_.set_video_codecs({});
2524 f2_.set_video_codecs({});
2525
2526 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2527 // second offer/answer is forward (|f1_| as offerer).
2528 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002529 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2530 RtpTransceiverDirection::kSendRecv, kActive,
2531 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002532 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2533 std::unique_ptr<SessionDescription> answer =
2534 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002535
2536 // Recycle the media section by changing its mid.
2537 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002538 std::unique_ptr<SessionDescription> reoffer =
2539 f1_.CreateOffer(opts, answer.get());
2540 std::unique_ptr<SessionDescription> reanswer =
2541 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002542
2543 // Expect that the results of the first negotiation are ignored. If the m=
2544 // section was not recycled the payload types would match the initial offerer.
2545 const AudioContentDescription* acd =
2546 GetFirstAudioContentDescription(reanswer.get());
2547 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2548}
2549
2550// Test that a reanswer does not reuse video codecs from a previous media
2551// section that is being recycled.
2552TEST_F(MediaSessionDescriptionFactoryTest,
2553 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2554 f1_.set_audio_codecs({}, {});
2555 f2_.set_audio_codecs({}, {});
2556
2557 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2558 // second offer/answer is forward (|f1_| as offerer).
2559 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002560 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2561 RtpTransceiverDirection::kSendRecv, kActive,
2562 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002563 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2564 std::unique_ptr<SessionDescription> answer =
2565 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002566
2567 // Recycle the media section by changing its mid.
2568 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002569 std::unique_ptr<SessionDescription> reoffer =
2570 f1_.CreateOffer(opts, answer.get());
2571 std::unique_ptr<SessionDescription> reanswer =
2572 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002573
2574 // Expect that the results of the first negotiation are ignored. If the m=
2575 // section was not recycled the payload types would match the initial offerer.
2576 const VideoContentDescription* vcd =
2577 GetFirstVideoContentDescription(reanswer.get());
2578 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2579}
2580
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002581// Create an updated offer after creating an answer to the original offer and
2582// verify that the codecs that were part of the original answer are not changed
2583// in the updated offer. In this test Rtx is enabled.
2584TEST_F(MediaSessionDescriptionFactoryTest,
2585 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2586 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002587 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2588 RtpTransceiverDirection::kRecvOnly, kActive,
2589 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002590 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002591 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002592 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002593 f1_.set_video_codecs(f1_codecs);
2594
2595 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002596 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002597 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002598 f2_.set_video_codecs(f2_codecs);
2599
Steve Anton6fe1fba2018-12-11 10:15:23 -08002600 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002601 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002602 std::unique_ptr<SessionDescription> answer =
2603 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002604
2605 const VideoContentDescription* vcd =
2606 GetFirstVideoContentDescription(answer.get());
2607
2608 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002609 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2610 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002611
2612 EXPECT_EQ(expected_codecs, vcd->codecs());
2613
deadbeef67cf2c12016-04-13 10:07:16 -07002614 // Now, make sure we get same result (except for the order) if |f2_| creates
2615 // an updated offer even though the default payload types between |f1_| and
2616 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002617 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002618 f2_.CreateOffer(opts, answer.get()));
2619 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002620 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002621 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2622
2623 const VideoContentDescription* updated_vcd =
2624 GetFirstVideoContentDescription(updated_answer.get());
2625
2626 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2627}
2628
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002629// Regression test for:
2630// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2631// Existing codecs should always appear before new codecs in re-offers. But
2632// under a specific set of circumstances, the existing RTX codec was ending up
2633// added to the end of the list.
2634TEST_F(MediaSessionDescriptionFactoryTest,
2635 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2636 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002637 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2638 RtpTransceiverDirection::kRecvOnly, kActive,
2639 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002640 // We specifically choose different preferred payload types for VP8 to
2641 // trigger the issue.
2642 cricket::VideoCodec vp8_offerer(100, "VP8");
2643 cricket::VideoCodec vp8_offerer_rtx =
2644 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2645 cricket::VideoCodec vp8_answerer(110, "VP8");
2646 cricket::VideoCodec vp8_answerer_rtx =
2647 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2648 cricket::VideoCodec vp9(120, "VP9");
2649 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2650
2651 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2652 // We also specifically cause the answerer to prefer VP9, such that if it
2653 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2654 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2655 vp8_answerer_rtx};
2656
2657 f1_.set_video_codecs(f1_codecs);
2658 f2_.set_video_codecs(f2_codecs);
2659 std::vector<AudioCodec> audio_codecs;
2660 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2661 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2662
2663 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002664 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002665 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002666 std::unique_ptr<SessionDescription> answer =
2667 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002668
2669 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2670 // But if the bug is triggered, RTX for VP8 ends up last.
2671 std::unique_ptr<SessionDescription> updated_offer(
2672 f2_.CreateOffer(opts, answer.get()));
2673
2674 const VideoContentDescription* vcd =
2675 GetFirstVideoContentDescription(updated_offer.get());
2676 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2677 ASSERT_EQ(4u, codecs.size());
2678 EXPECT_EQ(vp8_offerer, codecs[0]);
2679 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2680 EXPECT_EQ(vp9, codecs[2]);
2681 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002682}
2683
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684// Create an updated offer that adds video after creating an audio only answer
2685// to the original offer. This test verifies that if a video codec and the RTX
2686// codec have the same default payload type as an audio codec that is already in
2687// use, the added codecs payload types are changed.
2688TEST_F(MediaSessionDescriptionFactoryTest,
2689 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2690 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002691 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002692 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002693 f1_.set_video_codecs(f1_codecs);
2694
2695 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002696 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2697 RtpTransceiverDirection::kRecvOnly, kActive,
2698 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002699
Steve Anton6fe1fba2018-12-11 10:15:23 -08002700 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2701 std::unique_ptr<SessionDescription> answer =
2702 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002703
2704 const AudioContentDescription* acd =
2705 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002706 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707
2708 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2709 // reference be the same as an audio codec that was negotiated in the
2710 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002711 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002712 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713
2714 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2715 int used_pl_type = acd->codecs()[0].id;
2716 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002717 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002718 f2_.set_video_codecs(f2_codecs);
2719
kwiberg31022942016-03-11 14:18:21 -08002720 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002721 f2_.CreateOffer(opts, answer.get()));
2722 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002723 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002724 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2725
2726 const AudioContentDescription* updated_acd =
2727 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002728 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002729
2730 const VideoContentDescription* updated_vcd =
2731 GetFirstVideoContentDescription(updated_answer.get());
2732
2733 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002734 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002735 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002736 EXPECT_NE(used_pl_type, new_h264_pl_type);
2737 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002738 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002739 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2740 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2741}
2742
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002743// Create an updated offer with RTX after creating an answer to an offer
2744// without RTX, and with different default payload types.
2745// Verify that the added RTX codec references the correct payload type.
2746TEST_F(MediaSessionDescriptionFactoryTest,
2747 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2748 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002749 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002750
2751 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2752 // This creates rtx for H264 with the payload type |f2_| uses.
2753 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2754 f2_.set_video_codecs(f2_codecs);
2755
Steve Anton6fe1fba2018-12-11 10:15:23 -08002756 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002757 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002758 std::unique_ptr<SessionDescription> answer =
2759 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002760
2761 const VideoContentDescription* vcd =
2762 GetFirstVideoContentDescription(answer.get());
2763
2764 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2765 EXPECT_EQ(expected_codecs, vcd->codecs());
2766
2767 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2768 // updated offer, even though the default payload types are different from
2769 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002770 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002771 f2_.CreateOffer(opts, answer.get()));
2772 ASSERT_TRUE(updated_offer);
2773
2774 const VideoContentDescription* updated_vcd =
2775 GetFirstVideoContentDescription(updated_offer.get());
2776
2777 // New offer should attempt to add H263, and RTX for H264.
2778 expected_codecs.push_back(kVideoCodecs2[1]);
2779 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2780 &expected_codecs);
2781 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2782}
2783
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002784// Test that RTX is ignored when there is no associated payload type parameter.
2785TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2786 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002787 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2788 RtpTransceiverDirection::kRecvOnly, kActive,
2789 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002790 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002791 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002792 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793 f1_.set_video_codecs(f1_codecs);
2794
2795 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002796 // This creates RTX for H264 with the payload type |f2_| uses.
2797 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002798 f2_.set_video_codecs(f2_codecs);
2799
Steve Anton6fe1fba2018-12-11 10:15:23 -08002800 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002801 ASSERT_TRUE(offer.get() != NULL);
2802 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2803 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2804 // is possible to test that that RTX is dropped when
2805 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002806 MediaContentDescription* media_desc =
2807 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2808 ASSERT_TRUE(media_desc);
2809 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002810 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002811 for (VideoCodec& codec : codecs) {
2812 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2813 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814 }
2815 }
2816 desc->set_codecs(codecs);
2817
Steve Anton6fe1fba2018-12-11 10:15:23 -08002818 std::unique_ptr<SessionDescription> answer =
2819 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002820
Steve Anton64b626b2019-01-28 17:25:26 -08002821 EXPECT_THAT(
2822 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2823 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002824}
2825
2826// Test that RTX will be filtered out in the answer if its associated payload
2827// type doesn't match the local value.
2828TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2829 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002830 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2831 RtpTransceiverDirection::kRecvOnly, kActive,
2832 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002833 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2834 // This creates RTX for H264 in sender.
2835 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2836 f1_.set_video_codecs(f1_codecs);
2837
2838 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2839 // This creates RTX for H263 in receiver.
2840 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2841 f2_.set_video_codecs(f2_codecs);
2842
Steve Anton6fe1fba2018-12-11 10:15:23 -08002843 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002844 ASSERT_TRUE(offer.get() != NULL);
2845 // Associated payload type doesn't match, therefore, RTX codec is removed in
2846 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002847 std::unique_ptr<SessionDescription> answer =
2848 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002849
Steve Anton64b626b2019-01-28 17:25:26 -08002850 EXPECT_THAT(
2851 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2852 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002853}
2854
2855// Test that when multiple RTX codecs are offered, only the matched RTX codec
2856// is added in the answer, and the unsupported RTX codec is filtered out.
2857TEST_F(MediaSessionDescriptionFactoryTest,
2858 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2859 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002860 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2861 RtpTransceiverDirection::kRecvOnly, kActive,
2862 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002863 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2864 // This creates RTX for H264-SVC in sender.
2865 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2866 f1_.set_video_codecs(f1_codecs);
2867
2868 // This creates RTX for H264 in sender.
2869 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2870 f1_.set_video_codecs(f1_codecs);
2871
2872 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2873 // This creates RTX for H264 in receiver.
2874 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2875 f2_.set_video_codecs(f2_codecs);
2876
2877 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2878 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002879 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002880 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002881 std::unique_ptr<SessionDescription> answer =
2882 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002883 const VideoContentDescription* vcd =
2884 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002885 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2886 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2887 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002888
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002889 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002890}
2891
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002892// Test that after one RTX codec has been negotiated, a new offer can attempt
2893// to add another.
2894TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2895 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002896 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2897 RtpTransceiverDirection::kRecvOnly, kActive,
2898 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002899 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2900 // This creates RTX for H264 for the offerer.
2901 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2902 f1_.set_video_codecs(f1_codecs);
2903
Steve Anton6fe1fba2018-12-11 10:15:23 -08002904 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002905 ASSERT_TRUE(offer);
2906 const VideoContentDescription* vcd =
2907 GetFirstVideoContentDescription(offer.get());
2908
2909 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2910 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2911 &expected_codecs);
2912 EXPECT_EQ(expected_codecs, vcd->codecs());
2913
2914 // Now, attempt to add RTX for H264-SVC.
2915 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2916 f1_.set_video_codecs(f1_codecs);
2917
kwiberg31022942016-03-11 14:18:21 -08002918 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002919 f1_.CreateOffer(opts, offer.get()));
2920 ASSERT_TRUE(updated_offer);
2921 vcd = GetFirstVideoContentDescription(updated_offer.get());
2922
2923 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2924 &expected_codecs);
2925 EXPECT_EQ(expected_codecs, vcd->codecs());
2926}
2927
Noah Richards2e7a0982015-05-18 14:02:54 -07002928// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2929// generated for each simulcast ssrc and correctly grouped.
2930TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2931 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002932 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2933 RtpTransceiverDirection::kSendRecv, kActive,
2934 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002935 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002936 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2937 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002938
2939 // Use a single real codec, and then add RTX for it.
2940 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002941 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002942 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2943 f1_.set_video_codecs(f1_codecs);
2944
2945 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2946 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002947 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002948 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002949 MediaContentDescription* media_desc =
2950 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2951 ASSERT_TRUE(media_desc);
2952 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002953 const StreamParamsVec& streams = desc->streams();
2954 // Single stream.
2955 ASSERT_EQ(1u, streams.size());
2956 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2957 EXPECT_EQ(6u, streams[0].ssrcs.size());
2958 // And should have a SIM group for the simulcast.
2959 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2960 // And a FID group for RTX.
2961 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002962 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002963 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2964 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002965 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002966 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2967 EXPECT_EQ(3u, fid_ssrcs.size());
2968}
2969
brandtr03d5fb12016-11-22 03:37:59 -08002970// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2971// together with a FEC-FR grouping.
2972TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2973 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002974 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2975 RtpTransceiverDirection::kSendRecv, kActive,
2976 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002977 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002978 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2979 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002980
2981 // Use a single real codec, and then add FlexFEC for it.
2982 std::vector<VideoCodec> f1_codecs;
2983 f1_codecs.push_back(VideoCodec(97, "H264"));
2984 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2985 f1_.set_video_codecs(f1_codecs);
2986
2987 // Ensure that the offer has a single FlexFEC ssrc and that
2988 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002989 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002990 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002991 MediaContentDescription* media_desc =
2992 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2993 ASSERT_TRUE(media_desc);
2994 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002995 const StreamParamsVec& streams = desc->streams();
2996 // Single stream.
2997 ASSERT_EQ(1u, streams.size());
2998 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2999 EXPECT_EQ(2u, streams[0].ssrcs.size());
3000 // And should have a FEC-FR group for FlexFEC.
3001 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3002 std::vector<uint32_t> primary_ssrcs;
3003 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3004 ASSERT_EQ(1u, primary_ssrcs.size());
3005 uint32_t flexfec_ssrc;
3006 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3007 EXPECT_NE(flexfec_ssrc, 0u);
3008}
3009
3010// Test that FlexFEC is disabled for simulcast.
3011// TODO(brandtr): Remove this test when we support simulcast, either through
3012// multiple FlexfecSenders, or through multistream protection.
3013TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3014 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003015 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3016 RtpTransceiverDirection::kSendRecv, kActive,
3017 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003018 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003019 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3020 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003021
3022 // Use a single real codec, and then add FlexFEC for it.
3023 std::vector<VideoCodec> f1_codecs;
3024 f1_codecs.push_back(VideoCodec(97, "H264"));
3025 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3026 f1_.set_video_codecs(f1_codecs);
3027
3028 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3029 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003030 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003031 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003032 MediaContentDescription* media_desc =
3033 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3034 ASSERT_TRUE(media_desc);
3035 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003036 const StreamParamsVec& streams = desc->streams();
3037 // Single stream.
3038 ASSERT_EQ(1u, streams.size());
3039 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3040 EXPECT_EQ(3u, streams[0].ssrcs.size());
3041 // And should have a SIM group for the simulcast.
3042 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3043 // And not a FEC-FR group for FlexFEC.
3044 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3045 std::vector<uint32_t> primary_ssrcs;
3046 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3047 EXPECT_EQ(3u, primary_ssrcs.size());
3048 for (uint32_t primary_ssrc : primary_ssrcs) {
3049 uint32_t flexfec_ssrc;
3050 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3051 }
3052}
3053
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003054// Create an updated offer after creating an answer to the original offer and
3055// verify that the RTP header extensions that were part of the original answer
3056// are not changed in the updated offer.
3057TEST_F(MediaSessionDescriptionFactoryTest,
3058 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3059 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003060 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003061
3062 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3063 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3064 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3065 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3066
Steve Anton6fe1fba2018-12-11 10:15:23 -08003067 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3068 std::unique_ptr<SessionDescription> answer =
3069 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003070
Yves Gerey665174f2018-06-19 15:03:05 +02003071 EXPECT_EQ(
3072 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3073 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3074 EXPECT_EQ(
3075 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3076 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003077
kwiberg31022942016-03-11 14:18:21 -08003078 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003079 f2_.CreateOffer(opts, answer.get()));
3080
3081 // The expected RTP header extensions in the new offer are the resulting
3082 // extensions from the first offer/answer exchange plus the extensions only
3083 // |f2_| offer.
3084 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003085 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003086 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3087 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3088 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003089 };
3090
3091 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003092 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003093 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3094 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3095 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003096 };
3097
3098 const AudioContentDescription* updated_acd =
3099 GetFirstAudioContentDescription(updated_offer.get());
3100 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3101 updated_acd->rtp_header_extensions());
3102
3103 const VideoContentDescription* updated_vcd =
3104 GetFirstVideoContentDescription(updated_offer.get());
3105 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3106 updated_vcd->rtp_header_extensions());
3107}
3108
deadbeefa5b273a2015-08-20 17:30:13 -07003109// Verify that if the same RTP extension URI is used for audio and video, the
3110// same ID is used. Also verify that the ID isn't changed when creating an
3111// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003112TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003113 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003114 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003115
3116 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3117 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3118
Steve Anton6fe1fba2018-12-11 10:15:23 -08003119 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003120
3121 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3122 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003123 const RtpExtension kExpectedVideoRtpExtension[] = {
3124 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003125 };
3126
Yves Gerey665174f2018-06-19 15:03:05 +02003127 EXPECT_EQ(
3128 MAKE_VECTOR(kAudioRtpExtension3),
3129 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3130 EXPECT_EQ(
3131 MAKE_VECTOR(kExpectedVideoRtpExtension),
3132 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003133
3134 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003135 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003136 f1_.CreateOffer(opts, offer.get()));
3137
3138 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003139 GetFirstAudioContentDescription(updated_offer.get())
3140 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003141 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003142 GetFirstVideoContentDescription(updated_offer.get())
3143 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003144}
3145
jbauch5869f502017-06-29 12:31:36 -07003146// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3147TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3148 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003149 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003150
3151 f1_.set_enable_encrypted_rtp_header_extensions(true);
3152 f2_.set_enable_encrypted_rtp_header_extensions(true);
3153
3154 f1_.set_audio_rtp_header_extensions(
3155 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3156 f1_.set_video_rtp_header_extensions(
3157 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3158
Steve Anton6fe1fba2018-12-11 10:15:23 -08003159 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003160
3161 // The extensions that are shared between audio and video should use the same
3162 // id.
3163 const RtpExtension kExpectedVideoRtpExtension[] = {
3164 kVideoRtpExtension3ForEncryption[0],
3165 kAudioRtpExtension3ForEncryptionOffer[1],
3166 kAudioRtpExtension3ForEncryptionOffer[2],
3167 };
3168
Yves Gerey665174f2018-06-19 15:03:05 +02003169 EXPECT_EQ(
3170 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3171 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3172 EXPECT_EQ(
3173 MAKE_VECTOR(kExpectedVideoRtpExtension),
3174 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003175
3176 // Nothing should change when creating a new offer
3177 std::unique_ptr<SessionDescription> updated_offer(
3178 f1_.CreateOffer(opts, offer.get()));
3179
3180 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003181 GetFirstAudioContentDescription(updated_offer.get())
3182 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003183 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003184 GetFirstVideoContentDescription(updated_offer.get())
3185 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003186}
3187
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003188TEST(MediaSessionDescription, CopySessionDescription) {
3189 SessionDescription source;
3190 cricket::ContentGroup group(cricket::CN_AUDIO);
3191 source.AddGroup(group);
3192 AudioContentDescription* acd(new AudioContentDescription());
3193 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3194 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003195 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003196 VideoContentDescription* vcd(new VideoContentDescription());
3197 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3198 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003199 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003200
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003201 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003202 ASSERT_TRUE(copy.get() != NULL);
3203 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3204 const ContentInfo* ac = copy->GetContentByName("audio");
3205 const ContentInfo* vc = copy->GetContentByName("video");
3206 ASSERT_TRUE(ac != NULL);
3207 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003208 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003209 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003210 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3211 EXPECT_EQ(1u, acd->first_ssrc());
3212
Steve Anton5adfafd2017-12-20 16:34:00 -08003213 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003214 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003215 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3216 EXPECT_EQ(2u, vcd->first_ssrc());
3217}
3218
3219// The below TestTransportInfoXXX tests create different offers/answers, and
3220// ensure the TransportInfo in the SessionDescription matches what we expect.
3221TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3222 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003223 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3224 RtpTransceiverDirection::kRecvOnly, kActive,
3225 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003226 TestTransportInfo(true, options, false);
3227}
3228
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003229TEST_F(MediaSessionDescriptionFactoryTest,
3230 TestTransportInfoOfferIceRenomination) {
3231 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003232 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3233 RtpTransceiverDirection::kRecvOnly, kActive,
3234 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003235 options.media_description_options[0]
3236 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003237 TestTransportInfo(true, options, false);
3238}
3239
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003240TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3241 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003242 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3243 RtpTransceiverDirection::kRecvOnly, kActive,
3244 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003245 TestTransportInfo(true, options, true);
3246}
3247
3248TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3249 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003250 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3251 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3252 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003253 TestTransportInfo(true, options, false);
3254}
3255
3256TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003257 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003258 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003259 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3260 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3261 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003262 TestTransportInfo(true, options, true);
3263}
3264
3265TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3266 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003267 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3268 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3269 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003270 options.bundle_enabled = true;
3271 TestTransportInfo(true, options, false);
3272}
3273
3274TEST_F(MediaSessionDescriptionFactoryTest,
3275 TestTransportInfoOfferBundleCurrent) {
3276 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003277 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3278 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3279 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003280 options.bundle_enabled = true;
3281 TestTransportInfo(true, options, true);
3282}
3283
3284TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3285 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003286 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3287 RtpTransceiverDirection::kRecvOnly, kActive,
3288 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003289 TestTransportInfo(false, options, false);
3290}
3291
3292TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003293 TestTransportInfoAnswerIceRenomination) {
3294 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003295 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3296 RtpTransceiverDirection::kRecvOnly, kActive,
3297 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003298 options.media_description_options[0]
3299 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003300 TestTransportInfo(false, options, false);
3301}
3302
3303TEST_F(MediaSessionDescriptionFactoryTest,
3304 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003305 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003306 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3307 RtpTransceiverDirection::kRecvOnly, kActive,
3308 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003309 TestTransportInfo(false, options, true);
3310}
3311
3312TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3313 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003314 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3315 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3316 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003317 TestTransportInfo(false, options, false);
3318}
3319
3320TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003321 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003322 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003323 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3324 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3325 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003326 TestTransportInfo(false, options, true);
3327}
3328
3329TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3330 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003331 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3332 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3333 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003334 options.bundle_enabled = true;
3335 TestTransportInfo(false, options, false);
3336}
3337
3338TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003339 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003340 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003341 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3342 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3343 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003344 options.bundle_enabled = true;
3345 TestTransportInfo(false, options, true);
3346}
3347
3348// Create an offer with bundle enabled and verify the crypto parameters are
3349// the common set of the available cryptos.
3350TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3351 TestCryptoWithBundle(true);
3352}
3353
3354// Create an answer with bundle enabled and verify the crypto parameters are
3355// the common set of the available cryptos.
3356TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3357 TestCryptoWithBundle(false);
3358}
3359
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003360// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3361// DTLS is not enabled locally.
3362TEST_F(MediaSessionDescriptionFactoryTest,
3363 TestOfferDtlsSavpfWithoutDtlsFailed) {
3364 f1_.set_secure(SEC_ENABLED);
3365 f2_.set_secure(SEC_ENABLED);
3366 tdf1_.set_secure(SEC_DISABLED);
3367 tdf2_.set_secure(SEC_DISABLED);
3368
Steve Anton6fe1fba2018-12-11 10:15:23 -08003369 std::unique_ptr<SessionDescription> offer =
3370 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003371 ASSERT_TRUE(offer.get() != NULL);
3372 ContentInfo* offer_content = offer->GetContentByName("audio");
3373 ASSERT_TRUE(offer_content != NULL);
3374 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003375 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003376 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3377
Steve Anton6fe1fba2018-12-11 10:15:23 -08003378 std::unique_ptr<SessionDescription> answer =
3379 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003380 ASSERT_TRUE(answer != NULL);
3381 ContentInfo* answer_content = answer->GetContentByName("audio");
3382 ASSERT_TRUE(answer_content != NULL);
3383
3384 ASSERT_TRUE(answer_content->rejected);
3385}
3386
3387// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3388// UDP/TLS/RTP/SAVPF.
3389TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3390 f1_.set_secure(SEC_ENABLED);
3391 f2_.set_secure(SEC_ENABLED);
3392 tdf1_.set_secure(SEC_ENABLED);
3393 tdf2_.set_secure(SEC_ENABLED);
3394
Steve Anton6fe1fba2018-12-11 10:15:23 -08003395 std::unique_ptr<SessionDescription> offer =
3396 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003397 ASSERT_TRUE(offer.get() != NULL);
3398 ContentInfo* offer_content = offer->GetContentByName("audio");
3399 ASSERT_TRUE(offer_content != NULL);
3400 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003401 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003402 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3403
Steve Anton6fe1fba2018-12-11 10:15:23 -08003404 std::unique_ptr<SessionDescription> answer =
3405 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003406 ASSERT_TRUE(answer != NULL);
3407
3408 const ContentInfo* answer_content = answer->GetContentByName("audio");
3409 ASSERT_TRUE(answer_content != NULL);
3410 ASSERT_FALSE(answer_content->rejected);
3411
3412 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003413 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003414 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003415}
3416
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003417// Test that we include both SDES and DTLS in the offer, but only include SDES
3418// in the answer if DTLS isn't negotiated.
3419TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3420 f1_.set_secure(SEC_ENABLED);
3421 f2_.set_secure(SEC_ENABLED);
3422 tdf1_.set_secure(SEC_ENABLED);
3423 tdf2_.set_secure(SEC_DISABLED);
3424 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003425 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003426 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003427 const cricket::MediaContentDescription* audio_media_desc;
3428 const cricket::MediaContentDescription* video_media_desc;
3429 const cricket::TransportDescription* audio_trans_desc;
3430 const cricket::TransportDescription* video_trans_desc;
3431
3432 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003433 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003434 ASSERT_TRUE(offer.get() != NULL);
3435
Steve Antonb1c1de12017-12-21 15:14:30 -08003436 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003437 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003438 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003439 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003440 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003441 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3442
3443 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3444 ASSERT_TRUE(audio_trans_desc != NULL);
3445 video_trans_desc = offer->GetTransportDescriptionByName("video");
3446 ASSERT_TRUE(video_trans_desc != NULL);
3447 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3448 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3449
3450 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003451 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003452 ASSERT_TRUE(answer.get() != NULL);
3453
Steve Antonb1c1de12017-12-21 15:14:30 -08003454 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003455 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003456 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003457 ASSERT_TRUE(video_media_desc != NULL);
3458 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3459 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3460
3461 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3462 ASSERT_TRUE(audio_trans_desc != NULL);
3463 video_trans_desc = answer->GetTransportDescriptionByName("video");
3464 ASSERT_TRUE(video_trans_desc != NULL);
3465 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3466 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3467
3468 // Enable DTLS; the answer should now only have DTLS support.
3469 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003470 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003471 ASSERT_TRUE(answer.get() != NULL);
3472
Steve Antonb1c1de12017-12-21 15:14:30 -08003473 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003474 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003475 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003476 ASSERT_TRUE(video_media_desc != NULL);
3477 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3478 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003479 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3480 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003481
3482 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3483 ASSERT_TRUE(audio_trans_desc != NULL);
3484 video_trans_desc = answer->GetTransportDescriptionByName("video");
3485 ASSERT_TRUE(video_trans_desc != NULL);
3486 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3487 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003488
3489 // Try creating offer again. DTLS enabled now, crypto's should be empty
3490 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003491 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003492 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003493 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003494 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003495 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003496 ASSERT_TRUE(video_media_desc != NULL);
3497 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3498 EXPECT_TRUE(video_media_desc->cryptos().empty());
3499
3500 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3501 ASSERT_TRUE(audio_trans_desc != NULL);
3502 video_trans_desc = offer->GetTransportDescriptionByName("video");
3503 ASSERT_TRUE(video_trans_desc != NULL);
3504 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3505 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003506}
3507
3508// Test that an answer can't be created if cryptos are required but the offer is
3509// unsecure.
3510TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003511 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003512 f1_.set_secure(SEC_DISABLED);
3513 tdf1_.set_secure(SEC_DISABLED);
3514 f2_.set_secure(SEC_REQUIRED);
3515 tdf1_.set_secure(SEC_ENABLED);
3516
Steve Anton6fe1fba2018-12-11 10:15:23 -08003517 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003518 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003519 std::unique_ptr<SessionDescription> answer =
3520 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003521 EXPECT_TRUE(answer.get() == NULL);
3522}
3523
3524// Test that we accept a DTLS offer without SDES and create an appropriate
3525// answer.
3526TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3527 f1_.set_secure(SEC_DISABLED);
3528 f2_.set_secure(SEC_ENABLED);
3529 tdf1_.set_secure(SEC_ENABLED);
3530 tdf2_.set_secure(SEC_ENABLED);
3531 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003532 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3533 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3534 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003535
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003536 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003537 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003538 ASSERT_TRUE(offer.get() != NULL);
3539
3540 const AudioContentDescription* audio_offer =
3541 GetFirstAudioContentDescription(offer.get());
3542 ASSERT_TRUE(audio_offer->cryptos().empty());
3543 const VideoContentDescription* video_offer =
3544 GetFirstVideoContentDescription(offer.get());
3545 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003546 const RtpDataContentDescription* data_offer =
3547 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003548 ASSERT_TRUE(data_offer->cryptos().empty());
3549
3550 const cricket::TransportDescription* audio_offer_trans_desc =
3551 offer->GetTransportDescriptionByName("audio");
3552 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3553 const cricket::TransportDescription* video_offer_trans_desc =
3554 offer->GetTransportDescriptionByName("video");
3555 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3556 const cricket::TransportDescription* data_offer_trans_desc =
3557 offer->GetTransportDescriptionByName("data");
3558 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3559
3560 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003561 std::unique_ptr<SessionDescription> answer =
3562 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003563 ASSERT_TRUE(answer.get() != NULL);
3564
3565 const cricket::TransportDescription* audio_answer_trans_desc =
3566 answer->GetTransportDescriptionByName("audio");
3567 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3568 const cricket::TransportDescription* video_answer_trans_desc =
3569 answer->GetTransportDescriptionByName("video");
3570 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3571 const cricket::TransportDescription* data_answer_trans_desc =
3572 answer->GetTransportDescriptionByName("data");
3573 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3574}
3575
3576// Verifies if vad_enabled option is set to false, CN codecs are not present in
3577// offer or answer.
3578TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3579 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003580 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003581 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003582 ASSERT_TRUE(offer.get() != NULL);
3583 const ContentInfo* audio_content = offer->GetContentByName("audio");
3584 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3585
3586 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003587 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003588 ASSERT_TRUE(offer.get() != NULL);
3589 audio_content = offer->GetContentByName("audio");
3590 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003591 std::unique_ptr<SessionDescription> answer =
3592 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003593 ASSERT_TRUE(answer.get() != NULL);
3594 audio_content = answer->GetContentByName("audio");
3595 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3596}
deadbeef44f08192015-12-15 16:20:09 -08003597
zhihuang1c378ed2017-08-17 14:10:50 -07003598// Test that the generated MIDs match the existing offer.
3599TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003600 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003601 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3602 RtpTransceiverDirection::kRecvOnly, kActive,
3603 &opts);
3604 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3605 RtpTransceiverDirection::kRecvOnly, kActive,
3606 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003607 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003608 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3609 RtpTransceiverDirection::kSendRecv, kActive,
3610 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003611 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003612 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003613 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003614 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003615
deadbeef44f08192015-12-15 16:20:09 -08003616 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3617 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3618 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3619 ASSERT_TRUE(audio_content != nullptr);
3620 ASSERT_TRUE(video_content != nullptr);
3621 ASSERT_TRUE(data_content != nullptr);
3622 EXPECT_EQ("audio_modified", audio_content->name);
3623 EXPECT_EQ("video_modified", video_content->name);
3624 EXPECT_EQ("data_modified", data_content->name);
3625}
zhihuangcf5b37c2016-05-05 11:44:35 -07003626
zhihuang1c378ed2017-08-17 14:10:50 -07003627// The following tests verify that the unified plan SDP is supported.
3628// Test that we can create an offer with multiple media sections of same media
3629// type.
3630TEST_F(MediaSessionDescriptionFactoryTest,
3631 CreateOfferWithMultipleAVMediaSections) {
3632 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003633 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3634 RtpTransceiverDirection::kSendRecv, kActive,
3635 &opts);
3636 AttachSenderToMediaDescriptionOptions(
3637 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003638
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003639 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3640 RtpTransceiverDirection::kSendRecv, kActive,
3641 &opts);
3642 AttachSenderToMediaDescriptionOptions(
3643 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003644
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003645 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3646 RtpTransceiverDirection::kSendRecv, kActive,
3647 &opts);
3648 AttachSenderToMediaDescriptionOptions(
3649 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003650
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003651 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3652 RtpTransceiverDirection::kSendRecv, kActive,
3653 &opts);
3654 AttachSenderToMediaDescriptionOptions(
3655 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003656 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003657 ASSERT_TRUE(offer);
3658
3659 ASSERT_EQ(4u, offer->contents().size());
3660 EXPECT_FALSE(offer->contents()[0].rejected);
3661 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003662 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003663 ASSERT_EQ(1u, acd->streams().size());
3664 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003665 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003666
3667 EXPECT_FALSE(offer->contents()[1].rejected);
3668 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003669 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003670 ASSERT_EQ(1u, vcd->streams().size());
3671 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003672 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003673
3674 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003675 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003676 ASSERT_EQ(1u, acd->streams().size());
3677 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003678 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003679
3680 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003681 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003682 ASSERT_EQ(1u, vcd->streams().size());
3683 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003684 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003685}
3686
3687// Test that we can create an answer with multiple media sections of same media
3688// type.
3689TEST_F(MediaSessionDescriptionFactoryTest,
3690 CreateAnswerWithMultipleAVMediaSections) {
3691 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003692 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3693 RtpTransceiverDirection::kSendRecv, kActive,
3694 &opts);
3695 AttachSenderToMediaDescriptionOptions(
3696 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003697
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003698 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3699 RtpTransceiverDirection::kSendRecv, kActive,
3700 &opts);
3701 AttachSenderToMediaDescriptionOptions(
3702 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003703
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003704 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3705 RtpTransceiverDirection::kSendRecv, kActive,
3706 &opts);
3707 AttachSenderToMediaDescriptionOptions(
3708 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003709
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003710 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3711 RtpTransceiverDirection::kSendRecv, kActive,
3712 &opts);
3713 AttachSenderToMediaDescriptionOptions(
3714 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003715
Steve Anton6fe1fba2018-12-11 10:15:23 -08003716 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003717 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003718 std::unique_ptr<SessionDescription> answer =
3719 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003720
3721 ASSERT_EQ(4u, answer->contents().size());
3722 EXPECT_FALSE(answer->contents()[0].rejected);
3723 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003724 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003725 ASSERT_EQ(1u, acd->streams().size());
3726 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003727 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003728
3729 EXPECT_FALSE(answer->contents()[1].rejected);
3730 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003731 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003732 ASSERT_EQ(1u, vcd->streams().size());
3733 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003734 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003735
3736 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003737 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003738 ASSERT_EQ(1u, acd->streams().size());
3739 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003740 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003741
3742 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003743 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003744 ASSERT_EQ(1u, vcd->streams().size());
3745 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003746 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003747}
3748
3749// Test that the media section will be rejected in offer if the corresponding
3750// MediaDescriptionOptions is stopped by the offerer.
3751TEST_F(MediaSessionDescriptionFactoryTest,
3752 CreateOfferWithMediaSectionStoppedByOfferer) {
3753 // Create an offer with two audio sections and one of them is stopped.
3754 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003755 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3756 RtpTransceiverDirection::kSendRecv, kActive,
3757 &offer_opts);
3758 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3759 RtpTransceiverDirection::kInactive, kStopped,
3760 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003761 std::unique_ptr<SessionDescription> offer =
3762 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003763 ASSERT_TRUE(offer);
3764 ASSERT_EQ(2u, offer->contents().size());
3765 EXPECT_FALSE(offer->contents()[0].rejected);
3766 EXPECT_TRUE(offer->contents()[1].rejected);
3767}
3768
3769// Test that the media section will be rejected in answer if the corresponding
3770// MediaDescriptionOptions is stopped by the offerer.
3771TEST_F(MediaSessionDescriptionFactoryTest,
3772 CreateAnswerWithMediaSectionStoppedByOfferer) {
3773 // Create an offer with two audio sections and one of them is stopped.
3774 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003775 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3776 RtpTransceiverDirection::kSendRecv, kActive,
3777 &offer_opts);
3778 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3779 RtpTransceiverDirection::kInactive, kStopped,
3780 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003781 std::unique_ptr<SessionDescription> offer =
3782 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003783 ASSERT_TRUE(offer);
3784 ASSERT_EQ(2u, offer->contents().size());
3785 EXPECT_FALSE(offer->contents()[0].rejected);
3786 EXPECT_TRUE(offer->contents()[1].rejected);
3787
3788 // Create an answer based on the offer.
3789 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003790 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3791 RtpTransceiverDirection::kSendRecv, kActive,
3792 &answer_opts);
3793 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3794 RtpTransceiverDirection::kSendRecv, kActive,
3795 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003796 std::unique_ptr<SessionDescription> answer =
3797 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003798 ASSERT_EQ(2u, answer->contents().size());
3799 EXPECT_FALSE(answer->contents()[0].rejected);
3800 EXPECT_TRUE(answer->contents()[1].rejected);
3801}
3802
3803// Test that the media section will be rejected in answer if the corresponding
3804// MediaDescriptionOptions is stopped by the answerer.
3805TEST_F(MediaSessionDescriptionFactoryTest,
3806 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3807 // Create an offer with two audio sections.
3808 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003809 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3810 RtpTransceiverDirection::kSendRecv, kActive,
3811 &offer_opts);
3812 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3813 RtpTransceiverDirection::kSendRecv, kActive,
3814 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003815 std::unique_ptr<SessionDescription> offer =
3816 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003817 ASSERT_TRUE(offer);
3818 ASSERT_EQ(2u, offer->contents().size());
3819 ASSERT_FALSE(offer->contents()[0].rejected);
3820 ASSERT_FALSE(offer->contents()[1].rejected);
3821
3822 // The answerer rejects one of the audio sections.
3823 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003824 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3825 RtpTransceiverDirection::kSendRecv, kActive,
3826 &answer_opts);
3827 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3828 RtpTransceiverDirection::kInactive, kStopped,
3829 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003830 std::unique_ptr<SessionDescription> answer =
3831 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003832 ASSERT_EQ(2u, answer->contents().size());
3833 EXPECT_FALSE(answer->contents()[0].rejected);
3834 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003835
3836 // The TransportInfo of the rejected m= section is expected to be added in the
3837 // answer.
3838 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003839}
3840
3841// Test the generated media sections has the same order of the
3842// corresponding MediaDescriptionOptions.
3843TEST_F(MediaSessionDescriptionFactoryTest,
3844 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3845 MediaSessionOptions opts;
3846 // This tests put video section first because normally audio comes first by
3847 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003848 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3849 RtpTransceiverDirection::kSendRecv, kActive,
3850 &opts);
3851 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3852 RtpTransceiverDirection::kSendRecv, kActive,
3853 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003854 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003855
3856 ASSERT_TRUE(offer);
3857 ASSERT_EQ(2u, offer->contents().size());
3858 EXPECT_EQ("video", offer->contents()[0].name);
3859 EXPECT_EQ("audio", offer->contents()[1].name);
3860}
3861
3862// Test that different media sections using the same codec have same payload
3863// type.
3864TEST_F(MediaSessionDescriptionFactoryTest,
3865 PayloadTypesSharedByMediaSectionsOfSameType) {
3866 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003867 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3868 RtpTransceiverDirection::kSendRecv, kActive,
3869 &opts);
3870 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3871 RtpTransceiverDirection::kSendRecv, kActive,
3872 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003873 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003874 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003875 ASSERT_TRUE(offer);
3876 ASSERT_EQ(2u, offer->contents().size());
3877 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003878 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003879 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003880 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003881 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3882 ASSERT_EQ(2u, vcd1->codecs().size());
3883 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3884 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3885 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3886 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3887
3888 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003889 std::unique_ptr<SessionDescription> answer =
3890 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003891 ASSERT_TRUE(answer);
3892 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003893 vcd1 = answer->contents()[0].media_description()->as_video();
3894 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003895 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3896 ASSERT_EQ(1u, vcd1->codecs().size());
3897 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3898 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3899}
3900
3901// Test that the codec preference order per media section is respected in
3902// subsequent offer.
3903TEST_F(MediaSessionDescriptionFactoryTest,
3904 CreateOfferRespectsCodecPreferenceOrder) {
3905 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003906 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3907 RtpTransceiverDirection::kSendRecv, kActive,
3908 &opts);
3909 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3910 RtpTransceiverDirection::kSendRecv, kActive,
3911 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003912 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003913 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003914 ASSERT_TRUE(offer);
3915 ASSERT_EQ(2u, offer->contents().size());
3916 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003917 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003918 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003919 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003920 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3921 EXPECT_EQ(video_codecs, vcd1->codecs());
3922 EXPECT_EQ(video_codecs, vcd2->codecs());
3923
3924 // Change the codec preference of the first video section and create a
3925 // follow-up offer.
3926 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3927 vcd1->set_codecs(video_codecs_reverse);
3928 std::unique_ptr<SessionDescription> updated_offer(
3929 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003930 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3931 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003932 // The video codec preference order should be respected.
3933 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3934 EXPECT_EQ(video_codecs, vcd2->codecs());
3935}
3936
3937// Test that the codec preference order per media section is respected in
3938// the answer.
3939TEST_F(MediaSessionDescriptionFactoryTest,
3940 CreateAnswerRespectsCodecPreferenceOrder) {
3941 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003942 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3943 RtpTransceiverDirection::kSendRecv, kActive,
3944 &opts);
3945 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3946 RtpTransceiverDirection::kSendRecv, kActive,
3947 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003948 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003949 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003950 ASSERT_TRUE(offer);
3951 ASSERT_EQ(2u, offer->contents().size());
3952 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003953 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003954 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003955 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003956 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3957 EXPECT_EQ(video_codecs, vcd1->codecs());
3958 EXPECT_EQ(video_codecs, vcd2->codecs());
3959
3960 // Change the codec preference of the first video section and create an
3961 // answer.
3962 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3963 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003964 std::unique_ptr<SessionDescription> answer =
3965 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003966 vcd1 = answer->contents()[0].media_description()->as_video();
3967 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003968 // The video codec preference order should be respected.
3969 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3970 EXPECT_EQ(video_codecs, vcd2->codecs());
3971}
3972
Zhi Huang6f367472017-11-22 13:20:02 -08003973// Test that when creating an answer, the codecs use local parameters instead of
3974// the remote ones.
3975TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3976 const std::string audio_param_name = "audio_param";
3977 const std::string audio_value1 = "audio_v1";
3978 const std::string audio_value2 = "audio_v2";
3979 const std::string video_param_name = "video_param";
3980 const std::string video_value1 = "video_v1";
3981 const std::string video_value2 = "video_v2";
3982
3983 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3984 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3985 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3986 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3987
3988 // Set the parameters for codecs.
3989 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3990 video_codecs1[0].SetParam(video_param_name, video_value1);
3991 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3992 video_codecs2[0].SetParam(video_param_name, video_value2);
3993
3994 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3995 f1_.set_video_codecs(video_codecs1);
3996 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3997 f2_.set_video_codecs(video_codecs2);
3998
3999 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004000 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4001 RtpTransceiverDirection::kSendRecv, kActive,
4002 &opts);
4003 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4004 RtpTransceiverDirection::kSendRecv, kActive,
4005 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004006
Steve Anton6fe1fba2018-12-11 10:15:23 -08004007 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004008 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004009 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4010 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004011 std::string value;
4012 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4013 EXPECT_EQ(audio_value1, value);
4014 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4015 EXPECT_EQ(video_value1, value);
4016
Steve Anton6fe1fba2018-12-11 10:15:23 -08004017 std::unique_ptr<SessionDescription> answer =
4018 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004019 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004020 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4021 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004022 // Use the parameters from the local codecs.
4023 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4024 EXPECT_EQ(audio_value2, value);
4025 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4026 EXPECT_EQ(video_value2, value);
4027}
4028
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004029// Test that matching packetization-mode is part of the criteria for matching
4030// H264 codecs (in addition to profile-level-id). Previously, this was not the
4031// case, so the first H264 codec with the same profile-level-id would match and
4032// the payload type in the answer would be incorrect.
4033// This is a regression test for bugs.webrtc.org/8808
4034TEST_F(MediaSessionDescriptionFactoryTest,
4035 H264MatchCriteriaIncludesPacketizationMode) {
4036 // Create two H264 codecs with the same profile level ID and different
4037 // packetization modes.
4038 VideoCodec h264_pm0(96, "H264");
4039 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4040 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4041 VideoCodec h264_pm1(97, "H264");
4042 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4043 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4044
4045 // Offerer will send both codecs, answerer should choose the one with matching
4046 // packetization mode (and not the first one it sees).
4047 f1_.set_video_codecs({h264_pm0, h264_pm1});
4048 f2_.set_video_codecs({h264_pm1});
4049
4050 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004051 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4052 RtpTransceiverDirection::kSendRecv, kActive,
4053 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004054
Steve Anton6fe1fba2018-12-11 10:15:23 -08004055 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004056 ASSERT_TRUE(offer);
4057
Steve Anton6fe1fba2018-12-11 10:15:23 -08004058 std::unique_ptr<SessionDescription> answer =
4059 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004060 ASSERT_TRUE(answer);
4061
4062 // Answer should have one negotiated codec with packetization-mode=1 using the
4063 // offered payload type.
4064 ASSERT_EQ(1u, answer->contents().size());
4065 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4066 ASSERT_EQ(1u, answer_vcd->codecs().size());
4067 auto answer_codec = answer_vcd->codecs()[0];
4068 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4069}
4070
zhihuangcf5b37c2016-05-05 11:44:35 -07004071class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4072 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004073 MediaProtocolTest()
4074 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004075 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4076 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004077 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004078 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004079 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4080 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004081 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004082 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004083 f1_.set_secure(SEC_ENABLED);
4084 f2_.set_secure(SEC_ENABLED);
4085 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004086 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004087 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004088 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004089 tdf1_.set_secure(SEC_ENABLED);
4090 tdf2_.set_secure(SEC_ENABLED);
4091 }
4092
4093 protected:
4094 MediaSessionDescriptionFactory f1_;
4095 MediaSessionDescriptionFactory f2_;
4096 TransportDescriptionFactory tdf1_;
4097 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004098 UniqueRandomIdGenerator ssrc_generator1;
4099 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004100};
4101
4102TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4103 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004104 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004105 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004106 ASSERT_TRUE(offer.get() != nullptr);
4107 // Set the protocol for all the contents.
4108 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004109 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004110 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004111 std::unique_ptr<SessionDescription> answer =
4112 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004113 const ContentInfo* ac = answer->GetContentByName("audio");
4114 const ContentInfo* vc = answer->GetContentByName("video");
4115 ASSERT_TRUE(ac != nullptr);
4116 ASSERT_TRUE(vc != nullptr);
4117 EXPECT_FALSE(ac->rejected); // the offer is accepted
4118 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004119 const AudioContentDescription* acd = ac->media_description()->as_audio();
4120 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004121 EXPECT_EQ(GetParam(), acd->protocol());
4122 EXPECT_EQ(GetParam(), vcd->protocol());
4123}
4124
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004125INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4126 MediaProtocolTest,
4127 ::testing::ValuesIn(kMediaProtocols));
4128INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4129 MediaProtocolTest,
4130 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004131
4132TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4133 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004134 UniqueRandomIdGenerator ssrc_generator;
4135 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004136 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4137 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4138
4139 // The merged list of codecs should contain any send codecs that are also
4140 // nominally in the recieve codecs list. Payload types should be picked from
4141 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4142 // (set to 1). This equals what happens when the send codecs are used in an
4143 // offer and the receive codecs are used in the following answer.
4144 const std::vector<AudioCodec> sendrecv_codecs =
4145 MAKE_VECTOR(kAudioCodecsAnswer);
4146 const std::vector<AudioCodec> no_codecs;
4147
4148 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4149 << "Please don't change shared test data!";
4150 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4151 << "Please don't change shared test data!";
4152 // Alter iLBC send codec to have zero channels, to test that that is handled
4153 // properly.
4154 send_codecs[1].channels = 0;
4155
4156 // Alther iLBC receive codec to be lowercase, to test that case conversions
4157 // are handled properly.
4158 recv_codecs[2].name = "ilbc";
4159
4160 // Test proper merge
4161 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004162 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4163 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4164 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004165
4166 // Test empty send codecs list
4167 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004168 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4169 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4170 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004171
4172 // Test empty recv codecs list
4173 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004174 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4175 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4176 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004177
4178 // Test all empty codec lists
4179 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004180 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4181 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4182 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004183}
4184
Amit Hilbuch77938e62018-12-21 09:23:38 -08004185// Checks that the RID extensions are added to the video RTP header extensions.
4186// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4187// not very well defined, as calling set() and immediately get() will yield
4188// an object that is not semantically equivalent to the set object.
4189TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4190 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004191 UniqueRandomIdGenerator ssrc_generator;
4192 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004193 sf.set_is_unified_plan(true);
4194 cricket::RtpHeaderExtensions extensions;
4195 sf.set_video_rtp_header_extensions(extensions);
4196 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4197 // Check to see that RID extensions were added to the extension list
4198 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004199 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004200 RtpExtension::kMidUri)));
4201 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004202 RtpExtension::kRidUri)));
4203 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4204 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004205}
4206
4207// Checks that the RID extensions are added to the audio RTP header extensions.
4208// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4209// not very well defined, as calling set() and immediately get() will yield
4210// an object that is not semantically equivalent to the set object.
4211TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4212 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004213 UniqueRandomIdGenerator ssrc_generator;
4214 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004215 sf.set_is_unified_plan(true);
4216 cricket::RtpHeaderExtensions extensions;
4217 sf.set_audio_rtp_header_extensions(extensions);
4218 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4219 // Check to see that RID extensions were added to the extension list
4220 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004221 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004222 RtpExtension::kMidUri)));
4223 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004224 RtpExtension::kRidUri)));
4225 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4226 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004227}
4228
ossu075af922016-06-14 03:29:38 -07004229namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004230// Compare the two vectors of codecs ignoring the payload type.
4231template <class Codec>
4232bool CodecsMatch(const std::vector<Codec>& codecs1,
4233 const std::vector<Codec>& codecs2) {
4234 if (codecs1.size() != codecs2.size()) {
4235 return false;
4236 }
4237
4238 for (size_t i = 0; i < codecs1.size(); ++i) {
4239 if (!codecs1[i].Matches(codecs2[i])) {
4240 return false;
4241 }
4242 }
4243 return true;
4244}
4245
Steve Anton4e70a722017-11-28 14:57:10 -08004246void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004247 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004248 UniqueRandomIdGenerator ssrc_generator;
4249 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004250 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4251 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4252 const std::vector<AudioCodec> sendrecv_codecs =
4253 MAKE_VECTOR(kAudioCodecsAnswer);
4254 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004255
4256 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004257 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4258 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004259
Steve Anton4e70a722017-11-28 14:57:10 -08004260 if (direction == RtpTransceiverDirection::kSendRecv ||
4261 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004262 AttachSenderToMediaDescriptionOptions(
4263 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004264 }
ossu075af922016-06-14 03:29:38 -07004265
Steve Anton6fe1fba2018-12-11 10:15:23 -08004266 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004267 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004268 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004269
4270 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004271 // that the codecs put in are right. This happens when we neither want to
4272 // send nor receive audio. The checks are still in place if at some point
4273 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004274 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004275 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004276 // sendrecv and inactive should both present lists as if the channel was
4277 // to be used for sending and receiving. Inactive essentially means it
4278 // might eventually be used anything, but we don't know more at this
4279 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004280 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004281 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004282 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004283 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004284 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004285 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004286 }
4287 }
4288}
4289
4290static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004291 AudioCodec(0, "codec0", 16000, -1, 1),
4292 AudioCodec(1, "codec1", 8000, 13300, 1),
4293 AudioCodec(2, "codec2", 8000, 64000, 1),
4294 AudioCodec(3, "codec3", 8000, 64000, 1),
4295 AudioCodec(4, "codec4", 8000, 0, 2),
4296 AudioCodec(5, "codec5", 32000, 0, 1),
4297 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004298
zhihuang1c378ed2017-08-17 14:10:50 -07004299/* The codecs groups below are chosen as per the matrix below. The objective
4300 * is to have different sets of codecs in the inputs, to get unique sets of
4301 * codecs after negotiation, depending on offer and answer communication
4302 * directions. One-way directions in the offer should either result in the
4303 * opposite direction in the answer, or an inactive answer. Regardless, the
4304 * choice of codecs should be as if the answer contained the opposite
4305 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004306 *
4307 * | Offer | Answer | Result
4308 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4309 * 0 | x - - | - x - | x - - - -
4310 * 1 | x x x | - x - | x - - x -
4311 * 2 | - x - | x - - | - x - - -
4312 * 3 | x x x | x - - | - x x - -
4313 * 4 | - x - | x x x | - x - - -
4314 * 5 | x - - | x x x | x - - - -
4315 * 6 | x x x | x x x | x x x x x
4316 */
4317// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004318static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4319static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004320// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4321// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004322static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4323static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004324// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004325static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4326static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4327static const int kResultSendrecv_SendCodecs[] = {3, 6};
4328static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4329static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004330
4331template <typename T, int IDXS>
4332std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4333 std::vector<T> out;
4334 out.reserve(IDXS);
4335 for (int idx : indices)
4336 out.push_back(array[idx]);
4337
4338 return out;
4339}
4340
Steve Anton4e70a722017-11-28 14:57:10 -08004341void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4342 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004343 bool add_legacy_stream) {
4344 TransportDescriptionFactory offer_tdf;
4345 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004346 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4347 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4348 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004349 offer_factory.set_audio_codecs(
4350 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4351 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4352 answer_factory.set_audio_codecs(
4353 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4354 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4355
ossu075af922016-06-14 03:29:38 -07004356 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004357 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4358 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004359
Steve Anton4e70a722017-11-28 14:57:10 -08004360 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004361 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4362 kAudioTrack1, {kMediaStream1}, 1,
4363 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004364 }
4365
Steve Anton6fe1fba2018-12-11 10:15:23 -08004366 std::unique_ptr<SessionDescription> offer =
4367 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004368 ASSERT_TRUE(offer.get() != NULL);
4369
4370 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004371 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4372 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004373
Steve Anton4e70a722017-11-28 14:57:10 -08004374 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004375 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4376 kAudioTrack1, {kMediaStream1}, 1,
4377 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004378 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004379 std::unique_ptr<SessionDescription> answer =
4380 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004381 const ContentInfo* ac = answer->GetContentByName("audio");
4382
zhihuang1c378ed2017-08-17 14:10:50 -07004383 // If the factory didn't add any audio content to the answer, we cannot
4384 // check that the codecs put in are right. This happens when we neither want
4385 // to send nor receive audio. The checks are still in place if at some point
4386 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004387 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004388 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4389 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004390
ossu075af922016-06-14 03:29:38 -07004391 std::vector<AudioCodec> target_codecs;
4392 // For offers with sendrecv or inactive, we should never reply with more
4393 // codecs than offered, with these codec sets.
4394 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004395 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004396 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4397 kResultSendrecv_SendrecvCodecs);
4398 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004399 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004400 target_codecs =
4401 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004402 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004403 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004404 target_codecs =
4405 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004406 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004407 case RtpTransceiverDirection::kSendRecv:
4408 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004409 target_codecs =
4410 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004411 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004412 target_codecs =
4413 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004414 } else {
4415 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4416 kResultSendrecv_SendrecvCodecs);
4417 }
4418 break;
4419 }
4420
zhihuang1c378ed2017-08-17 14:10:50 -07004421 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004422 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004423 bool first = true;
4424 os << "{";
4425 for (const auto& c : codecs) {
4426 os << (first ? " " : ", ") << c.id;
4427 first = false;
4428 }
4429 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004430 return os.Release();
ossu075af922016-06-14 03:29:38 -07004431 };
4432
4433 EXPECT_TRUE(acd->codecs() == target_codecs)
4434 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004435 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4436 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004437 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004438 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4439 << "; got: "
4440 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004441 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004442 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004443 << "Only inactive offers are allowed to not generate any audio "
4444 "content";
ossu075af922016-06-14 03:29:38 -07004445 }
4446}
brandtr03d5fb12016-11-22 03:37:59 -08004447
4448} // namespace
ossu075af922016-06-14 03:29:38 -07004449
4450class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004451 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004452
4453TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004454 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004455}
4456
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004457INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4458 AudioCodecsOfferTest,
4459 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4460 RtpTransceiverDirection::kRecvOnly,
4461 RtpTransceiverDirection::kSendRecv,
4462 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004463
4464class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004465 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4466 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004467 bool>> {};
ossu075af922016-06-14 03:29:38 -07004468
4469TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004470 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4471 ::testing::get<1>(GetParam()),
4472 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004473}
4474
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004475INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004476 MediaSessionDescriptionFactoryTest,
4477 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004478 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4479 RtpTransceiverDirection::kRecvOnly,
4480 RtpTransceiverDirection::kSendRecv,
4481 RtpTransceiverDirection::kInactive),
4482 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4483 RtpTransceiverDirection::kRecvOnly,
4484 RtpTransceiverDirection::kSendRecv,
4485 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004486 ::testing::Bool()));