blob: e876c363015b00711033d4b3c1b6cca2276061d6 [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;
45using cricket::DataCodec;
46using cricket::DataContentDescription;
47using cricket::GetFirstAudioContent;
48using cricket::GetFirstAudioContentDescription;
49using cricket::GetFirstDataContent;
50using cricket::GetFirstDataContentDescription;
51using cricket::GetFirstVideoContent;
52using cricket::GetFirstVideoContentDescription;
53using cricket::kAutoBandwidth;
54using cricket::MEDIA_TYPE_AUDIO;
55using cricket::MEDIA_TYPE_DATA;
56using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070058using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080059using cricket::MediaProtocolType;
60using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061using cricket::MediaSessionOptions;
62using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080063using cricket::RidDescription;
64using cricket::RidDirection;
65using cricket::SEC_DISABLED;
66using cricket::SEC_ENABLED;
67using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000068using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080069using cricket::SimulcastDescription;
70using cricket::SimulcastLayer;
71using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072using cricket::SsrcGroup;
73using cricket::StreamParams;
74using cricket::StreamParamsVec;
75using cricket::TransportDescription;
76using cricket::TransportDescriptionFactory;
77using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000078using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080079using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070080using rtc::CS_AEAD_AES_128_GCM;
81using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080082using rtc::CS_AES_CM_128_HMAC_SHA1_32;
83using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080084using rtc::UniqueRandomIdGenerator;
Steve Anton64b626b2019-01-28 17:25:26 -080085using testing::Contains;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080086using testing::Each;
Steve Antone38a5a12018-11-21 16:05:15 -080087using testing::ElementsAreArray;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080088using testing::Eq;
89using testing::Field;
90using testing::IsEmpty;
91using testing::IsFalse;
92using testing::Ne;
Steve Anton64b626b2019-01-28 17:25:26 -080093using testing::Not;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080094using testing::Pointwise;
95using testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070096using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080097using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098
99static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700100 AudioCodec(103, "ISAC", 16000, -1, 1),
101 AudioCodec(102, "iLBC", 8000, 13300, 1),
102 AudioCodec(0, "PCMU", 8000, 64000, 1),
103 AudioCodec(8, "PCMA", 8000, 64000, 1),
104 AudioCodec(117, "red", 8000, 0, 1),
105 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106
107static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200108 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700109 AudioCodec(0, "PCMU", 8000, 64000, 1),
110 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111};
112
113static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700114 AudioCodec(102, "iLBC", 8000, 13300, 1),
115 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116};
117
perkj26752742016-10-24 01:21:16 -0700118static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
119 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120
zhihuang1c378ed2017-08-17 14:10:50 -0700121static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
122 VideoCodec(96, "H264-SVC")};
123
perkj26752742016-10-24 01:21:16 -0700124static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
125 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126
perkj26752742016-10-24 01:21:16 -0700127static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128
deadbeef67cf2c12016-04-13 10:07:16 -0700129static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
130 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
deadbeef67cf2c12016-04-13 10:07:16 -0700132static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
133 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
deadbeef67cf2c12016-04-13 10:07:16 -0700135static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
136 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
isheriff6f8d6862016-05-26 11:24:55 -0700138static const RtpExtension kAudioRtpExtension1[] = {
139 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
140 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000141};
142
jbauch5869f502017-06-29 12:31:36 -0700143static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
144 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
145 RtpExtension("http://google.com/testing/audio_something", 10),
146 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
147};
148
isheriff6f8d6862016-05-26 11:24:55 -0700149static const RtpExtension kAudioRtpExtension2[] = {
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
151 RtpExtension("http://google.com/testing/audio_something_else", 8),
152 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153};
154
isheriff6f8d6862016-05-26 11:24:55 -0700155static const RtpExtension kAudioRtpExtension3[] = {
156 RtpExtension("http://google.com/testing/audio_something", 2),
157 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700158};
159
jbauch5869f502017-06-29 12:31:36 -0700160static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
161 RtpExtension("http://google.com/testing/audio_something", 2),
162 // Use RTP extension that supports encryption.
163 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
164};
165
166static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
167 RtpExtension("http://google.com/testing/audio_something", 2),
168 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
170};
171
isheriff6f8d6862016-05-26 11:24:55 -0700172static const RtpExtension kAudioRtpExtensionAnswer[] = {
173 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000174};
175
jbauch5869f502017-06-29 12:31:36 -0700176static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
177 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
178};
179
isheriff6f8d6862016-05-26 11:24:55 -0700180static const RtpExtension kVideoRtpExtension1[] = {
181 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
182 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000183};
184
jbauch5869f502017-06-29 12:31:36 -0700185static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
187 RtpExtension("http://google.com/testing/video_something", 13),
188 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
189};
190
isheriff6f8d6862016-05-26 11:24:55 -0700191static const RtpExtension kVideoRtpExtension2[] = {
192 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
193 RtpExtension("http://google.com/testing/video_something_else", 14),
194 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000195};
196
isheriff6f8d6862016-05-26 11:24:55 -0700197static const RtpExtension kVideoRtpExtension3[] = {
198 RtpExtension("http://google.com/testing/video_something", 4),
199 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700200};
201
jbauch5869f502017-06-29 12:31:36 -0700202static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
203 RtpExtension("http://google.com/testing/video_something", 4),
204 // Use RTP extension that supports encryption.
205 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
206};
207
isheriff6f8d6862016-05-26 11:24:55 -0700208static const RtpExtension kVideoRtpExtensionAnswer[] = {
209 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210};
211
jbauch5869f502017-06-29 12:31:36 -0700212static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
213 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
214};
215
Johannes Kronce8e8672019-02-22 13:06:44 +0100216static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
217 RtpExtension("http://www.ietf.org/id/"
218 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
219 1),
220};
221
222static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
223 RtpExtension("http://www.ietf.org/id/"
224 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
225 1),
226 RtpExtension("http://www.ietf.org/id/"
227 "draft-holmer-rmcat-transport-wide-cc-extensions-02",
228 2),
229};
230
231static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
232 RtpExtension("http://www.ietf.org/id/"
233 "draft-holmer-rmcat-transport-wide-cc-extensions-02",
234 2),
235};
236
Peter Boström0c4e06b2015-10-07 12:23:21 +0200237static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
238static const uint32_t kSimSsrc[] = {10, 20, 30};
239static const uint32_t kFec1Ssrc[] = {10, 11};
240static const uint32_t kFec2Ssrc[] = {20, 21};
241static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000242
243static const char kMediaStream1[] = "stream_1";
244static const char kMediaStream2[] = "stream_2";
245static const char kVideoTrack1[] = "video_1";
246static const char kVideoTrack2[] = "video_2";
247static const char kAudioTrack1[] = "audio_1";
248static const char kAudioTrack2[] = "audio_2";
249static const char kAudioTrack3[] = "audio_3";
250static const char kDataTrack1[] = "data_1";
251static const char kDataTrack2[] = "data_2";
252static const char kDataTrack3[] = "data_3";
253
zhihuangcf5b37c2016-05-05 11:44:35 -0700254static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
255 "RTP/SAVPF"};
256static const char* kMediaProtocolsDtls[] = {
257 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
258 "UDP/TLS/RTP/SAVP"};
259
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700260// SRTP cipher name negotiated by the tests. This must be updated if the
261// default changes.
262static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
263static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
264
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800265// These constants are used to make the code using "AddMediaDescriptionOptions"
266// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700267static constexpr bool kStopped = true;
268static constexpr bool kActive = false;
269
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000270static bool IsMediaContentOfType(const ContentInfo* content,
271 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800272 RTC_DCHECK(content);
273 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000274}
275
Steve Anton4e70a722017-11-28 14:57:10 -0800276static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800277 RTC_DCHECK(content);
278 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000279}
280
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000281static void AddRtxCodec(const VideoCodec& rtx_codec,
282 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800283 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000284 codecs->push_back(rtx_codec);
285}
286
287template <class T>
288static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
289 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100290 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000291 for (const auto& codec : codecs) {
292 codec_names.push_back(codec.name);
293 }
294 return codec_names;
295}
296
zhihuang1c378ed2017-08-17 14:10:50 -0700297// This is used for test only. MIDs are not the identification of the
298// MediaDescriptionOptions since some end points may not support MID and the SDP
299// may not contain 'mid'.
300std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
301 const std::string& mid,
302 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800303 return absl::c_find_if(
304 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700305 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
306}
307
308std::vector<MediaDescriptionOptions>::const_iterator
309FindFirstMediaDescriptionByMid(const std::string& mid,
310 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800311 return absl::c_find_if(
312 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700313 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700314}
315
316// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800317static void AddMediaDescriptionOptions(MediaType type,
318 const std::string& mid,
319 RtpTransceiverDirection direction,
320 bool stopped,
321 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800322 opts->media_description_options.push_back(
323 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700324}
325
Steve Anton4e70a722017-11-28 14:57:10 -0800326static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700327 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800328 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
329 opts);
330 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
331 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700332}
333
334static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800335 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700336 MediaSessionOptions* opts) {
337 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800338 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700339}
340
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800341static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700342 const std::string& mid,
343 MediaType type,
344 const std::string& track_id,
345 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800346 const std::vector<RidDescription>& rids,
347 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700348 int num_sim_layer,
349 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700350 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
351 switch (type) {
352 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700353 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700354 break;
355 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800356 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
357 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700358 break;
359 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700360 RTC_CHECK(stream_ids.size() == 1U);
361 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700362 break;
363 default:
364 RTC_NOTREACHED();
365 }
366}
367
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800368static void AttachSenderToMediaDescriptionOptions(
369 const std::string& mid,
370 MediaType type,
371 const std::string& track_id,
372 const std::vector<std::string>& stream_ids,
373 int num_sim_layer,
374 MediaSessionOptions* session_options) {
375 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
376 SimulcastLayerList(), num_sim_layer,
377 session_options);
378}
379
zhihuang1c378ed2017-08-17 14:10:50 -0700380static void DetachSenderFromMediaSection(const std::string& mid,
381 const std::string& track_id,
382 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700383 std::vector<cricket::SenderOptions>& sender_options_list =
384 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
385 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800386 absl::c_find_if(sender_options_list,
387 [track_id](const cricket::SenderOptions& sender_options) {
388 return sender_options.track_id == track_id;
389 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700390 RTC_DCHECK(sender_it != sender_options_list.end());
391 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700392}
393
394// Helper function used to create a default MediaSessionOptions for Plan B SDP.
395// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
396static MediaSessionOptions CreatePlanBMediaSessionOptions() {
397 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800398 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
399 RtpTransceiverDirection::kRecvOnly, kActive,
400 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700401 return session_options;
402}
403
404// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
405// was designed for Plan B SDP, where only one audio "m=" section and one video
406// "m=" section could be generated, and ordering couldn't be controlled. Many of
407// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000408class MediaSessionDescriptionFactoryTest : public testing::Test {
409 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800410 MediaSessionDescriptionFactoryTest()
411 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700412 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
413 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000414 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
415 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700416 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
417 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
419 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200420 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700421 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200422 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700423 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424 }
425
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000426 // Create a video StreamParamsVec object with:
427 // - one video stream with 3 simulcast streams and FEC,
428 StreamParamsVec CreateComplexVideoStreamParamsVec() {
429 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
430 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
431 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
432 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
433
434 std::vector<SsrcGroup> ssrc_groups;
435 ssrc_groups.push_back(sim_group);
436 ssrc_groups.push_back(fec_group1);
437 ssrc_groups.push_back(fec_group2);
438 ssrc_groups.push_back(fec_group3);
439
440 StreamParams simulcast_params;
441 simulcast_params.id = kVideoTrack1;
442 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
443 simulcast_params.ssrc_groups = ssrc_groups;
444 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800445 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000446
447 StreamParamsVec video_streams;
448 video_streams.push_back(simulcast_params);
449
450 return video_streams;
451 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452
453 bool CompareCryptoParams(const CryptoParamsVec& c1,
454 const CryptoParamsVec& c2) {
455 if (c1.size() != c2.size())
456 return false;
457 for (size_t i = 0; i < c1.size(); ++i)
458 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
459 c1[i].key_params != c2[i].key_params ||
460 c1[i].session_params != c2[i].session_params)
461 return false;
462 return true;
463 }
464
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700465 // Returns true if the transport info contains "renomination" as an
466 // ICE option.
467 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800468 return absl::c_linear_search(transport_info->description.transport_options,
469 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700470 }
471
zhihuang1c378ed2017-08-17 14:10:50 -0700472 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700473 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474 bool has_current_desc) {
475 const std::string current_audio_ufrag = "current_audio_ufrag";
476 const std::string current_audio_pwd = "current_audio_pwd";
477 const std::string current_video_ufrag = "current_video_ufrag";
478 const std::string current_video_pwd = "current_video_pwd";
479 const std::string current_data_ufrag = "current_data_ufrag";
480 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800481 std::unique_ptr<SessionDescription> current_desc;
482 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800484 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800485 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200486 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800487 TransportDescription(current_audio_ufrag, current_audio_pwd)));
488 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200489 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800490 TransportDescription(current_video_ufrag, current_video_pwd)));
491 current_desc->AddTransportInfo(TransportInfo(
492 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493 }
494 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800495 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496 } else {
kwiberg31022942016-03-11 14:18:21 -0800497 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800498 offer = f1_.CreateOffer(options, NULL);
499 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 }
501 ASSERT_TRUE(desc.get() != NULL);
502 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000503 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 EXPECT_TRUE(ti_audio != NULL);
505 if (has_current_desc) {
506 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
507 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
508 } else {
509 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
510 ti_audio->description.ice_ufrag.size());
511 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
512 ti_audio->description.ice_pwd.size());
513 }
zhihuang1c378ed2017-08-17 14:10:50 -0700514 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700515 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700516 EXPECT_EQ(
517 media_desc_options_it->transport_options.enable_ice_renomination,
518 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519
520 } else {
521 EXPECT_TRUE(ti_audio == NULL);
522 }
523 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000524 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525 EXPECT_TRUE(ti_video != NULL);
526 if (options.bundle_enabled) {
527 EXPECT_EQ(ti_audio->description.ice_ufrag,
528 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200529 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 } else {
531 if (has_current_desc) {
532 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
533 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
534 } else {
535 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
536 ti_video->description.ice_ufrag.size());
537 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
538 ti_video->description.ice_pwd.size());
539 }
540 }
zhihuang1c378ed2017-08-17 14:10:50 -0700541 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700542 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700543 EXPECT_EQ(
544 media_desc_options_it->transport_options.enable_ice_renomination,
545 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546 } else {
547 EXPECT_TRUE(ti_video == NULL);
548 }
549 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
550 if (options.has_data()) {
551 EXPECT_TRUE(ti_data != NULL);
552 if (options.bundle_enabled) {
553 EXPECT_EQ(ti_audio->description.ice_ufrag,
554 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200555 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 } else {
557 if (has_current_desc) {
558 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
559 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
560 } else {
561 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
562 ti_data->description.ice_ufrag.size());
563 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
564 ti_data->description.ice_pwd.size());
565 }
566 }
zhihuang1c378ed2017-08-17 14:10:50 -0700567 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700568 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700569 EXPECT_EQ(
570 media_desc_options_it->transport_options.enable_ice_renomination,
571 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700572
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 } else {
574 EXPECT_TRUE(ti_video == NULL);
575 }
576 }
577
578 void TestCryptoWithBundle(bool offer) {
579 f1_.set_secure(SEC_ENABLED);
580 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800581 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
582 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
583 &options);
kwiberg31022942016-03-11 14:18:21 -0800584 std::unique_ptr<SessionDescription> ref_desc;
585 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 if (offer) {
587 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800588 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800590 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 } else {
592 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800593 ref_desc = f1_.CreateOffer(options, NULL);
594 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800596 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800598 desc->GetContentDescriptionByName("audio");
599 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800601 desc->GetContentDescriptionByName("video");
602 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
604 video_media_desc->cryptos()));
605 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800606 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 audio_media_desc->cryptos()[0].cipher_suite);
608
609 // Verify the selected crypto is one from the reference audio
610 // media content.
611 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800612 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 bool found = false;
614 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
615 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200616 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 found = true;
618 break;
619 }
620 }
621 EXPECT_TRUE(found);
622 }
623
624 // This test that the audio and video media direction is set to
625 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700626 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800628 RtpTransceiverDirection direction_in_offer,
629 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700630 MediaSessionOptions offer_opts;
631 AddAudioVideoSections(direction_in_offer, &offer_opts);
632
Steve Anton6fe1fba2018-12-11 10:15:23 -0800633 std::unique_ptr<SessionDescription> offer =
634 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000635 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700636 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000637 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700638 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640
zhihuang1c378ed2017-08-17 14:10:50 -0700641 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800642 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800643 std::unique_ptr<SessionDescription> answer =
644 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 const AudioContentDescription* acd_answer =
646 GetFirstAudioContentDescription(answer.get());
647 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
648 const VideoContentDescription* vcd_answer =
649 GetFirstVideoContentDescription(answer.get());
650 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
651 }
652
653 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800654 RTC_DCHECK(content);
655 RTC_CHECK(content->media_description());
656 const cricket::AudioContentDescription* audio_desc =
657 content->media_description()->as_audio();
658 RTC_CHECK(audio_desc);
659 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
660 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800662 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 }
664 return true;
665 }
666
jbauchcb560652016-08-04 05:20:32 -0700667 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
668 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800669 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700670 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700671
jbauchcb560652016-08-04 05:20:32 -0700672 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800673 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700674 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700675
jbauchcb560652016-08-04 05:20:32 -0700676 f1_.set_secure(SEC_ENABLED);
677 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800678 std::unique_ptr<SessionDescription> offer =
679 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700680 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800681 std::unique_ptr<SessionDescription> answer =
682 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700683 const ContentInfo* ac = answer->GetContentByName("audio");
684 const ContentInfo* vc = answer->GetContentByName("video");
685 ASSERT_TRUE(ac != NULL);
686 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800687 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
688 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800689 const AudioContentDescription* acd = ac->media_description()->as_audio();
690 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700691 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800692 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700693 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700694 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700695 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
696 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700697 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700698 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700699 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700700 }
701 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800702 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200703 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
704 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700705 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700706 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700707 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700708 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700709 }
Steve Antone38a5a12018-11-21 16:05:15 -0800710 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700711 }
712
Johannes Kronce8e8672019-02-22 13:06:44 +0100713 void TestTransportSequenceNumberNegotiation(
714 const cricket::RtpHeaderExtensions& local,
715 const cricket::RtpHeaderExtensions& offered,
716 const cricket::RtpHeaderExtensions& expectedAnswer) {
717 MediaSessionOptions opts;
718 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
719 f1_.set_audio_rtp_header_extensions(offered);
720 f1_.set_video_rtp_header_extensions(offered);
721 f2_.set_audio_rtp_header_extensions(local);
722 f2_.set_video_rtp_header_extensions(local);
723
724 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
725 ASSERT_TRUE(offer.get() != NULL);
726 std::unique_ptr<SessionDescription> answer =
727 f2_.CreateAnswer(offer.get(), opts, NULL);
728
729 EXPECT_EQ(
730 expectedAnswer,
731 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
732 EXPECT_EQ(
733 expectedAnswer,
734 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
735 }
736
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800738 UniqueRandomIdGenerator ssrc_generator1;
739 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000740 MediaSessionDescriptionFactory f1_;
741 MediaSessionDescriptionFactory f2_;
742 TransportDescriptionFactory tdf1_;
743 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000744};
745
746// Create a typical audio offer, and ensure it matches what we expect.
747TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
748 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800749 std::unique_ptr<SessionDescription> offer =
750 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751 ASSERT_TRUE(offer.get() != NULL);
752 const ContentInfo* ac = offer->GetContentByName("audio");
753 const ContentInfo* vc = offer->GetContentByName("video");
754 ASSERT_TRUE(ac != NULL);
755 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800756 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800757 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700759 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700760 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
762 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700763 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800764 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000765}
766
767// Create a typical video offer, and ensure it matches what we expect.
768TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
769 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800770 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800772 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 ASSERT_TRUE(offer.get() != NULL);
774 const ContentInfo* ac = offer->GetContentByName("audio");
775 const ContentInfo* vc = offer->GetContentByName("video");
776 ASSERT_TRUE(ac != NULL);
777 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800778 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
779 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800780 const AudioContentDescription* acd = ac->media_description()->as_audio();
781 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700783 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700784 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
786 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700787 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800788 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
790 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700791 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
793 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700794 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800795 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796}
797
798// Test creating an offer with bundle where the Codecs have the same dynamic
799// RTP playlod type. The test verifies that the offer don't contain the
800// duplicate RTP payload types.
801TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
802 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700803 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
805 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
806 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
807
808 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800809 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
810 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800812 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 const VideoContentDescription* vcd =
814 GetFirstVideoContentDescription(offer.get());
815 const AudioContentDescription* acd =
816 GetFirstAudioContentDescription(offer.get());
817 const DataContentDescription* dcd =
818 GetFirstDataContentDescription(offer.get());
819 ASSERT_TRUE(NULL != vcd);
820 ASSERT_TRUE(NULL != acd);
821 ASSERT_TRUE(NULL != dcd);
822 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
823 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
824 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
825 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
826 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
827 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
828}
829
zhihuang1c378ed2017-08-17 14:10:50 -0700830// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831// after an audio only session has been negotiated.
832TEST_F(MediaSessionDescriptionFactoryTest,
833 TestCreateUpdatedVideoOfferWithBundle) {
834 f1_.set_secure(SEC_ENABLED);
835 f2_.set_secure(SEC_ENABLED);
836 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800837 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
838 RtpTransceiverDirection::kRecvOnly, kActive,
839 &opts);
840 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
841 RtpTransceiverDirection::kInactive, kStopped,
842 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 opts.data_channel_type = cricket::DCT_NONE;
844 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800845 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
846 std::unique_ptr<SessionDescription> answer =
847 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848
849 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800850 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
851 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
852 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800854 std::unique_ptr<SessionDescription> updated_offer(
855 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856
857 const AudioContentDescription* acd =
858 GetFirstAudioContentDescription(updated_offer.get());
859 const VideoContentDescription* vcd =
860 GetFirstVideoContentDescription(updated_offer.get());
861 const DataContentDescription* dcd =
862 GetFirstDataContentDescription(updated_offer.get());
863 EXPECT_TRUE(NULL != vcd);
864 EXPECT_TRUE(NULL != acd);
865 EXPECT_TRUE(NULL != dcd);
866
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700867 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800868 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700869 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800870 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700871 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800872 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873}
deadbeef44f08192015-12-15 16:20:09 -0800874
wu@webrtc.org78187522013-10-07 23:32:02 +0000875// Create a RTP data offer, and ensure it matches what we expect.
876TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800878 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
879 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800881 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882 ASSERT_TRUE(offer.get() != NULL);
883 const ContentInfo* ac = offer->GetContentByName("audio");
884 const ContentInfo* dc = offer->GetContentByName("data");
885 ASSERT_TRUE(ac != NULL);
886 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800887 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
888 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800889 const AudioContentDescription* acd = ac->media_description()->as_audio();
890 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700892 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700893 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
895 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700896 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800897 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000898 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
899 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700900 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200902 dcd->bandwidth()); // default bandwidth (auto)
903 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700904 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800905 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000906}
907
wu@webrtc.org78187522013-10-07 23:32:02 +0000908// Create an SCTP data offer with bundle without error.
909TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
910 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000911 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800912 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000913 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800914 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000915 EXPECT_TRUE(offer.get() != NULL);
916 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
917}
918
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000919// Test creating an sctp data channel from an already generated offer.
920TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
921 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000922 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800923 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000924 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800925 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000926 ASSERT_TRUE(offer1.get() != NULL);
927 const ContentInfo* data = offer1->GetContentByName("data");
928 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800929 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000930
931 // Now set data_channel_type to 'none' (default) and make sure that the
932 // datachannel type that gets generated from the previous offer, is of the
933 // same type.
934 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800935 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000936 f1_.CreateOffer(opts, offer1.get()));
937 data = offer2->GetContentByName("data");
938 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800939 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000940}
941
Steve Anton2bed3972019-01-04 17:04:30 -0800942// Test that if BUNDLE is enabled and all media sections are rejected then the
943// BUNDLE group is not present in the re-offer.
944TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
945 MediaSessionOptions opts;
946 opts.bundle_enabled = true;
947 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
948 RtpTransceiverDirection::kSendRecv, kActive,
949 &opts);
950 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
951
952 opts.media_description_options[0].stopped = true;
953 std::unique_ptr<SessionDescription> reoffer =
954 f1_.CreateOffer(opts, offer.get());
955
956 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
957}
958
959// Test that if BUNDLE is enabled and the remote re-offer does not include a
960// BUNDLE group since all media sections are rejected, then the re-answer also
961// does not include a BUNDLE group.
962TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
963 MediaSessionOptions opts;
964 opts.bundle_enabled = true;
965 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
966 RtpTransceiverDirection::kSendRecv, kActive,
967 &opts);
968 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
969 std::unique_ptr<SessionDescription> answer =
970 f2_.CreateAnswer(offer.get(), opts, nullptr);
971
972 opts.media_description_options[0].stopped = true;
973 std::unique_ptr<SessionDescription> reoffer =
974 f1_.CreateOffer(opts, offer.get());
975 std::unique_ptr<SessionDescription> reanswer =
976 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
977
978 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
979}
980
981// Test that if BUNDLE is enabled and the previous offerer-tagged media section
982// was rejected then the new offerer-tagged media section is the non-rejected
983// media section.
984TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
985 MediaSessionOptions opts;
986 opts.bundle_enabled = true;
987 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
988 RtpTransceiverDirection::kSendRecv, kActive,
989 &opts);
990 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
991
992 // Reject the audio m= section and add a video m= section.
993 opts.media_description_options[0].stopped = true;
994 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
995 RtpTransceiverDirection::kSendRecv, kActive,
996 &opts);
997 std::unique_ptr<SessionDescription> reoffer =
998 f1_.CreateOffer(opts, offer.get());
999
1000 const cricket::ContentGroup* bundle_group =
1001 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1002 ASSERT_TRUE(bundle_group);
1003 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1004 EXPECT_TRUE(bundle_group->HasContentName("video"));
1005}
1006
1007// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1008// was rejected and a new media section is added, then the re-answer BUNDLE
1009// group will contain only the non-rejected media section.
1010TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1011 MediaSessionOptions opts;
1012 opts.bundle_enabled = true;
1013 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1014 RtpTransceiverDirection::kSendRecv, kActive,
1015 &opts);
1016 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1017 std::unique_ptr<SessionDescription> answer =
1018 f2_.CreateAnswer(offer.get(), opts, nullptr);
1019
1020 // Reject the audio m= section and add a video m= section.
1021 opts.media_description_options[0].stopped = true;
1022 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1023 RtpTransceiverDirection::kSendRecv, kActive,
1024 &opts);
1025 std::unique_ptr<SessionDescription> reoffer =
1026 f1_.CreateOffer(opts, offer.get());
1027 std::unique_ptr<SessionDescription> reanswer =
1028 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1029
1030 const cricket::ContentGroup* bundle_group =
1031 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1032 ASSERT_TRUE(bundle_group);
1033 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1034 EXPECT_TRUE(bundle_group->HasContentName("video"));
1035}
1036
1037// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1038// and there is still a non-rejected media section that was in the initial
1039// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1040// media section.
1041TEST_F(MediaSessionDescriptionFactoryTest,
1042 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1043 MediaSessionOptions opts;
1044 opts.bundle_enabled = true;
1045 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1046 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1047 std::unique_ptr<SessionDescription> answer =
1048 f2_.CreateAnswer(offer.get(), opts, nullptr);
1049
1050 // Reject the audio m= section.
1051 opts.media_description_options[0].stopped = true;
1052 std::unique_ptr<SessionDescription> reoffer =
1053 f1_.CreateOffer(opts, offer.get());
1054
1055 const TransportDescription* offer_tagged =
1056 offer->GetTransportDescriptionByName("audio");
1057 ASSERT_TRUE(offer_tagged);
1058 const TransportDescription* reoffer_tagged =
1059 reoffer->GetTransportDescriptionByName("video");
1060 ASSERT_TRUE(reoffer_tagged);
1061 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1062 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1063}
1064
1065// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1066// and there is still a non-rejected media section that was in the initial
1067// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1068// media section.
1069TEST_F(MediaSessionDescriptionFactoryTest,
1070 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1071 MediaSessionOptions opts;
1072 opts.bundle_enabled = true;
1073 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1074 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1075 std::unique_ptr<SessionDescription> answer =
1076 f2_.CreateAnswer(offer.get(), opts, nullptr);
1077
1078 // Reject the audio m= section.
1079 opts.media_description_options[0].stopped = true;
1080 std::unique_ptr<SessionDescription> reoffer =
1081 f1_.CreateOffer(opts, offer.get());
1082 std::unique_ptr<SessionDescription> reanswer =
1083 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1084
1085 const TransportDescription* answer_tagged =
1086 answer->GetTransportDescriptionByName("audio");
1087 ASSERT_TRUE(answer_tagged);
1088 const TransportDescription* reanswer_tagged =
1089 reanswer->GetTransportDescriptionByName("video");
1090 ASSERT_TRUE(reanswer_tagged);
1091 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1092 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1093}
1094
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001095// Create an audio, video offer without legacy StreamParams.
1096TEST_F(MediaSessionDescriptionFactoryTest,
1097 TestCreateOfferWithoutLegacyStreams) {
1098 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001099 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001100 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001101 ASSERT_TRUE(offer.get() != NULL);
1102 const ContentInfo* ac = offer->GetContentByName("audio");
1103 const ContentInfo* vc = offer->GetContentByName("video");
1104 ASSERT_TRUE(ac != NULL);
1105 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001106 const AudioContentDescription* acd = ac->media_description()->as_audio();
1107 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108
Yves Gerey665174f2018-06-19 15:03:05 +02001109 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1110 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111}
1112
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001113// Creates an audio+video sendonly offer.
1114TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001115 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001116 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001117 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1118 {kMediaStream1}, 1, &opts);
1119 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1120 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001121
Steve Anton6fe1fba2018-12-11 10:15:23 -08001122 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001123 ASSERT_TRUE(offer.get() != NULL);
1124 EXPECT_EQ(2u, offer->contents().size());
1125 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1126 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1127
Steve Anton4e70a722017-11-28 14:57:10 -08001128 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1129 GetMediaDirection(&offer->contents()[0]));
1130 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1131 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001132}
1133
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001134// Verifies that the order of the media contents in the current
1135// SessionDescription is preserved in the new SessionDescription.
1136TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1137 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001138 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001139
kwiberg31022942016-03-11 14:18:21 -08001140 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001141 ASSERT_TRUE(offer1.get() != NULL);
1142 EXPECT_EQ(1u, offer1->contents().size());
1143 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1144
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001145 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1146 RtpTransceiverDirection::kRecvOnly, kActive,
1147 &opts);
kwiberg31022942016-03-11 14:18:21 -08001148 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001149 f1_.CreateOffer(opts, offer1.get()));
1150 ASSERT_TRUE(offer2.get() != NULL);
1151 EXPECT_EQ(2u, offer2->contents().size());
1152 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1153 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1154
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001155 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1156 RtpTransceiverDirection::kRecvOnly, kActive,
1157 &opts);
kwiberg31022942016-03-11 14:18:21 -08001158 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001159 f1_.CreateOffer(opts, offer2.get()));
1160 ASSERT_TRUE(offer3.get() != NULL);
1161 EXPECT_EQ(3u, offer3->contents().size());
1162 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1163 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1164 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001165}
1166
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001167// Create a typical audio answer, and ensure it matches what we expect.
1168TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1169 f1_.set_secure(SEC_ENABLED);
1170 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001171 std::unique_ptr<SessionDescription> offer =
1172 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001173 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001174 std::unique_ptr<SessionDescription> answer =
1175 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001176 const ContentInfo* ac = answer->GetContentByName("audio");
1177 const ContentInfo* vc = answer->GetContentByName("video");
1178 ASSERT_TRUE(ac != NULL);
1179 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001180 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001181 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001182 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001183 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001184 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001185 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1186 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001187 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001188 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189}
1190
jbauchcb560652016-08-04 05:20:32 -07001191// Create a typical audio answer with GCM ciphers enabled, and ensure it
1192// matches what we expect.
1193TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1194 f1_.set_secure(SEC_ENABLED);
1195 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001196 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001197 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001198 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001199 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001200 std::unique_ptr<SessionDescription> answer =
1201 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001202 const ContentInfo* ac = answer->GetContentByName("audio");
1203 const ContentInfo* vc = answer->GetContentByName("video");
1204 ASSERT_TRUE(ac != NULL);
1205 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001206 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001207 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001208 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001209 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001210 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001211 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1212 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001213 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001214 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001215}
1216
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001217// Create a typical video answer, and ensure it matches what we expect.
1218TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1219 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001220 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 f1_.set_secure(SEC_ENABLED);
1222 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001223 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001225 std::unique_ptr<SessionDescription> answer =
1226 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227 const ContentInfo* ac = answer->GetContentByName("audio");
1228 const ContentInfo* vc = answer->GetContentByName("video");
1229 ASSERT_TRUE(ac != NULL);
1230 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001231 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1232 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001233 const AudioContentDescription* acd = ac->media_description()->as_audio();
1234 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001236 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001238 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001240 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001241 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001242 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001243 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1244 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001245 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001246 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247}
1248
jbauchcb560652016-08-04 05:20:32 -07001249// Create a typical video answer with GCM ciphers enabled, and ensure it
1250// matches what we expect.
1251TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1252 TestVideoGcmCipher(true, true);
1253}
1254
1255// Create a typical video answer with GCM ciphers enabled for the offer only,
1256// and ensure it matches what we expect.
1257TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1258 TestVideoGcmCipher(true, false);
1259}
1260
1261// Create a typical video answer with GCM ciphers enabled for the answer only,
1262// and ensure it matches what we expect.
1263TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1264 TestVideoGcmCipher(false, true);
1265}
1266
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001268 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001269 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270 f1_.set_secure(SEC_ENABLED);
1271 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001272 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001273 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001274 std::unique_ptr<SessionDescription> answer =
1275 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001277 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001279 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001280 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1281 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001282 const AudioContentDescription* acd = ac->media_description()->as_audio();
1283 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001284 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001285 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001287 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001288 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001289 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001290 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001291 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001292 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001293 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001294 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001295 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296}
1297
jbauchcb560652016-08-04 05:20:32 -07001298TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001299 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001300 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001301 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001302 f1_.set_secure(SEC_ENABLED);
1303 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001304 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001305 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001306 std::unique_ptr<SessionDescription> answer =
1307 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001308 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001309 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001310 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001311 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001312 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1313 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001314 const AudioContentDescription* acd = ac->media_description()->as_audio();
1315 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001316 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001317 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001318 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001319 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001320 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001321 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001322 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001323 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001324 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001325 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001326 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001327 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001328}
1329
1330// The use_sctpmap flag should be set in a DataContentDescription by default.
1331// The answer's use_sctpmap flag should match the offer's.
1332TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1333 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001334 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001335 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001336 ASSERT_TRUE(offer.get() != NULL);
1337 ContentInfo* dc_offer = offer->GetContentByName("data");
1338 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001339 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001340 EXPECT_TRUE(dcd_offer->use_sctpmap());
1341
Steve Anton6fe1fba2018-12-11 10:15:23 -08001342 std::unique_ptr<SessionDescription> answer =
1343 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001344 const ContentInfo* dc_answer = answer->GetContentByName("data");
1345 ASSERT_TRUE(dc_answer != NULL);
1346 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001347 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001348 EXPECT_TRUE(dcd_answer->use_sctpmap());
1349}
1350
1351// The answer's use_sctpmap flag should match the offer's.
1352TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1353 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001354 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001355 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001356 ASSERT_TRUE(offer.get() != NULL);
1357 ContentInfo* dc_offer = offer->GetContentByName("data");
1358 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001359 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001360 dcd_offer->set_use_sctpmap(false);
1361
Steve Anton6fe1fba2018-12-11 10:15:23 -08001362 std::unique_ptr<SessionDescription> answer =
1363 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001364 const ContentInfo* dc_answer = answer->GetContentByName("data");
1365 ASSERT_TRUE(dc_answer != NULL);
1366 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001367 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001368 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001369}
1370
deadbeef8b7e9ad2017-05-25 09:38:55 -07001371// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1372// and "TCP/DTLS/SCTP" offers.
1373TEST_F(MediaSessionDescriptionFactoryTest,
1374 TestCreateDataAnswerToDifferentOfferedProtos) {
1375 // Need to enable DTLS offer/answer generation (disabled by default in this
1376 // test).
1377 f1_.set_secure(SEC_ENABLED);
1378 f2_.set_secure(SEC_ENABLED);
1379 tdf1_.set_secure(SEC_ENABLED);
1380 tdf2_.set_secure(SEC_ENABLED);
1381
1382 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001383 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001384 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001385 ASSERT_TRUE(offer.get() != nullptr);
1386 ContentInfo* dc_offer = offer->GetContentByName("data");
1387 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001388 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001389
1390 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1391 "TCP/DTLS/SCTP"};
1392 for (const std::string& proto : protos) {
1393 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001394 std::unique_ptr<SessionDescription> answer =
1395 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001396 const ContentInfo* dc_answer = answer->GetContentByName("data");
1397 ASSERT_TRUE(dc_answer != nullptr);
1398 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001399 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001400 EXPECT_FALSE(dc_answer->rejected);
1401 EXPECT_EQ(proto, dcd_answer->protocol());
1402 }
1403}
1404
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001405// Verifies that the order of the media contents in the offer is preserved in
1406// the answer.
1407TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1408 MediaSessionOptions opts;
1409
1410 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001411 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001412 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001413 ASSERT_TRUE(offer1.get() != NULL);
1414
1415 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001416 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1417 RtpTransceiverDirection::kRecvOnly, kActive,
1418 &opts);
kwiberg31022942016-03-11 14:18:21 -08001419 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001420 f1_.CreateOffer(opts, offer1.get()));
1421 ASSERT_TRUE(offer2.get() != NULL);
1422
1423 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001424 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1425 RtpTransceiverDirection::kRecvOnly, kActive,
1426 &opts);
kwiberg31022942016-03-11 14:18:21 -08001427 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001428 f1_.CreateOffer(opts, offer2.get()));
1429 ASSERT_TRUE(offer3.get() != NULL);
1430
Steve Anton6fe1fba2018-12-11 10:15:23 -08001431 std::unique_ptr<SessionDescription> answer =
1432 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001433 ASSERT_TRUE(answer.get() != NULL);
1434 EXPECT_EQ(3u, answer->contents().size());
1435 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1436 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1437 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1438}
1439
ossu075af922016-06-14 03:29:38 -07001440// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1441// answerer settings.
1442
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001443// This test that the media direction is set to send/receive in an answer if
1444// the offer is send receive.
1445TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001446 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1447 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001448}
1449
1450// This test that the media direction is set to receive only in an answer if
1451// the offer is send only.
1452TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001453 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1454 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001455}
1456
1457// This test that the media direction is set to send only in an answer if
1458// the offer is recv only.
1459TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001460 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1461 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001462}
1463
1464// This test that the media direction is set to inactive in an answer if
1465// the offer is inactive.
1466TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001467 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1468 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001469}
1470
1471// Test that a data content with an unknown protocol is rejected in an answer.
1472TEST_F(MediaSessionDescriptionFactoryTest,
1473 CreateDataAnswerToOfferWithUnknownProtocol) {
1474 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001475 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001476 f1_.set_secure(SEC_ENABLED);
1477 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001478 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001479 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001480 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001481 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001482 ASSERT_TRUE(dcd_offer != NULL);
1483 std::string protocol = "a weird unknown protocol";
1484 dcd_offer->set_protocol(protocol);
1485
Steve Anton6fe1fba2018-12-11 10:15:23 -08001486 std::unique_ptr<SessionDescription> answer =
1487 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001488
1489 const ContentInfo* dc_answer = answer->GetContentByName("data");
1490 ASSERT_TRUE(dc_answer != NULL);
1491 EXPECT_TRUE(dc_answer->rejected);
1492 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001493 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494 ASSERT_TRUE(dcd_answer != NULL);
1495 EXPECT_EQ(protocol, dcd_answer->protocol());
1496}
1497
1498// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1499TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001500 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001501 f1_.set_secure(SEC_DISABLED);
1502 f2_.set_secure(SEC_DISABLED);
1503 tdf1_.set_secure(SEC_DISABLED);
1504 tdf2_.set_secure(SEC_DISABLED);
1505
Steve Anton6fe1fba2018-12-11 10:15:23 -08001506 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507 const AudioContentDescription* offer_acd =
1508 GetFirstAudioContentDescription(offer.get());
1509 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001510 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001511
Steve Anton6fe1fba2018-12-11 10:15:23 -08001512 std::unique_ptr<SessionDescription> answer =
1513 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001514
1515 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1516 ASSERT_TRUE(ac_answer != NULL);
1517 EXPECT_FALSE(ac_answer->rejected);
1518
1519 const AudioContentDescription* answer_acd =
1520 GetFirstAudioContentDescription(answer.get());
1521 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001522 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001523}
1524
1525// Create a video offer and answer and ensure the RTP header extensions
1526// matches what we expect.
1527TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1528 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001529 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001530 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1531 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1532 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1533 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1534
Steve Anton6fe1fba2018-12-11 10:15:23 -08001535 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001536 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001537 std::unique_ptr<SessionDescription> answer =
1538 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001539
Yves Gerey665174f2018-06-19 15:03:05 +02001540 EXPECT_EQ(
1541 MAKE_VECTOR(kAudioRtpExtension1),
1542 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1543 EXPECT_EQ(
1544 MAKE_VECTOR(kVideoRtpExtension1),
1545 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1546 EXPECT_EQ(
1547 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1548 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1549 EXPECT_EQ(
1550 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1551 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001552}
1553
Johannes Kronce8e8672019-02-22 13:06:44 +01001554// Create a audio/video offer and answer and ensure that the
1555// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1556// supported and should take precedence even though not listed among locally
1557// supported extensions.
1558TEST_F(MediaSessionDescriptionFactoryTest,
1559 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1560 TestTransportSequenceNumberNegotiation(
1561 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1562 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1563 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1564}
1565TEST_F(MediaSessionDescriptionFactoryTest,
1566 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1567 TestTransportSequenceNumberNegotiation(
1568 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1569 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1570 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1571}
1572TEST_F(MediaSessionDescriptionFactoryTest,
1573 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1574 TestTransportSequenceNumberNegotiation(
1575 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1576 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1577 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1578}
1579
jbauch5869f502017-06-29 12:31:36 -07001580TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001581 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001582 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001583 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001584
1585 f1_.set_enable_encrypted_rtp_header_extensions(true);
1586 f2_.set_enable_encrypted_rtp_header_extensions(true);
1587
Yves Gerey665174f2018-06-19 15:03:05 +02001588 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1589 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1590 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1591 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001592
Steve Anton6fe1fba2018-12-11 10:15:23 -08001593 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001594 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001595 std::unique_ptr<SessionDescription> answer =
1596 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001597
Yves Gerey665174f2018-06-19 15:03:05 +02001598 EXPECT_EQ(
1599 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1600 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1601 EXPECT_EQ(
1602 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1603 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1604 EXPECT_EQ(
1605 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1606 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1607 EXPECT_EQ(
1608 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1609 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001610}
1611
1612TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001613 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001614 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001615 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001616
1617 f1_.set_enable_encrypted_rtp_header_extensions(true);
1618
Yves Gerey665174f2018-06-19 15:03:05 +02001619 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1620 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1621 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1622 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001623
Steve Anton6fe1fba2018-12-11 10:15:23 -08001624 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001625 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001626 std::unique_ptr<SessionDescription> answer =
1627 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001628
Yves Gerey665174f2018-06-19 15:03:05 +02001629 EXPECT_EQ(
1630 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1631 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1632 EXPECT_EQ(
1633 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1634 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1635 EXPECT_EQ(
1636 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1637 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1638 EXPECT_EQ(
1639 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1640 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001641}
1642
1643TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001644 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001645 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001646 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001647
1648 f2_.set_enable_encrypted_rtp_header_extensions(true);
1649
Yves Gerey665174f2018-06-19 15:03:05 +02001650 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1651 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1652 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1653 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001654
Steve Anton6fe1fba2018-12-11 10:15:23 -08001655 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001656 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001657 std::unique_ptr<SessionDescription> answer =
1658 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001659
Yves Gerey665174f2018-06-19 15:03:05 +02001660 EXPECT_EQ(
1661 MAKE_VECTOR(kAudioRtpExtension1),
1662 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1663 EXPECT_EQ(
1664 MAKE_VECTOR(kVideoRtpExtension1),
1665 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1666 EXPECT_EQ(
1667 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1668 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1669 EXPECT_EQ(
1670 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1671 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001672}
1673
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001674// Create an audio, video, data answer without legacy StreamParams.
1675TEST_F(MediaSessionDescriptionFactoryTest,
1676 TestCreateAnswerWithoutLegacyStreams) {
1677 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001678 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1679 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001680 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001681 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001682 std::unique_ptr<SessionDescription> answer =
1683 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001684 const ContentInfo* ac = answer->GetContentByName("audio");
1685 const ContentInfo* vc = answer->GetContentByName("video");
1686 const ContentInfo* dc = answer->GetContentByName("data");
1687 ASSERT_TRUE(ac != NULL);
1688 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001689 const AudioContentDescription* acd = ac->media_description()->as_audio();
1690 const VideoContentDescription* vcd = vc->media_description()->as_video();
1691 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001692
1693 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1694 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1695 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1696}
1697
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698// Create a typical video answer, and ensure it matches what we expect.
1699TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1700 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001701 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1702 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1703 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001704
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001705 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001706 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1707 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1708 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001709
kwiberg31022942016-03-11 14:18:21 -08001710 std::unique_ptr<SessionDescription> offer;
1711 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001712
1713 offer_opts.rtcp_mux_enabled = true;
1714 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001715 offer = f1_.CreateOffer(offer_opts, NULL);
1716 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001717 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1718 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1719 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1720 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1721 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1722 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1723 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1724 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1725 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1726 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1727 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1728 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1729
1730 offer_opts.rtcp_mux_enabled = true;
1731 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001732 offer = f1_.CreateOffer(offer_opts, NULL);
1733 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001734 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1735 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1736 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1737 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1738 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1739 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1740 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1741 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1742 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1743 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1744 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1745 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1746
1747 offer_opts.rtcp_mux_enabled = false;
1748 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001749 offer = f1_.CreateOffer(offer_opts, NULL);
1750 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001751 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1752 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1753 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1754 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1755 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1756 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1757 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1758 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1759 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1760 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1761 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1762 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1763
1764 offer_opts.rtcp_mux_enabled = false;
1765 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001766 offer = f1_.CreateOffer(offer_opts, NULL);
1767 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001768 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1769 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1770 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1771 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1772 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1773 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1774 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1775 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1776 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1777 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1778 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1779 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1780}
1781
1782// Create an audio-only answer to a video offer.
1783TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1784 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001785 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1786 RtpTransceiverDirection::kRecvOnly, kActive,
1787 &opts);
1788 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1789 RtpTransceiverDirection::kRecvOnly, kActive,
1790 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001791 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001792 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001793
1794 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001795 std::unique_ptr<SessionDescription> answer =
1796 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001797 const ContentInfo* ac = answer->GetContentByName("audio");
1798 const ContentInfo* vc = answer->GetContentByName("video");
1799 ASSERT_TRUE(ac != NULL);
1800 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001801 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001802 EXPECT_TRUE(vc->rejected);
1803}
1804
1805// Create an audio-only answer to an offer with data.
1806TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001807 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001808 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001809 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1810 RtpTransceiverDirection::kRecvOnly, kActive,
1811 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001812 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001813 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001814
1815 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001816 std::unique_ptr<SessionDescription> answer =
1817 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001818 const ContentInfo* ac = answer->GetContentByName("audio");
1819 const ContentInfo* dc = answer->GetContentByName("data");
1820 ASSERT_TRUE(ac != NULL);
1821 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001822 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001823 EXPECT_TRUE(dc->rejected);
1824}
1825
1826// Create an answer that rejects the contents which are rejected in the offer.
1827TEST_F(MediaSessionDescriptionFactoryTest,
1828 CreateAnswerToOfferWithRejectedMedia) {
1829 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001830 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1831 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001832 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001833 ASSERT_TRUE(offer.get() != NULL);
1834 ContentInfo* ac = offer->GetContentByName("audio");
1835 ContentInfo* vc = offer->GetContentByName("video");
1836 ContentInfo* dc = offer->GetContentByName("data");
1837 ASSERT_TRUE(ac != NULL);
1838 ASSERT_TRUE(vc != NULL);
1839 ASSERT_TRUE(dc != NULL);
1840 ac->rejected = true;
1841 vc->rejected = true;
1842 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001843 std::unique_ptr<SessionDescription> answer =
1844 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001845 ac = answer->GetContentByName("audio");
1846 vc = answer->GetContentByName("video");
1847 dc = answer->GetContentByName("data");
1848 ASSERT_TRUE(ac != NULL);
1849 ASSERT_TRUE(vc != NULL);
1850 ASSERT_TRUE(dc != NULL);
1851 EXPECT_TRUE(ac->rejected);
1852 EXPECT_TRUE(vc->rejected);
1853 EXPECT_TRUE(dc->rejected);
1854}
1855
Johannes Kron0854eb62018-10-10 22:33:20 +02001856TEST_F(MediaSessionDescriptionFactoryTest,
1857 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1858 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001859 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001860 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001861 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001862 ASSERT_TRUE(offer.get() != NULL);
1863 std::unique_ptr<SessionDescription> answer_no_support(
1864 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001865 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001866
1867 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001868 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001869 ASSERT_TRUE(offer.get() != NULL);
1870 std::unique_ptr<SessionDescription> answer_support(
1871 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001872 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001873}
1874
1875TEST_F(MediaSessionDescriptionFactoryTest,
1876 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1877 MediaSessionOptions opts;
1878 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001879 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001880 MediaContentDescription* video_offer =
1881 offer->GetContentDescriptionByName("video");
1882 ASSERT_TRUE(video_offer);
1883 MediaContentDescription* audio_offer =
1884 offer->GetContentDescriptionByName("audio");
1885 ASSERT_TRUE(audio_offer);
1886
1887 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001888 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1889 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001890
1891 ASSERT_TRUE(offer.get() != NULL);
1892 std::unique_ptr<SessionDescription> answer_no_support(
1893 f2_.CreateAnswer(offer.get(), opts, NULL));
1894 MediaContentDescription* video_answer =
1895 answer_no_support->GetContentDescriptionByName("video");
1896 MediaContentDescription* audio_answer =
1897 answer_no_support->GetContentDescriptionByName("audio");
1898 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001899 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001900 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001901 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001902
1903 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001904 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1905 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001906 ASSERT_TRUE(offer.get() != NULL);
1907 std::unique_ptr<SessionDescription> answer_support(
1908 f2_.CreateAnswer(offer.get(), opts, NULL));
1909 video_answer = answer_support->GetContentDescriptionByName("video");
1910 audio_answer = answer_support->GetContentDescriptionByName("audio");
1911 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001912 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001913 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001914 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001915}
1916
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001917// Create an audio and video offer with:
1918// - one video track
1919// - two audio tracks
1920// - two data tracks
1921// and ensure it matches what we expect. Also updates the initial offer by
1922// adding a new video track and replaces one of the audio tracks.
1923TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1924 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001925 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001926 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1927 {kMediaStream1}, 1, &opts);
1928 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1929 {kMediaStream1}, 1, &opts);
1930 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1931 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001932
Steve Anton4e70a722017-11-28 14:57:10 -08001933 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001934 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1935 {kMediaStream1}, 1, &opts);
1936 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1937 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001938
1939 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941
1942 ASSERT_TRUE(offer.get() != NULL);
1943 const ContentInfo* ac = offer->GetContentByName("audio");
1944 const ContentInfo* vc = offer->GetContentByName("video");
1945 const ContentInfo* dc = offer->GetContentByName("data");
1946 ASSERT_TRUE(ac != NULL);
1947 ASSERT_TRUE(vc != NULL);
1948 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001949 const AudioContentDescription* acd = ac->media_description()->as_audio();
1950 const VideoContentDescription* vcd = vc->media_description()->as_video();
1951 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001952 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001953 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001954
1955 const StreamParamsVec& audio_streams = acd->streams();
1956 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001957 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001958 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1959 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1960 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1961 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1962 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1963 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1964
1965 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1966 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001967 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001968
1969 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1970 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001971 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001972
1973 const StreamParamsVec& video_streams = vcd->streams();
1974 ASSERT_EQ(1U, video_streams.size());
1975 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1976 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1977 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1978 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1979
1980 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1981 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001982 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983
1984 const StreamParamsVec& data_streams = dcd->streams();
1985 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001986 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001987 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1988 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1989 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1990 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1991 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1992 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1993
1994 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001995 dcd->bandwidth()); // default bandwidth (auto)
1996 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001997 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001998
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999 // Update the offer. Add a new video track that is not synched to the
2000 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002001 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2002 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002003 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002004 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2005 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002006 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002007 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2008 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002009 std::unique_ptr<SessionDescription> updated_offer(
2010 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011
2012 ASSERT_TRUE(updated_offer.get() != NULL);
2013 ac = updated_offer->GetContentByName("audio");
2014 vc = updated_offer->GetContentByName("video");
2015 dc = updated_offer->GetContentByName("data");
2016 ASSERT_TRUE(ac != NULL);
2017 ASSERT_TRUE(vc != NULL);
2018 ASSERT_TRUE(dc != NULL);
2019 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002020 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002021 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002022 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002023 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002024 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025
2026 EXPECT_EQ(acd->type(), updated_acd->type());
2027 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2028 EXPECT_EQ(vcd->type(), updated_vcd->type());
2029 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2030 EXPECT_EQ(dcd->type(), updated_dcd->type());
2031 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002032 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002033 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002034 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002035 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002036 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002037 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2038
2039 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2040 ASSERT_EQ(2U, updated_audio_streams.size());
2041 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2042 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2043 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2044 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2045 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2046
2047 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2048 ASSERT_EQ(2U, updated_video_streams.size());
2049 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2050 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002051 // All the media streams in one PeerConnection share one RTCP CNAME.
2052 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002053
2054 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2055 ASSERT_EQ(2U, updated_data_streams.size());
2056 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2057 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2058 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2059 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2060 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002061 // The stream correctly got the CNAME from the MediaSessionOptions.
2062 // The Expected RTCP CNAME is the default one as we are using the default
2063 // MediaSessionOptions.
2064 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065}
2066
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002067// Create an offer with simulcast video stream.
2068TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2069 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002070 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2071 RtpTransceiverDirection::kRecvOnly, kActive,
2072 &opts);
2073 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2074 RtpTransceiverDirection::kSendRecv, kActive,
2075 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002076 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002077 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2078 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002079 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002080
2081 ASSERT_TRUE(offer.get() != NULL);
2082 const ContentInfo* vc = offer->GetContentByName("video");
2083 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002084 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002085
2086 const StreamParamsVec& video_streams = vcd->streams();
2087 ASSERT_EQ(1U, video_streams.size());
2088 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2089 const SsrcGroup* sim_ssrc_group =
2090 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2091 ASSERT_TRUE(sim_ssrc_group != NULL);
2092 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2093}
2094
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002095MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2096 const RidDescription& rid1 = ::testing::get<0>(arg);
2097 const RidDescription& rid2 = ::testing::get<1>(arg);
2098 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2099}
2100
2101static void CheckSimulcastInSessionDescription(
2102 const SessionDescription* description,
2103 const std::string& content_name,
2104 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002105 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002106 ASSERT_NE(description, nullptr);
2107 const ContentInfo* content = description->GetContentByName(content_name);
2108 ASSERT_NE(content, nullptr);
2109 const MediaContentDescription* cd = content->media_description();
2110 ASSERT_NE(cd, nullptr);
2111 const StreamParamsVec& streams = cd->streams();
2112 ASSERT_THAT(streams, SizeIs(1));
2113 const StreamParams& stream = streams[0];
2114 ASSERT_THAT(stream.ssrcs, IsEmpty());
2115 EXPECT_TRUE(stream.has_rids());
2116 const std::vector<RidDescription> rids = stream.rids();
2117
2118 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2119
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002120 EXPECT_TRUE(cd->HasSimulcast());
2121 const SimulcastDescription& simulcast = cd->simulcast_description();
2122 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2123 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2124
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002125 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002126}
2127
2128// Create an offer with spec-compliant simulcast video stream.
2129TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2130 MediaSessionOptions opts;
2131 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2132 RtpTransceiverDirection::kSendRecv, kActive,
2133 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002134 std::vector<RidDescription> send_rids;
2135 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2136 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2137 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2138 SimulcastLayerList simulcast_layers;
2139 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2140 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2141 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2142 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2143 {kMediaStream1}, send_rids,
2144 simulcast_layers, 0, &opts);
2145 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2146
2147 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002148 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002149}
2150
2151// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2152// In this scenario, RIDs do not need to be negotiated (there is only one).
2153TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2154 MediaSessionOptions opts;
2155 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2156 RtpTransceiverDirection::kSendRecv, kActive,
2157 &opts);
2158 RidDescription rid("f", RidDirection::kSend);
2159 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2160 {kMediaStream1}, {rid},
2161 SimulcastLayerList(), 0, &opts);
2162 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2163
2164 ASSERT_NE(offer.get(), nullptr);
2165 const ContentInfo* content = offer->GetContentByName("video");
2166 ASSERT_NE(content, nullptr);
2167 const MediaContentDescription* cd = content->media_description();
2168 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002169 const StreamParamsVec& streams = cd->streams();
2170 ASSERT_THAT(streams, SizeIs(1));
2171 const StreamParams& stream = streams[0];
2172 ASSERT_THAT(stream.ssrcs, IsEmpty());
2173 EXPECT_FALSE(stream.has_rids());
2174 EXPECT_FALSE(cd->HasSimulcast());
2175}
2176
2177// Create an answer with spec-compliant simulcast video stream.
2178// In this scenario, the SFU is the caller requesting that we send Simulcast.
2179TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2180 MediaSessionOptions offer_opts;
2181 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2182 RtpTransceiverDirection::kSendRecv, kActive,
2183 &offer_opts);
2184 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2185 {kMediaStream1}, 1, &offer_opts);
2186 std::unique_ptr<SessionDescription> offer =
2187 f1_.CreateOffer(offer_opts, nullptr);
2188
2189 MediaSessionOptions answer_opts;
2190 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2191 RtpTransceiverDirection::kSendRecv, kActive,
2192 &answer_opts);
2193
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002194 std::vector<RidDescription> rid_descriptions{
2195 RidDescription("f", RidDirection::kSend),
2196 RidDescription("h", RidDirection::kSend),
2197 RidDescription("q", RidDirection::kSend),
2198 };
2199 SimulcastLayerList simulcast_layers;
2200 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2201 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2202 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2203 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2204 {kMediaStream1}, rid_descriptions,
2205 simulcast_layers, 0, &answer_opts);
2206 std::unique_ptr<SessionDescription> answer =
2207 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2208
2209 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002210 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002211}
2212
2213// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2214// In this scenario, RIDs do not need to be negotiated (there is only one).
2215// Note that RID Direction is not the same as the transceiver direction.
2216TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2217 MediaSessionOptions offer_opts;
2218 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2219 RtpTransceiverDirection::kSendRecv, kActive,
2220 &offer_opts);
2221 RidDescription rid_offer("f", RidDirection::kSend);
2222 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2223 {kMediaStream1}, {rid_offer},
2224 SimulcastLayerList(), 0, &offer_opts);
2225 std::unique_ptr<SessionDescription> offer =
2226 f1_.CreateOffer(offer_opts, nullptr);
2227
2228 MediaSessionOptions answer_opts;
2229 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2230 RtpTransceiverDirection::kSendRecv, kActive,
2231 &answer_opts);
2232
2233 RidDescription rid_answer("f", RidDirection::kReceive);
2234 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2235 {kMediaStream1}, {rid_answer},
2236 SimulcastLayerList(), 0, &answer_opts);
2237 std::unique_ptr<SessionDescription> answer =
2238 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2239
2240 ASSERT_NE(answer.get(), nullptr);
2241 const ContentInfo* content = offer->GetContentByName("video");
2242 ASSERT_NE(content, nullptr);
2243 const MediaContentDescription* cd = content->media_description();
2244 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002245 const StreamParamsVec& streams = cd->streams();
2246 ASSERT_THAT(streams, SizeIs(1));
2247 const StreamParams& stream = streams[0];
2248 ASSERT_THAT(stream.ssrcs, IsEmpty());
2249 EXPECT_FALSE(stream.has_rids());
2250 EXPECT_FALSE(cd->HasSimulcast());
2251}
2252
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002253// Create an audio and video answer to a standard video offer with:
2254// - one video track
2255// - two audio tracks
2256// - two data tracks
2257// and ensure it matches what we expect. Also updates the initial answer by
2258// adding a new video track and removes one of the audio tracks.
2259TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2260 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002261 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2262 RtpTransceiverDirection::kRecvOnly, kActive,
2263 &offer_opts);
2264 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2265 RtpTransceiverDirection::kRecvOnly, kActive,
2266 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002267 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002268 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2269 RtpTransceiverDirection::kRecvOnly, kActive,
2270 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002271 f1_.set_secure(SEC_ENABLED);
2272 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002273 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002274
zhihuang1c378ed2017-08-17 14:10:50 -07002275 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002276 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2277 RtpTransceiverDirection::kSendRecv, kActive,
2278 &answer_opts);
2279 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2280 RtpTransceiverDirection::kSendRecv, kActive,
2281 &answer_opts);
2282 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2283 {kMediaStream1}, 1, &answer_opts);
2284 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2285 {kMediaStream1}, 1, &answer_opts);
2286 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2287 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002288
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002289 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2290 RtpTransceiverDirection::kSendRecv, kActive,
2291 &answer_opts);
2292 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2293 {kMediaStream1}, 1, &answer_opts);
2294 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2295 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002296 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002297
Steve Anton6fe1fba2018-12-11 10:15:23 -08002298 std::unique_ptr<SessionDescription> answer =
2299 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002300
2301 ASSERT_TRUE(answer.get() != NULL);
2302 const ContentInfo* ac = answer->GetContentByName("audio");
2303 const ContentInfo* vc = answer->GetContentByName("video");
2304 const ContentInfo* dc = answer->GetContentByName("data");
2305 ASSERT_TRUE(ac != NULL);
2306 ASSERT_TRUE(vc != NULL);
2307 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002308 const AudioContentDescription* acd = ac->media_description()->as_audio();
2309 const VideoContentDescription* vcd = vc->media_description()->as_video();
2310 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002311 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2312 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2313 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002314
2315 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002316 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002317
2318 const StreamParamsVec& audio_streams = acd->streams();
2319 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002320 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002321 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2322 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2323 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2324 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2325 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2326 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2327
2328 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2329 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2330
2331 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002332 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002333
2334 const StreamParamsVec& video_streams = vcd->streams();
2335 ASSERT_EQ(1U, video_streams.size());
2336 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2337 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2338 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2339 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2340
2341 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002342 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002343
2344 const StreamParamsVec& data_streams = dcd->streams();
2345 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002346 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002347 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2348 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2349 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2350 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2351 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2352 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2353
2354 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002355 dcd->bandwidth()); // default bandwidth (auto)
2356 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002357
2358 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002359 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002360 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2361 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002362 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2363 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002364 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002365 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002366
2367 ASSERT_TRUE(updated_answer.get() != NULL);
2368 ac = updated_answer->GetContentByName("audio");
2369 vc = updated_answer->GetContentByName("video");
2370 dc = updated_answer->GetContentByName("data");
2371 ASSERT_TRUE(ac != NULL);
2372 ASSERT_TRUE(vc != NULL);
2373 ASSERT_TRUE(dc != NULL);
2374 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002375 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002376 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002377 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002378 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002379 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002380
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002381 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002383 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002384 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002385 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002386 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2387
2388 EXPECT_EQ(acd->type(), updated_acd->type());
2389 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2390 EXPECT_EQ(vcd->type(), updated_vcd->type());
2391 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2392 EXPECT_EQ(dcd->type(), updated_dcd->type());
2393 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2394
2395 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2396 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002397 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002398
2399 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2400 ASSERT_EQ(2U, updated_video_streams.size());
2401 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2402 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002403 // All media streams in one PeerConnection share one CNAME.
2404 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002405
2406 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2407 ASSERT_EQ(1U, updated_data_streams.size());
2408 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2409}
2410
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002411// Create an updated offer after creating an answer to the original offer and
2412// verify that the codecs that were part of the original answer are not changed
2413// in the updated offer.
2414TEST_F(MediaSessionDescriptionFactoryTest,
2415 RespondentCreatesOfferAfterCreatingAnswer) {
2416 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002417 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002418
Steve Anton6fe1fba2018-12-11 10:15:23 -08002419 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2420 std::unique_ptr<SessionDescription> answer =
2421 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002422
2423 const AudioContentDescription* acd =
2424 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002425 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002426
2427 const VideoContentDescription* vcd =
2428 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002429 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002430
kwiberg31022942016-03-11 14:18:21 -08002431 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432 f2_.CreateOffer(opts, answer.get()));
2433
2434 // The expected audio codecs are the common audio codecs from the first
2435 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2436 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002437 // TODO(wu): |updated_offer| should not include the codec
2438 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002439 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002440 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002441 };
2442
2443 // The expected video codecs are the common video codecs from the first
2444 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2445 // preference order.
2446 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002447 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002448 };
2449
2450 const AudioContentDescription* updated_acd =
2451 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002452 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002453
2454 const VideoContentDescription* updated_vcd =
2455 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002456 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002457}
2458
Steve Anton5c72e712018-12-10 14:25:30 -08002459// Test that a reoffer does not reuse audio codecs from a previous media section
2460// that is being recycled.
2461TEST_F(MediaSessionDescriptionFactoryTest,
2462 ReOfferDoesNotReUseRecycledAudioCodecs) {
2463 f1_.set_video_codecs({});
2464 f2_.set_video_codecs({});
2465
2466 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002467 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2468 RtpTransceiverDirection::kSendRecv, kActive,
2469 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002470 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2471 std::unique_ptr<SessionDescription> answer =
2472 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002473
2474 // Recycle the media section by changing its mid.
2475 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002476 std::unique_ptr<SessionDescription> reoffer =
2477 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002478
2479 // Expect that the results of the first negotiation are ignored. If the m=
2480 // section was not recycled the payload types would match the initial offerer.
2481 const AudioContentDescription* acd =
2482 GetFirstAudioContentDescription(reoffer.get());
2483 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2484}
2485
2486// Test that a reoffer does not reuse video codecs from a previous media section
2487// that is being recycled.
2488TEST_F(MediaSessionDescriptionFactoryTest,
2489 ReOfferDoesNotReUseRecycledVideoCodecs) {
2490 f1_.set_audio_codecs({}, {});
2491 f2_.set_audio_codecs({}, {});
2492
2493 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002494 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2495 RtpTransceiverDirection::kSendRecv, kActive,
2496 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002497 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2498 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002499
2500 // Recycle the media section by changing its mid.
2501 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002502 std::unique_ptr<SessionDescription> reoffer =
2503 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002504
2505 // Expect that the results of the first negotiation are ignored. If the m=
2506 // section was not recycled the payload types would match the initial offerer.
2507 const VideoContentDescription* vcd =
2508 GetFirstVideoContentDescription(reoffer.get());
2509 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2510}
2511
2512// Test that a reanswer does not reuse audio codecs from a previous media
2513// section that is being recycled.
2514TEST_F(MediaSessionDescriptionFactoryTest,
2515 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2516 f1_.set_video_codecs({});
2517 f2_.set_video_codecs({});
2518
2519 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2520 // second offer/answer is forward (|f1_| as offerer).
2521 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002522 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2523 RtpTransceiverDirection::kSendRecv, kActive,
2524 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002525 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2526 std::unique_ptr<SessionDescription> answer =
2527 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002528
2529 // Recycle the media section by changing its mid.
2530 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002531 std::unique_ptr<SessionDescription> reoffer =
2532 f1_.CreateOffer(opts, answer.get());
2533 std::unique_ptr<SessionDescription> reanswer =
2534 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002535
2536 // Expect that the results of the first negotiation are ignored. If the m=
2537 // section was not recycled the payload types would match the initial offerer.
2538 const AudioContentDescription* acd =
2539 GetFirstAudioContentDescription(reanswer.get());
2540 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2541}
2542
2543// Test that a reanswer does not reuse video codecs from a previous media
2544// section that is being recycled.
2545TEST_F(MediaSessionDescriptionFactoryTest,
2546 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2547 f1_.set_audio_codecs({}, {});
2548 f2_.set_audio_codecs({}, {});
2549
2550 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2551 // second offer/answer is forward (|f1_| as offerer).
2552 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002553 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2554 RtpTransceiverDirection::kSendRecv, kActive,
2555 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002556 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2557 std::unique_ptr<SessionDescription> answer =
2558 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002559
2560 // Recycle the media section by changing its mid.
2561 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002562 std::unique_ptr<SessionDescription> reoffer =
2563 f1_.CreateOffer(opts, answer.get());
2564 std::unique_ptr<SessionDescription> reanswer =
2565 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002566
2567 // Expect that the results of the first negotiation are ignored. If the m=
2568 // section was not recycled the payload types would match the initial offerer.
2569 const VideoContentDescription* vcd =
2570 GetFirstVideoContentDescription(reanswer.get());
2571 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2572}
2573
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002574// Create an updated offer after creating an answer to the original offer and
2575// verify that the codecs that were part of the original answer are not changed
2576// in the updated offer. In this test Rtx is enabled.
2577TEST_F(MediaSessionDescriptionFactoryTest,
2578 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2579 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002580 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2581 RtpTransceiverDirection::kRecvOnly, kActive,
2582 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002583 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002584 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002585 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002586 f1_.set_video_codecs(f1_codecs);
2587
2588 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002589 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002590 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002591 f2_.set_video_codecs(f2_codecs);
2592
Steve Anton6fe1fba2018-12-11 10:15:23 -08002593 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002594 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002595 std::unique_ptr<SessionDescription> answer =
2596 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002597
2598 const VideoContentDescription* vcd =
2599 GetFirstVideoContentDescription(answer.get());
2600
2601 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002602 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2603 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002604
2605 EXPECT_EQ(expected_codecs, vcd->codecs());
2606
deadbeef67cf2c12016-04-13 10:07:16 -07002607 // Now, make sure we get same result (except for the order) if |f2_| creates
2608 // an updated offer even though the default payload types between |f1_| and
2609 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002610 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002611 f2_.CreateOffer(opts, answer.get()));
2612 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002613 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002614 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2615
2616 const VideoContentDescription* updated_vcd =
2617 GetFirstVideoContentDescription(updated_answer.get());
2618
2619 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2620}
2621
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002622// Regression test for:
2623// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2624// Existing codecs should always appear before new codecs in re-offers. But
2625// under a specific set of circumstances, the existing RTX codec was ending up
2626// added to the end of the list.
2627TEST_F(MediaSessionDescriptionFactoryTest,
2628 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2629 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002630 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2631 RtpTransceiverDirection::kRecvOnly, kActive,
2632 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002633 // We specifically choose different preferred payload types for VP8 to
2634 // trigger the issue.
2635 cricket::VideoCodec vp8_offerer(100, "VP8");
2636 cricket::VideoCodec vp8_offerer_rtx =
2637 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2638 cricket::VideoCodec vp8_answerer(110, "VP8");
2639 cricket::VideoCodec vp8_answerer_rtx =
2640 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2641 cricket::VideoCodec vp9(120, "VP9");
2642 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2643
2644 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2645 // We also specifically cause the answerer to prefer VP9, such that if it
2646 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2647 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2648 vp8_answerer_rtx};
2649
2650 f1_.set_video_codecs(f1_codecs);
2651 f2_.set_video_codecs(f2_codecs);
2652 std::vector<AudioCodec> audio_codecs;
2653 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2654 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2655
2656 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002657 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002658 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002659 std::unique_ptr<SessionDescription> answer =
2660 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002661
2662 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2663 // But if the bug is triggered, RTX for VP8 ends up last.
2664 std::unique_ptr<SessionDescription> updated_offer(
2665 f2_.CreateOffer(opts, answer.get()));
2666
2667 const VideoContentDescription* vcd =
2668 GetFirstVideoContentDescription(updated_offer.get());
2669 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2670 ASSERT_EQ(4u, codecs.size());
2671 EXPECT_EQ(vp8_offerer, codecs[0]);
2672 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2673 EXPECT_EQ(vp9, codecs[2]);
2674 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002675}
2676
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002677// Create an updated offer that adds video after creating an audio only answer
2678// to the original offer. This test verifies that if a video codec and the RTX
2679// codec have the same default payload type as an audio codec that is already in
2680// use, the added codecs payload types are changed.
2681TEST_F(MediaSessionDescriptionFactoryTest,
2682 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2683 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002685 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686 f1_.set_video_codecs(f1_codecs);
2687
2688 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002689 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2690 RtpTransceiverDirection::kRecvOnly, kActive,
2691 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002692
Steve Anton6fe1fba2018-12-11 10:15:23 -08002693 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2694 std::unique_ptr<SessionDescription> answer =
2695 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696
2697 const AudioContentDescription* acd =
2698 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002699 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002700
2701 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2702 // reference be the same as an audio codec that was negotiated in the
2703 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002704 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002705 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002706
2707 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2708 int used_pl_type = acd->codecs()[0].id;
2709 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002710 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711 f2_.set_video_codecs(f2_codecs);
2712
kwiberg31022942016-03-11 14:18:21 -08002713 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714 f2_.CreateOffer(opts, answer.get()));
2715 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002716 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002717 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2718
2719 const AudioContentDescription* updated_acd =
2720 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002721 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002722
2723 const VideoContentDescription* updated_vcd =
2724 GetFirstVideoContentDescription(updated_answer.get());
2725
2726 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002727 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002728 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002729 EXPECT_NE(used_pl_type, new_h264_pl_type);
2730 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002731 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002732 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2733 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2734}
2735
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002736// Create an updated offer with RTX after creating an answer to an offer
2737// without RTX, and with different default payload types.
2738// Verify that the added RTX codec references the correct payload type.
2739TEST_F(MediaSessionDescriptionFactoryTest,
2740 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2741 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002742 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002743
2744 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2745 // This creates rtx for H264 with the payload type |f2_| uses.
2746 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2747 f2_.set_video_codecs(f2_codecs);
2748
Steve Anton6fe1fba2018-12-11 10:15:23 -08002749 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002750 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002751 std::unique_ptr<SessionDescription> answer =
2752 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002753
2754 const VideoContentDescription* vcd =
2755 GetFirstVideoContentDescription(answer.get());
2756
2757 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2758 EXPECT_EQ(expected_codecs, vcd->codecs());
2759
2760 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2761 // updated offer, even though the default payload types are different from
2762 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002763 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002764 f2_.CreateOffer(opts, answer.get()));
2765 ASSERT_TRUE(updated_offer);
2766
2767 const VideoContentDescription* updated_vcd =
2768 GetFirstVideoContentDescription(updated_offer.get());
2769
2770 // New offer should attempt to add H263, and RTX for H264.
2771 expected_codecs.push_back(kVideoCodecs2[1]);
2772 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2773 &expected_codecs);
2774 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2775}
2776
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777// Test that RTX is ignored when there is no associated payload type parameter.
2778TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2779 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002780 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2781 RtpTransceiverDirection::kRecvOnly, kActive,
2782 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002784 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002785 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786 f1_.set_video_codecs(f1_codecs);
2787
2788 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002789 // This creates RTX for H264 with the payload type |f2_| uses.
2790 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002791 f2_.set_video_codecs(f2_codecs);
2792
Steve Anton6fe1fba2018-12-11 10:15:23 -08002793 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002794 ASSERT_TRUE(offer.get() != NULL);
2795 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2796 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2797 // is possible to test that that RTX is dropped when
2798 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002799 MediaContentDescription* media_desc =
2800 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2801 ASSERT_TRUE(media_desc);
2802 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002803 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002804 for (VideoCodec& codec : codecs) {
2805 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2806 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002807 }
2808 }
2809 desc->set_codecs(codecs);
2810
Steve Anton6fe1fba2018-12-11 10:15:23 -08002811 std::unique_ptr<SessionDescription> answer =
2812 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002813
Steve Anton64b626b2019-01-28 17:25:26 -08002814 EXPECT_THAT(
2815 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2816 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002817}
2818
2819// Test that RTX will be filtered out in the answer if its associated payload
2820// type doesn't match the local value.
2821TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2822 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002823 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2824 RtpTransceiverDirection::kRecvOnly, kActive,
2825 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002826 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2827 // This creates RTX for H264 in sender.
2828 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2829 f1_.set_video_codecs(f1_codecs);
2830
2831 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2832 // This creates RTX for H263 in receiver.
2833 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2834 f2_.set_video_codecs(f2_codecs);
2835
Steve Anton6fe1fba2018-12-11 10:15:23 -08002836 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002837 ASSERT_TRUE(offer.get() != NULL);
2838 // Associated payload type doesn't match, therefore, RTX codec is removed in
2839 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002840 std::unique_ptr<SessionDescription> answer =
2841 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002842
Steve Anton64b626b2019-01-28 17:25:26 -08002843 EXPECT_THAT(
2844 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2845 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002846}
2847
2848// Test that when multiple RTX codecs are offered, only the matched RTX codec
2849// is added in the answer, and the unsupported RTX codec is filtered out.
2850TEST_F(MediaSessionDescriptionFactoryTest,
2851 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2852 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002853 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2854 RtpTransceiverDirection::kRecvOnly, kActive,
2855 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002856 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2857 // This creates RTX for H264-SVC in sender.
2858 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2859 f1_.set_video_codecs(f1_codecs);
2860
2861 // This creates RTX for H264 in sender.
2862 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2863 f1_.set_video_codecs(f1_codecs);
2864
2865 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2866 // This creates RTX for H264 in receiver.
2867 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2868 f2_.set_video_codecs(f2_codecs);
2869
2870 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2871 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002872 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002873 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002874 std::unique_ptr<SessionDescription> answer =
2875 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002876 const VideoContentDescription* vcd =
2877 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002878 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2879 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2880 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002881
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002882 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002883}
2884
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002885// Test that after one RTX codec has been negotiated, a new offer can attempt
2886// to add another.
2887TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2888 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002889 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2890 RtpTransceiverDirection::kRecvOnly, kActive,
2891 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002892 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2893 // This creates RTX for H264 for the offerer.
2894 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2895 f1_.set_video_codecs(f1_codecs);
2896
Steve Anton6fe1fba2018-12-11 10:15:23 -08002897 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002898 ASSERT_TRUE(offer);
2899 const VideoContentDescription* vcd =
2900 GetFirstVideoContentDescription(offer.get());
2901
2902 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2903 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2904 &expected_codecs);
2905 EXPECT_EQ(expected_codecs, vcd->codecs());
2906
2907 // Now, attempt to add RTX for H264-SVC.
2908 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2909 f1_.set_video_codecs(f1_codecs);
2910
kwiberg31022942016-03-11 14:18:21 -08002911 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002912 f1_.CreateOffer(opts, offer.get()));
2913 ASSERT_TRUE(updated_offer);
2914 vcd = GetFirstVideoContentDescription(updated_offer.get());
2915
2916 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2917 &expected_codecs);
2918 EXPECT_EQ(expected_codecs, vcd->codecs());
2919}
2920
Noah Richards2e7a0982015-05-18 14:02:54 -07002921// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2922// generated for each simulcast ssrc and correctly grouped.
2923TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2924 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002925 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2926 RtpTransceiverDirection::kSendRecv, kActive,
2927 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002928 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002929 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2930 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002931
2932 // Use a single real codec, and then add RTX for it.
2933 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002934 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002935 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2936 f1_.set_video_codecs(f1_codecs);
2937
2938 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2939 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002941 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002942 MediaContentDescription* media_desc =
2943 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2944 ASSERT_TRUE(media_desc);
2945 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002946 const StreamParamsVec& streams = desc->streams();
2947 // Single stream.
2948 ASSERT_EQ(1u, streams.size());
2949 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2950 EXPECT_EQ(6u, streams[0].ssrcs.size());
2951 // And should have a SIM group for the simulcast.
2952 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2953 // And a FID group for RTX.
2954 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002955 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002956 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2957 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002958 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002959 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2960 EXPECT_EQ(3u, fid_ssrcs.size());
2961}
2962
brandtr03d5fb12016-11-22 03:37:59 -08002963// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2964// together with a FEC-FR grouping.
2965TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2966 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002967 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2968 RtpTransceiverDirection::kSendRecv, kActive,
2969 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002970 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002971 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2972 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002973
2974 // Use a single real codec, and then add FlexFEC for it.
2975 std::vector<VideoCodec> f1_codecs;
2976 f1_codecs.push_back(VideoCodec(97, "H264"));
2977 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2978 f1_.set_video_codecs(f1_codecs);
2979
2980 // Ensure that the offer has a single FlexFEC ssrc and that
2981 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002982 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002983 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002984 MediaContentDescription* media_desc =
2985 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2986 ASSERT_TRUE(media_desc);
2987 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002988 const StreamParamsVec& streams = desc->streams();
2989 // Single stream.
2990 ASSERT_EQ(1u, streams.size());
2991 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2992 EXPECT_EQ(2u, streams[0].ssrcs.size());
2993 // And should have a FEC-FR group for FlexFEC.
2994 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2995 std::vector<uint32_t> primary_ssrcs;
2996 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2997 ASSERT_EQ(1u, primary_ssrcs.size());
2998 uint32_t flexfec_ssrc;
2999 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3000 EXPECT_NE(flexfec_ssrc, 0u);
3001}
3002
3003// Test that FlexFEC is disabled for simulcast.
3004// TODO(brandtr): Remove this test when we support simulcast, either through
3005// multiple FlexfecSenders, or through multistream protection.
3006TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3007 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003008 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3009 RtpTransceiverDirection::kSendRecv, kActive,
3010 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003011 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003012 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3013 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003014
3015 // Use a single real codec, and then add FlexFEC for it.
3016 std::vector<VideoCodec> f1_codecs;
3017 f1_codecs.push_back(VideoCodec(97, "H264"));
3018 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3019 f1_.set_video_codecs(f1_codecs);
3020
3021 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3022 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003023 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003024 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003025 MediaContentDescription* media_desc =
3026 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3027 ASSERT_TRUE(media_desc);
3028 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003029 const StreamParamsVec& streams = desc->streams();
3030 // Single stream.
3031 ASSERT_EQ(1u, streams.size());
3032 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3033 EXPECT_EQ(3u, streams[0].ssrcs.size());
3034 // And should have a SIM group for the simulcast.
3035 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3036 // And not a FEC-FR group for FlexFEC.
3037 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3038 std::vector<uint32_t> primary_ssrcs;
3039 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3040 EXPECT_EQ(3u, primary_ssrcs.size());
3041 for (uint32_t primary_ssrc : primary_ssrcs) {
3042 uint32_t flexfec_ssrc;
3043 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3044 }
3045}
3046
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003047// Create an updated offer after creating an answer to the original offer and
3048// verify that the RTP header extensions that were part of the original answer
3049// are not changed in the updated offer.
3050TEST_F(MediaSessionDescriptionFactoryTest,
3051 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3052 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003053 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003054
3055 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3056 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3057 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3058 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3059
Steve Anton6fe1fba2018-12-11 10:15:23 -08003060 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3061 std::unique_ptr<SessionDescription> answer =
3062 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003063
Yves Gerey665174f2018-06-19 15:03:05 +02003064 EXPECT_EQ(
3065 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3066 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3067 EXPECT_EQ(
3068 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3069 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003070
kwiberg31022942016-03-11 14:18:21 -08003071 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003072 f2_.CreateOffer(opts, answer.get()));
3073
3074 // The expected RTP header extensions in the new offer are the resulting
3075 // extensions from the first offer/answer exchange plus the extensions only
3076 // |f2_| offer.
3077 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003078 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003079 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3080 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3081 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003082 };
3083
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, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003086 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3087 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3088 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003089 };
3090
3091 const AudioContentDescription* updated_acd =
3092 GetFirstAudioContentDescription(updated_offer.get());
3093 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3094 updated_acd->rtp_header_extensions());
3095
3096 const VideoContentDescription* updated_vcd =
3097 GetFirstVideoContentDescription(updated_offer.get());
3098 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3099 updated_vcd->rtp_header_extensions());
3100}
3101
deadbeefa5b273a2015-08-20 17:30:13 -07003102// Verify that if the same RTP extension URI is used for audio and video, the
3103// same ID is used. Also verify that the ID isn't changed when creating an
3104// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003105TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003106 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003107 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003108
3109 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3110 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3111
Steve Anton6fe1fba2018-12-11 10:15:23 -08003112 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003113
3114 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3115 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003116 const RtpExtension kExpectedVideoRtpExtension[] = {
3117 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003118 };
3119
Yves Gerey665174f2018-06-19 15:03:05 +02003120 EXPECT_EQ(
3121 MAKE_VECTOR(kAudioRtpExtension3),
3122 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3123 EXPECT_EQ(
3124 MAKE_VECTOR(kExpectedVideoRtpExtension),
3125 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003126
3127 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003128 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003129 f1_.CreateOffer(opts, offer.get()));
3130
3131 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003132 GetFirstAudioContentDescription(updated_offer.get())
3133 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003134 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003135 GetFirstVideoContentDescription(updated_offer.get())
3136 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003137}
3138
jbauch5869f502017-06-29 12:31:36 -07003139// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3140TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3141 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003142 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003143
3144 f1_.set_enable_encrypted_rtp_header_extensions(true);
3145 f2_.set_enable_encrypted_rtp_header_extensions(true);
3146
3147 f1_.set_audio_rtp_header_extensions(
3148 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3149 f1_.set_video_rtp_header_extensions(
3150 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3151
Steve Anton6fe1fba2018-12-11 10:15:23 -08003152 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003153
3154 // The extensions that are shared between audio and video should use the same
3155 // id.
3156 const RtpExtension kExpectedVideoRtpExtension[] = {
3157 kVideoRtpExtension3ForEncryption[0],
3158 kAudioRtpExtension3ForEncryptionOffer[1],
3159 kAudioRtpExtension3ForEncryptionOffer[2],
3160 };
3161
Yves Gerey665174f2018-06-19 15:03:05 +02003162 EXPECT_EQ(
3163 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3164 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3165 EXPECT_EQ(
3166 MAKE_VECTOR(kExpectedVideoRtpExtension),
3167 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003168
3169 // Nothing should change when creating a new offer
3170 std::unique_ptr<SessionDescription> updated_offer(
3171 f1_.CreateOffer(opts, offer.get()));
3172
3173 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003174 GetFirstAudioContentDescription(updated_offer.get())
3175 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003176 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003177 GetFirstVideoContentDescription(updated_offer.get())
3178 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003179}
3180
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003181TEST(MediaSessionDescription, CopySessionDescription) {
3182 SessionDescription source;
3183 cricket::ContentGroup group(cricket::CN_AUDIO);
3184 source.AddGroup(group);
3185 AudioContentDescription* acd(new AudioContentDescription());
3186 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3187 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003188 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003189 VideoContentDescription* vcd(new VideoContentDescription());
3190 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3191 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003192 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003193
kwiberg31022942016-03-11 14:18:21 -08003194 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003195 ASSERT_TRUE(copy.get() != NULL);
3196 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3197 const ContentInfo* ac = copy->GetContentByName("audio");
3198 const ContentInfo* vc = copy->GetContentByName("video");
3199 ASSERT_TRUE(ac != NULL);
3200 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003201 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003202 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003203 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3204 EXPECT_EQ(1u, acd->first_ssrc());
3205
Steve Anton5adfafd2017-12-20 16:34:00 -08003206 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003207 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003208 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3209 EXPECT_EQ(2u, vcd->first_ssrc());
3210}
3211
3212// The below TestTransportInfoXXX tests create different offers/answers, and
3213// ensure the TransportInfo in the SessionDescription matches what we expect.
3214TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3215 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003216 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3217 RtpTransceiverDirection::kRecvOnly, kActive,
3218 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003219 TestTransportInfo(true, options, false);
3220}
3221
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003222TEST_F(MediaSessionDescriptionFactoryTest,
3223 TestTransportInfoOfferIceRenomination) {
3224 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003225 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3226 RtpTransceiverDirection::kRecvOnly, kActive,
3227 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003228 options.media_description_options[0]
3229 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003230 TestTransportInfo(true, options, false);
3231}
3232
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003233TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3234 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003235 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3236 RtpTransceiverDirection::kRecvOnly, kActive,
3237 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003238 TestTransportInfo(true, options, true);
3239}
3240
3241TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3242 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003243 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3244 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3245 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003246 TestTransportInfo(true, options, false);
3247}
3248
3249TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003250 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003251 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003252 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3253 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3254 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003255 TestTransportInfo(true, options, true);
3256}
3257
3258TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3259 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003260 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3261 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3262 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003263 options.bundle_enabled = true;
3264 TestTransportInfo(true, options, false);
3265}
3266
3267TEST_F(MediaSessionDescriptionFactoryTest,
3268 TestTransportInfoOfferBundleCurrent) {
3269 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003270 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3271 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3272 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003273 options.bundle_enabled = true;
3274 TestTransportInfo(true, options, true);
3275}
3276
3277TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3278 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003279 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3280 RtpTransceiverDirection::kRecvOnly, kActive,
3281 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003282 TestTransportInfo(false, options, false);
3283}
3284
3285TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003286 TestTransportInfoAnswerIceRenomination) {
3287 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003288 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3289 RtpTransceiverDirection::kRecvOnly, kActive,
3290 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003291 options.media_description_options[0]
3292 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003293 TestTransportInfo(false, options, false);
3294}
3295
3296TEST_F(MediaSessionDescriptionFactoryTest,
3297 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003298 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003299 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3300 RtpTransceiverDirection::kRecvOnly, kActive,
3301 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003302 TestTransportInfo(false, options, true);
3303}
3304
3305TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3306 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003307 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3308 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3309 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003310 TestTransportInfo(false, options, false);
3311}
3312
3313TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003314 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003315 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003316 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3317 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3318 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003319 TestTransportInfo(false, options, true);
3320}
3321
3322TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3323 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003324 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3325 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3326 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003327 options.bundle_enabled = true;
3328 TestTransportInfo(false, options, false);
3329}
3330
3331TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003332 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003333 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003334 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3335 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3336 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003337 options.bundle_enabled = true;
3338 TestTransportInfo(false, options, true);
3339}
3340
3341// Create an offer with bundle enabled and verify the crypto parameters are
3342// the common set of the available cryptos.
3343TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3344 TestCryptoWithBundle(true);
3345}
3346
3347// Create an answer with bundle enabled and verify the crypto parameters are
3348// the common set of the available cryptos.
3349TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3350 TestCryptoWithBundle(false);
3351}
3352
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003353// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3354// DTLS is not enabled locally.
3355TEST_F(MediaSessionDescriptionFactoryTest,
3356 TestOfferDtlsSavpfWithoutDtlsFailed) {
3357 f1_.set_secure(SEC_ENABLED);
3358 f2_.set_secure(SEC_ENABLED);
3359 tdf1_.set_secure(SEC_DISABLED);
3360 tdf2_.set_secure(SEC_DISABLED);
3361
Steve Anton6fe1fba2018-12-11 10:15:23 -08003362 std::unique_ptr<SessionDescription> offer =
3363 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003364 ASSERT_TRUE(offer.get() != NULL);
3365 ContentInfo* offer_content = offer->GetContentByName("audio");
3366 ASSERT_TRUE(offer_content != NULL);
3367 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003368 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003369 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3370
Steve Anton6fe1fba2018-12-11 10:15:23 -08003371 std::unique_ptr<SessionDescription> answer =
3372 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003373 ASSERT_TRUE(answer != NULL);
3374 ContentInfo* answer_content = answer->GetContentByName("audio");
3375 ASSERT_TRUE(answer_content != NULL);
3376
3377 ASSERT_TRUE(answer_content->rejected);
3378}
3379
3380// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3381// UDP/TLS/RTP/SAVPF.
3382TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3383 f1_.set_secure(SEC_ENABLED);
3384 f2_.set_secure(SEC_ENABLED);
3385 tdf1_.set_secure(SEC_ENABLED);
3386 tdf2_.set_secure(SEC_ENABLED);
3387
Steve Anton6fe1fba2018-12-11 10:15:23 -08003388 std::unique_ptr<SessionDescription> offer =
3389 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003390 ASSERT_TRUE(offer.get() != NULL);
3391 ContentInfo* offer_content = offer->GetContentByName("audio");
3392 ASSERT_TRUE(offer_content != NULL);
3393 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003394 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003395 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3396
Steve Anton6fe1fba2018-12-11 10:15:23 -08003397 std::unique_ptr<SessionDescription> answer =
3398 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003399 ASSERT_TRUE(answer != NULL);
3400
3401 const ContentInfo* answer_content = answer->GetContentByName("audio");
3402 ASSERT_TRUE(answer_content != NULL);
3403 ASSERT_FALSE(answer_content->rejected);
3404
3405 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003406 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003407 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003408}
3409
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003410// Test that we include both SDES and DTLS in the offer, but only include SDES
3411// in the answer if DTLS isn't negotiated.
3412TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3413 f1_.set_secure(SEC_ENABLED);
3414 f2_.set_secure(SEC_ENABLED);
3415 tdf1_.set_secure(SEC_ENABLED);
3416 tdf2_.set_secure(SEC_DISABLED);
3417 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003418 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003419 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003420 const cricket::MediaContentDescription* audio_media_desc;
3421 const cricket::MediaContentDescription* video_media_desc;
3422 const cricket::TransportDescription* audio_trans_desc;
3423 const cricket::TransportDescription* video_trans_desc;
3424
3425 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003426 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003427 ASSERT_TRUE(offer.get() != NULL);
3428
Steve Antonb1c1de12017-12-21 15:14:30 -08003429 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003430 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003431 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003432 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003433 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003434 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3435
3436 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3437 ASSERT_TRUE(audio_trans_desc != NULL);
3438 video_trans_desc = offer->GetTransportDescriptionByName("video");
3439 ASSERT_TRUE(video_trans_desc != NULL);
3440 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3441 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3442
3443 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003444 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003445 ASSERT_TRUE(answer.get() != NULL);
3446
Steve Antonb1c1de12017-12-21 15:14:30 -08003447 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003448 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003449 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003450 ASSERT_TRUE(video_media_desc != NULL);
3451 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3452 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3453
3454 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3455 ASSERT_TRUE(audio_trans_desc != NULL);
3456 video_trans_desc = answer->GetTransportDescriptionByName("video");
3457 ASSERT_TRUE(video_trans_desc != NULL);
3458 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3459 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3460
3461 // Enable DTLS; the answer should now only have DTLS support.
3462 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003463 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003464 ASSERT_TRUE(answer.get() != NULL);
3465
Steve Antonb1c1de12017-12-21 15:14:30 -08003466 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003467 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003468 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003469 ASSERT_TRUE(video_media_desc != NULL);
3470 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3471 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003472 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3473 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003474
3475 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3476 ASSERT_TRUE(audio_trans_desc != NULL);
3477 video_trans_desc = answer->GetTransportDescriptionByName("video");
3478 ASSERT_TRUE(video_trans_desc != NULL);
3479 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3480 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003481
3482 // Try creating offer again. DTLS enabled now, crypto's should be empty
3483 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003484 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003485 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003486 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003487 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003488 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003489 ASSERT_TRUE(video_media_desc != NULL);
3490 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3491 EXPECT_TRUE(video_media_desc->cryptos().empty());
3492
3493 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3494 ASSERT_TRUE(audio_trans_desc != NULL);
3495 video_trans_desc = offer->GetTransportDescriptionByName("video");
3496 ASSERT_TRUE(video_trans_desc != NULL);
3497 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3498 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003499}
3500
3501// Test that an answer can't be created if cryptos are required but the offer is
3502// unsecure.
3503TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003504 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003505 f1_.set_secure(SEC_DISABLED);
3506 tdf1_.set_secure(SEC_DISABLED);
3507 f2_.set_secure(SEC_REQUIRED);
3508 tdf1_.set_secure(SEC_ENABLED);
3509
Steve Anton6fe1fba2018-12-11 10:15:23 -08003510 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003511 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003512 std::unique_ptr<SessionDescription> answer =
3513 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003514 EXPECT_TRUE(answer.get() == NULL);
3515}
3516
3517// Test that we accept a DTLS offer without SDES and create an appropriate
3518// answer.
3519TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3520 f1_.set_secure(SEC_DISABLED);
3521 f2_.set_secure(SEC_ENABLED);
3522 tdf1_.set_secure(SEC_ENABLED);
3523 tdf2_.set_secure(SEC_ENABLED);
3524 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003525 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3526 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3527 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003528
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003529 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003530 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003531 ASSERT_TRUE(offer.get() != NULL);
3532
3533 const AudioContentDescription* audio_offer =
3534 GetFirstAudioContentDescription(offer.get());
3535 ASSERT_TRUE(audio_offer->cryptos().empty());
3536 const VideoContentDescription* video_offer =
3537 GetFirstVideoContentDescription(offer.get());
3538 ASSERT_TRUE(video_offer->cryptos().empty());
3539 const DataContentDescription* data_offer =
3540 GetFirstDataContentDescription(offer.get());
3541 ASSERT_TRUE(data_offer->cryptos().empty());
3542
3543 const cricket::TransportDescription* audio_offer_trans_desc =
3544 offer->GetTransportDescriptionByName("audio");
3545 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3546 const cricket::TransportDescription* video_offer_trans_desc =
3547 offer->GetTransportDescriptionByName("video");
3548 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3549 const cricket::TransportDescription* data_offer_trans_desc =
3550 offer->GetTransportDescriptionByName("data");
3551 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3552
3553 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003554 std::unique_ptr<SessionDescription> answer =
3555 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003556 ASSERT_TRUE(answer.get() != NULL);
3557
3558 const cricket::TransportDescription* audio_answer_trans_desc =
3559 answer->GetTransportDescriptionByName("audio");
3560 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3561 const cricket::TransportDescription* video_answer_trans_desc =
3562 answer->GetTransportDescriptionByName("video");
3563 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3564 const cricket::TransportDescription* data_answer_trans_desc =
3565 answer->GetTransportDescriptionByName("data");
3566 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3567}
3568
3569// Verifies if vad_enabled option is set to false, CN codecs are not present in
3570// offer or answer.
3571TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3572 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003573 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003574 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003575 ASSERT_TRUE(offer.get() != NULL);
3576 const ContentInfo* audio_content = offer->GetContentByName("audio");
3577 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3578
3579 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003580 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003581 ASSERT_TRUE(offer.get() != NULL);
3582 audio_content = offer->GetContentByName("audio");
3583 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003584 std::unique_ptr<SessionDescription> answer =
3585 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003586 ASSERT_TRUE(answer.get() != NULL);
3587 audio_content = answer->GetContentByName("audio");
3588 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3589}
deadbeef44f08192015-12-15 16:20:09 -08003590
zhihuang1c378ed2017-08-17 14:10:50 -07003591// Test that the generated MIDs match the existing offer.
3592TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003593 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003594 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3595 RtpTransceiverDirection::kRecvOnly, kActive,
3596 &opts);
3597 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3598 RtpTransceiverDirection::kRecvOnly, kActive,
3599 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003600 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003601 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3602 RtpTransceiverDirection::kSendRecv, kActive,
3603 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003604 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003605 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003606 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003607 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003608
deadbeef44f08192015-12-15 16:20:09 -08003609 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3610 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3611 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3612 ASSERT_TRUE(audio_content != nullptr);
3613 ASSERT_TRUE(video_content != nullptr);
3614 ASSERT_TRUE(data_content != nullptr);
3615 EXPECT_EQ("audio_modified", audio_content->name);
3616 EXPECT_EQ("video_modified", video_content->name);
3617 EXPECT_EQ("data_modified", data_content->name);
3618}
zhihuangcf5b37c2016-05-05 11:44:35 -07003619
zhihuang1c378ed2017-08-17 14:10:50 -07003620// The following tests verify that the unified plan SDP is supported.
3621// Test that we can create an offer with multiple media sections of same media
3622// type.
3623TEST_F(MediaSessionDescriptionFactoryTest,
3624 CreateOfferWithMultipleAVMediaSections) {
3625 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003626 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3627 RtpTransceiverDirection::kSendRecv, kActive,
3628 &opts);
3629 AttachSenderToMediaDescriptionOptions(
3630 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003631
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003632 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3633 RtpTransceiverDirection::kSendRecv, kActive,
3634 &opts);
3635 AttachSenderToMediaDescriptionOptions(
3636 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003637
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003638 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3639 RtpTransceiverDirection::kSendRecv, kActive,
3640 &opts);
3641 AttachSenderToMediaDescriptionOptions(
3642 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003643
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003644 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3645 RtpTransceiverDirection::kSendRecv, kActive,
3646 &opts);
3647 AttachSenderToMediaDescriptionOptions(
3648 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003649 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003650 ASSERT_TRUE(offer);
3651
3652 ASSERT_EQ(4u, offer->contents().size());
3653 EXPECT_FALSE(offer->contents()[0].rejected);
3654 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003655 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003656 ASSERT_EQ(1u, acd->streams().size());
3657 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003658 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003659
3660 EXPECT_FALSE(offer->contents()[1].rejected);
3661 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003662 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003663 ASSERT_EQ(1u, vcd->streams().size());
3664 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003665 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003666
3667 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003668 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003669 ASSERT_EQ(1u, acd->streams().size());
3670 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003671 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003672
3673 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003674 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003675 ASSERT_EQ(1u, vcd->streams().size());
3676 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003677 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003678}
3679
3680// Test that we can create an answer with multiple media sections of same media
3681// type.
3682TEST_F(MediaSessionDescriptionFactoryTest,
3683 CreateAnswerWithMultipleAVMediaSections) {
3684 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003685 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3686 RtpTransceiverDirection::kSendRecv, kActive,
3687 &opts);
3688 AttachSenderToMediaDescriptionOptions(
3689 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003690
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003691 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3692 RtpTransceiverDirection::kSendRecv, kActive,
3693 &opts);
3694 AttachSenderToMediaDescriptionOptions(
3695 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003696
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003697 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3698 RtpTransceiverDirection::kSendRecv, kActive,
3699 &opts);
3700 AttachSenderToMediaDescriptionOptions(
3701 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003702
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003703 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3704 RtpTransceiverDirection::kSendRecv, kActive,
3705 &opts);
3706 AttachSenderToMediaDescriptionOptions(
3707 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003708
Steve Anton6fe1fba2018-12-11 10:15:23 -08003709 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003710 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003711 std::unique_ptr<SessionDescription> answer =
3712 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003713
3714 ASSERT_EQ(4u, answer->contents().size());
3715 EXPECT_FALSE(answer->contents()[0].rejected);
3716 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003717 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003718 ASSERT_EQ(1u, acd->streams().size());
3719 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003720 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003721
3722 EXPECT_FALSE(answer->contents()[1].rejected);
3723 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003724 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003725 ASSERT_EQ(1u, vcd->streams().size());
3726 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003727 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003728
3729 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003730 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003731 ASSERT_EQ(1u, acd->streams().size());
3732 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003733 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003734
3735 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003736 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003737 ASSERT_EQ(1u, vcd->streams().size());
3738 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003739 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003740}
3741
3742// Test that the media section will be rejected in offer if the corresponding
3743// MediaDescriptionOptions is stopped by the offerer.
3744TEST_F(MediaSessionDescriptionFactoryTest,
3745 CreateOfferWithMediaSectionStoppedByOfferer) {
3746 // Create an offer with two audio sections and one of them is stopped.
3747 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003748 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3749 RtpTransceiverDirection::kSendRecv, kActive,
3750 &offer_opts);
3751 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3752 RtpTransceiverDirection::kInactive, kStopped,
3753 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003754 std::unique_ptr<SessionDescription> offer =
3755 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003756 ASSERT_TRUE(offer);
3757 ASSERT_EQ(2u, offer->contents().size());
3758 EXPECT_FALSE(offer->contents()[0].rejected);
3759 EXPECT_TRUE(offer->contents()[1].rejected);
3760}
3761
3762// Test that the media section will be rejected in answer if the corresponding
3763// MediaDescriptionOptions is stopped by the offerer.
3764TEST_F(MediaSessionDescriptionFactoryTest,
3765 CreateAnswerWithMediaSectionStoppedByOfferer) {
3766 // Create an offer with two audio sections and one of them is stopped.
3767 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003768 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3769 RtpTransceiverDirection::kSendRecv, kActive,
3770 &offer_opts);
3771 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3772 RtpTransceiverDirection::kInactive, kStopped,
3773 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003774 std::unique_ptr<SessionDescription> offer =
3775 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003776 ASSERT_TRUE(offer);
3777 ASSERT_EQ(2u, offer->contents().size());
3778 EXPECT_FALSE(offer->contents()[0].rejected);
3779 EXPECT_TRUE(offer->contents()[1].rejected);
3780
3781 // Create an answer based on the offer.
3782 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003783 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3784 RtpTransceiverDirection::kSendRecv, kActive,
3785 &answer_opts);
3786 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3787 RtpTransceiverDirection::kSendRecv, kActive,
3788 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003789 std::unique_ptr<SessionDescription> answer =
3790 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003791 ASSERT_EQ(2u, answer->contents().size());
3792 EXPECT_FALSE(answer->contents()[0].rejected);
3793 EXPECT_TRUE(answer->contents()[1].rejected);
3794}
3795
3796// Test that the media section will be rejected in answer if the corresponding
3797// MediaDescriptionOptions is stopped by the answerer.
3798TEST_F(MediaSessionDescriptionFactoryTest,
3799 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3800 // Create an offer with two audio sections.
3801 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003802 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3803 RtpTransceiverDirection::kSendRecv, kActive,
3804 &offer_opts);
3805 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3806 RtpTransceiverDirection::kSendRecv, kActive,
3807 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003808 std::unique_ptr<SessionDescription> offer =
3809 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003810 ASSERT_TRUE(offer);
3811 ASSERT_EQ(2u, offer->contents().size());
3812 ASSERT_FALSE(offer->contents()[0].rejected);
3813 ASSERT_FALSE(offer->contents()[1].rejected);
3814
3815 // The answerer rejects one of the audio sections.
3816 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003817 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3818 RtpTransceiverDirection::kSendRecv, kActive,
3819 &answer_opts);
3820 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3821 RtpTransceiverDirection::kInactive, kStopped,
3822 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003823 std::unique_ptr<SessionDescription> answer =
3824 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003825 ASSERT_EQ(2u, answer->contents().size());
3826 EXPECT_FALSE(answer->contents()[0].rejected);
3827 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003828
3829 // The TransportInfo of the rejected m= section is expected to be added in the
3830 // answer.
3831 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003832}
3833
3834// Test the generated media sections has the same order of the
3835// corresponding MediaDescriptionOptions.
3836TEST_F(MediaSessionDescriptionFactoryTest,
3837 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3838 MediaSessionOptions opts;
3839 // This tests put video section first because normally audio comes first by
3840 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003841 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3842 RtpTransceiverDirection::kSendRecv, kActive,
3843 &opts);
3844 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3845 RtpTransceiverDirection::kSendRecv, kActive,
3846 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003847 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003848
3849 ASSERT_TRUE(offer);
3850 ASSERT_EQ(2u, offer->contents().size());
3851 EXPECT_EQ("video", offer->contents()[0].name);
3852 EXPECT_EQ("audio", offer->contents()[1].name);
3853}
3854
3855// Test that different media sections using the same codec have same payload
3856// type.
3857TEST_F(MediaSessionDescriptionFactoryTest,
3858 PayloadTypesSharedByMediaSectionsOfSameType) {
3859 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003860 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3861 RtpTransceiverDirection::kSendRecv, kActive,
3862 &opts);
3863 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3864 RtpTransceiverDirection::kSendRecv, kActive,
3865 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003866 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003867 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003868 ASSERT_TRUE(offer);
3869 ASSERT_EQ(2u, offer->contents().size());
3870 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003871 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003872 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003873 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003874 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3875 ASSERT_EQ(2u, vcd1->codecs().size());
3876 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3877 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3878 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3879 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3880
3881 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003882 std::unique_ptr<SessionDescription> answer =
3883 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003884 ASSERT_TRUE(answer);
3885 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003886 vcd1 = answer->contents()[0].media_description()->as_video();
3887 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003888 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3889 ASSERT_EQ(1u, vcd1->codecs().size());
3890 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3891 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3892}
3893
3894// Test that the codec preference order per media section is respected in
3895// subsequent offer.
3896TEST_F(MediaSessionDescriptionFactoryTest,
3897 CreateOfferRespectsCodecPreferenceOrder) {
3898 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003899 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3900 RtpTransceiverDirection::kSendRecv, kActive,
3901 &opts);
3902 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3903 RtpTransceiverDirection::kSendRecv, kActive,
3904 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003905 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003906 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003907 ASSERT_TRUE(offer);
3908 ASSERT_EQ(2u, offer->contents().size());
3909 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003910 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003911 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003912 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003913 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3914 EXPECT_EQ(video_codecs, vcd1->codecs());
3915 EXPECT_EQ(video_codecs, vcd2->codecs());
3916
3917 // Change the codec preference of the first video section and create a
3918 // follow-up offer.
3919 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3920 vcd1->set_codecs(video_codecs_reverse);
3921 std::unique_ptr<SessionDescription> updated_offer(
3922 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003923 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3924 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003925 // The video codec preference order should be respected.
3926 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3927 EXPECT_EQ(video_codecs, vcd2->codecs());
3928}
3929
3930// Test that the codec preference order per media section is respected in
3931// the answer.
3932TEST_F(MediaSessionDescriptionFactoryTest,
3933 CreateAnswerRespectsCodecPreferenceOrder) {
3934 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003935 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3936 RtpTransceiverDirection::kSendRecv, kActive,
3937 &opts);
3938 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3939 RtpTransceiverDirection::kSendRecv, kActive,
3940 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003941 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003942 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003943 ASSERT_TRUE(offer);
3944 ASSERT_EQ(2u, offer->contents().size());
3945 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003946 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003947 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003948 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003949 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3950 EXPECT_EQ(video_codecs, vcd1->codecs());
3951 EXPECT_EQ(video_codecs, vcd2->codecs());
3952
3953 // Change the codec preference of the first video section and create an
3954 // answer.
3955 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3956 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003957 std::unique_ptr<SessionDescription> answer =
3958 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003959 vcd1 = answer->contents()[0].media_description()->as_video();
3960 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003961 // The video codec preference order should be respected.
3962 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3963 EXPECT_EQ(video_codecs, vcd2->codecs());
3964}
3965
Zhi Huang6f367472017-11-22 13:20:02 -08003966// Test that when creating an answer, the codecs use local parameters instead of
3967// the remote ones.
3968TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3969 const std::string audio_param_name = "audio_param";
3970 const std::string audio_value1 = "audio_v1";
3971 const std::string audio_value2 = "audio_v2";
3972 const std::string video_param_name = "video_param";
3973 const std::string video_value1 = "video_v1";
3974 const std::string video_value2 = "video_v2";
3975
3976 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3977 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3978 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3979 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3980
3981 // Set the parameters for codecs.
3982 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3983 video_codecs1[0].SetParam(video_param_name, video_value1);
3984 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3985 video_codecs2[0].SetParam(video_param_name, video_value2);
3986
3987 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3988 f1_.set_video_codecs(video_codecs1);
3989 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3990 f2_.set_video_codecs(video_codecs2);
3991
3992 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003993 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3994 RtpTransceiverDirection::kSendRecv, kActive,
3995 &opts);
3996 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3997 RtpTransceiverDirection::kSendRecv, kActive,
3998 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003999
Steve Anton6fe1fba2018-12-11 10:15:23 -08004000 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004001 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004002 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4003 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004004 std::string value;
4005 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4006 EXPECT_EQ(audio_value1, value);
4007 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4008 EXPECT_EQ(video_value1, value);
4009
Steve Anton6fe1fba2018-12-11 10:15:23 -08004010 std::unique_ptr<SessionDescription> answer =
4011 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004012 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004013 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4014 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004015 // Use the parameters from the local codecs.
4016 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4017 EXPECT_EQ(audio_value2, value);
4018 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4019 EXPECT_EQ(video_value2, value);
4020}
4021
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004022// Test that matching packetization-mode is part of the criteria for matching
4023// H264 codecs (in addition to profile-level-id). Previously, this was not the
4024// case, so the first H264 codec with the same profile-level-id would match and
4025// the payload type in the answer would be incorrect.
4026// This is a regression test for bugs.webrtc.org/8808
4027TEST_F(MediaSessionDescriptionFactoryTest,
4028 H264MatchCriteriaIncludesPacketizationMode) {
4029 // Create two H264 codecs with the same profile level ID and different
4030 // packetization modes.
4031 VideoCodec h264_pm0(96, "H264");
4032 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4033 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4034 VideoCodec h264_pm1(97, "H264");
4035 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4036 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4037
4038 // Offerer will send both codecs, answerer should choose the one with matching
4039 // packetization mode (and not the first one it sees).
4040 f1_.set_video_codecs({h264_pm0, h264_pm1});
4041 f2_.set_video_codecs({h264_pm1});
4042
4043 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004044 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4045 RtpTransceiverDirection::kSendRecv, kActive,
4046 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004047
Steve Anton6fe1fba2018-12-11 10:15:23 -08004048 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004049 ASSERT_TRUE(offer);
4050
Steve Anton6fe1fba2018-12-11 10:15:23 -08004051 std::unique_ptr<SessionDescription> answer =
4052 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004053 ASSERT_TRUE(answer);
4054
4055 // Answer should have one negotiated codec with packetization-mode=1 using the
4056 // offered payload type.
4057 ASSERT_EQ(1u, answer->contents().size());
4058 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4059 ASSERT_EQ(1u, answer_vcd->codecs().size());
4060 auto answer_codec = answer_vcd->codecs()[0];
4061 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4062}
4063
zhihuangcf5b37c2016-05-05 11:44:35 -07004064class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4065 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004066 MediaProtocolTest()
4067 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004068 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4069 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004070 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
4071 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004072 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4073 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004074 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
4075 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
4076 f1_.set_secure(SEC_ENABLED);
4077 f2_.set_secure(SEC_ENABLED);
4078 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004079 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004080 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004081 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004082 tdf1_.set_secure(SEC_ENABLED);
4083 tdf2_.set_secure(SEC_ENABLED);
4084 }
4085
4086 protected:
4087 MediaSessionDescriptionFactory f1_;
4088 MediaSessionDescriptionFactory f2_;
4089 TransportDescriptionFactory tdf1_;
4090 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004091 UniqueRandomIdGenerator ssrc_generator1;
4092 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004093};
4094
4095TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4096 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004097 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004098 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004099 ASSERT_TRUE(offer.get() != nullptr);
4100 // Set the protocol for all the contents.
4101 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004102 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004103 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004104 std::unique_ptr<SessionDescription> answer =
4105 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004106 const ContentInfo* ac = answer->GetContentByName("audio");
4107 const ContentInfo* vc = answer->GetContentByName("video");
4108 ASSERT_TRUE(ac != nullptr);
4109 ASSERT_TRUE(vc != nullptr);
4110 EXPECT_FALSE(ac->rejected); // the offer is accepted
4111 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004112 const AudioContentDescription* acd = ac->media_description()->as_audio();
4113 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004114 EXPECT_EQ(GetParam(), acd->protocol());
4115 EXPECT_EQ(GetParam(), vcd->protocol());
4116}
4117
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004118INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4119 MediaProtocolTest,
4120 ::testing::ValuesIn(kMediaProtocols));
4121INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4122 MediaProtocolTest,
4123 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004124
4125TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4126 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004127 UniqueRandomIdGenerator ssrc_generator;
4128 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004129 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4130 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4131
4132 // The merged list of codecs should contain any send codecs that are also
4133 // nominally in the recieve codecs list. Payload types should be picked from
4134 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4135 // (set to 1). This equals what happens when the send codecs are used in an
4136 // offer and the receive codecs are used in the following answer.
4137 const std::vector<AudioCodec> sendrecv_codecs =
4138 MAKE_VECTOR(kAudioCodecsAnswer);
4139 const std::vector<AudioCodec> no_codecs;
4140
4141 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4142 << "Please don't change shared test data!";
4143 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4144 << "Please don't change shared test data!";
4145 // Alter iLBC send codec to have zero channels, to test that that is handled
4146 // properly.
4147 send_codecs[1].channels = 0;
4148
4149 // Alther iLBC receive codec to be lowercase, to test that case conversions
4150 // are handled properly.
4151 recv_codecs[2].name = "ilbc";
4152
4153 // Test proper merge
4154 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004155 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4156 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4157 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004158
4159 // Test empty send codecs list
4160 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004161 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4162 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4163 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004164
4165 // Test empty recv codecs list
4166 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004167 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4168 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4169 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004170
4171 // Test all empty codec lists
4172 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004173 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4174 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4175 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004176}
4177
Amit Hilbuch77938e62018-12-21 09:23:38 -08004178// Checks that the RID extensions are added to the video RTP header extensions.
4179// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4180// not very well defined, as calling set() and immediately get() will yield
4181// an object that is not semantically equivalent to the set object.
4182TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4183 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004184 UniqueRandomIdGenerator ssrc_generator;
4185 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004186 sf.set_is_unified_plan(true);
4187 cricket::RtpHeaderExtensions extensions;
4188 sf.set_video_rtp_header_extensions(extensions);
4189 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4190 // Check to see that RID extensions were added to the extension list
4191 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004192 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004193 RtpExtension::kMidUri)));
4194 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004195 RtpExtension::kRidUri)));
4196 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4197 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004198}
4199
4200// Checks that the RID extensions are added to the audio RTP header extensions.
4201// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4202// not very well defined, as calling set() and immediately get() will yield
4203// an object that is not semantically equivalent to the set object.
4204TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4205 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004206 UniqueRandomIdGenerator ssrc_generator;
4207 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004208 sf.set_is_unified_plan(true);
4209 cricket::RtpHeaderExtensions extensions;
4210 sf.set_audio_rtp_header_extensions(extensions);
4211 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4212 // Check to see that RID extensions were added to the extension list
4213 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004214 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004215 RtpExtension::kMidUri)));
4216 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004217 RtpExtension::kRidUri)));
4218 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4219 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004220}
4221
ossu075af922016-06-14 03:29:38 -07004222namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004223// Compare the two vectors of codecs ignoring the payload type.
4224template <class Codec>
4225bool CodecsMatch(const std::vector<Codec>& codecs1,
4226 const std::vector<Codec>& codecs2) {
4227 if (codecs1.size() != codecs2.size()) {
4228 return false;
4229 }
4230
4231 for (size_t i = 0; i < codecs1.size(); ++i) {
4232 if (!codecs1[i].Matches(codecs2[i])) {
4233 return false;
4234 }
4235 }
4236 return true;
4237}
4238
Steve Anton4e70a722017-11-28 14:57:10 -08004239void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004240 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004241 UniqueRandomIdGenerator ssrc_generator;
4242 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004243 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4244 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4245 const std::vector<AudioCodec> sendrecv_codecs =
4246 MAKE_VECTOR(kAudioCodecsAnswer);
4247 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004248
4249 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004250 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4251 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004252
Steve Anton4e70a722017-11-28 14:57:10 -08004253 if (direction == RtpTransceiverDirection::kSendRecv ||
4254 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004255 AttachSenderToMediaDescriptionOptions(
4256 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004257 }
ossu075af922016-06-14 03:29:38 -07004258
Steve Anton6fe1fba2018-12-11 10:15:23 -08004259 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004260 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004261 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004262
4263 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004264 // that the codecs put in are right. This happens when we neither want to
4265 // send nor receive audio. The checks are still in place if at some point
4266 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004267 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004268 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004269 // sendrecv and inactive should both present lists as if the channel was
4270 // to be used for sending and receiving. Inactive essentially means it
4271 // might eventually be used anything, but we don't know more at this
4272 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004273 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004274 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004275 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004276 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004277 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004278 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004279 }
4280 }
4281}
4282
4283static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004284 AudioCodec(0, "codec0", 16000, -1, 1),
4285 AudioCodec(1, "codec1", 8000, 13300, 1),
4286 AudioCodec(2, "codec2", 8000, 64000, 1),
4287 AudioCodec(3, "codec3", 8000, 64000, 1),
4288 AudioCodec(4, "codec4", 8000, 0, 2),
4289 AudioCodec(5, "codec5", 32000, 0, 1),
4290 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004291
zhihuang1c378ed2017-08-17 14:10:50 -07004292/* The codecs groups below are chosen as per the matrix below. The objective
4293 * is to have different sets of codecs in the inputs, to get unique sets of
4294 * codecs after negotiation, depending on offer and answer communication
4295 * directions. One-way directions in the offer should either result in the
4296 * opposite direction in the answer, or an inactive answer. Regardless, the
4297 * choice of codecs should be as if the answer contained the opposite
4298 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004299 *
4300 * | Offer | Answer | Result
4301 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4302 * 0 | x - - | - x - | x - - - -
4303 * 1 | x x x | - x - | x - - x -
4304 * 2 | - x - | x - - | - x - - -
4305 * 3 | x x x | x - - | - x x - -
4306 * 4 | - x - | x x x | - x - - -
4307 * 5 | x - - | x x x | x - - - -
4308 * 6 | x x x | x x x | x x x x x
4309 */
4310// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004311static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4312static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004313// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4314// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004315static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4316static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004317// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004318static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4319static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4320static const int kResultSendrecv_SendCodecs[] = {3, 6};
4321static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4322static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004323
4324template <typename T, int IDXS>
4325std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4326 std::vector<T> out;
4327 out.reserve(IDXS);
4328 for (int idx : indices)
4329 out.push_back(array[idx]);
4330
4331 return out;
4332}
4333
Steve Anton4e70a722017-11-28 14:57:10 -08004334void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4335 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004336 bool add_legacy_stream) {
4337 TransportDescriptionFactory offer_tdf;
4338 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004339 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4340 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4341 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004342 offer_factory.set_audio_codecs(
4343 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4344 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4345 answer_factory.set_audio_codecs(
4346 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4347 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4348
ossu075af922016-06-14 03:29:38 -07004349 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004350 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4351 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004352
Steve Anton4e70a722017-11-28 14:57:10 -08004353 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004354 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4355 kAudioTrack1, {kMediaStream1}, 1,
4356 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004357 }
4358
Steve Anton6fe1fba2018-12-11 10:15:23 -08004359 std::unique_ptr<SessionDescription> offer =
4360 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004361 ASSERT_TRUE(offer.get() != NULL);
4362
4363 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004364 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4365 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004366
Steve Anton4e70a722017-11-28 14:57:10 -08004367 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004368 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4369 kAudioTrack1, {kMediaStream1}, 1,
4370 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004371 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004372 std::unique_ptr<SessionDescription> answer =
4373 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004374 const ContentInfo* ac = answer->GetContentByName("audio");
4375
zhihuang1c378ed2017-08-17 14:10:50 -07004376 // If the factory didn't add any audio content to the answer, we cannot
4377 // check that the codecs put in are right. This happens when we neither want
4378 // to send nor receive audio. The checks are still in place if at some point
4379 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004380 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004381 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4382 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004383
ossu075af922016-06-14 03:29:38 -07004384 std::vector<AudioCodec> target_codecs;
4385 // For offers with sendrecv or inactive, we should never reply with more
4386 // codecs than offered, with these codec sets.
4387 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004388 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004389 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4390 kResultSendrecv_SendrecvCodecs);
4391 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004392 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004393 target_codecs =
4394 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004395 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004396 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004397 target_codecs =
4398 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004399 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004400 case RtpTransceiverDirection::kSendRecv:
4401 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004402 target_codecs =
4403 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004404 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004405 target_codecs =
4406 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004407 } else {
4408 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4409 kResultSendrecv_SendrecvCodecs);
4410 }
4411 break;
4412 }
4413
zhihuang1c378ed2017-08-17 14:10:50 -07004414 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004415 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004416 bool first = true;
4417 os << "{";
4418 for (const auto& c : codecs) {
4419 os << (first ? " " : ", ") << c.id;
4420 first = false;
4421 }
4422 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004423 return os.Release();
ossu075af922016-06-14 03:29:38 -07004424 };
4425
4426 EXPECT_TRUE(acd->codecs() == target_codecs)
4427 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004428 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4429 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004430 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004431 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4432 << "; got: "
4433 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004434 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004435 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004436 << "Only inactive offers are allowed to not generate any audio "
4437 "content";
ossu075af922016-06-14 03:29:38 -07004438 }
4439}
brandtr03d5fb12016-11-22 03:37:59 -08004440
4441} // namespace
ossu075af922016-06-14 03:29:38 -07004442
4443class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004444 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004445
4446TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004447 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004448}
4449
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004450INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4451 AudioCodecsOfferTest,
4452 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4453 RtpTransceiverDirection::kRecvOnly,
4454 RtpTransceiverDirection::kSendRecv,
4455 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004456
4457class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004458 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4459 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004460 bool>> {};
ossu075af922016-06-14 03:29:38 -07004461
4462TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004463 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4464 ::testing::get<1>(GetParam()),
4465 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004466}
4467
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004468INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004469 MediaSessionDescriptionFactoryTest,
4470 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004471 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4472 RtpTransceiverDirection::kRecvOnly,
4473 RtpTransceiverDirection::kSendRecv,
4474 RtpTransceiverDirection::kInactive),
4475 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4476 RtpTransceiverDirection::kRecvOnly,
4477 RtpTransceiverDirection::kSendRecv,
4478 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004479 ::testing::Bool()));