blob: b0409eab11406b996bb7809024b3f7b0572f825e [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
Peter Boström0c4e06b2015-10-07 12:23:21 +0200216static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
217static const uint32_t kSimSsrc[] = {10, 20, 30};
218static const uint32_t kFec1Ssrc[] = {10, 11};
219static const uint32_t kFec2Ssrc[] = {20, 21};
220static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221
222static const char kMediaStream1[] = "stream_1";
223static const char kMediaStream2[] = "stream_2";
224static const char kVideoTrack1[] = "video_1";
225static const char kVideoTrack2[] = "video_2";
226static const char kAudioTrack1[] = "audio_1";
227static const char kAudioTrack2[] = "audio_2";
228static const char kAudioTrack3[] = "audio_3";
229static const char kDataTrack1[] = "data_1";
230static const char kDataTrack2[] = "data_2";
231static const char kDataTrack3[] = "data_3";
232
zhihuangcf5b37c2016-05-05 11:44:35 -0700233static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
234 "RTP/SAVPF"};
235static const char* kMediaProtocolsDtls[] = {
236 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
237 "UDP/TLS/RTP/SAVP"};
238
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700239// SRTP cipher name negotiated by the tests. This must be updated if the
240// default changes.
241static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
242static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
243
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800244// These constants are used to make the code using "AddMediaDescriptionOptions"
245// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700246static constexpr bool kStopped = true;
247static constexpr bool kActive = false;
248
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000249static bool IsMediaContentOfType(const ContentInfo* content,
250 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800251 RTC_DCHECK(content);
252 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000253}
254
Steve Anton4e70a722017-11-28 14:57:10 -0800255static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800256 RTC_DCHECK(content);
257 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000258}
259
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000260static void AddRtxCodec(const VideoCodec& rtx_codec,
261 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800262 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000263 codecs->push_back(rtx_codec);
264}
265
266template <class T>
267static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
268 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100269 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000270 for (const auto& codec : codecs) {
271 codec_names.push_back(codec.name);
272 }
273 return codec_names;
274}
275
zhihuang1c378ed2017-08-17 14:10:50 -0700276// This is used for test only. MIDs are not the identification of the
277// MediaDescriptionOptions since some end points may not support MID and the SDP
278// may not contain 'mid'.
279std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
280 const std::string& mid,
281 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800282 return absl::c_find_if(
283 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700284 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
285}
286
287std::vector<MediaDescriptionOptions>::const_iterator
288FindFirstMediaDescriptionByMid(const std::string& mid,
289 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800290 return absl::c_find_if(
291 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700292 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700293}
294
295// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800296static void AddMediaDescriptionOptions(MediaType type,
297 const std::string& mid,
298 RtpTransceiverDirection direction,
299 bool stopped,
300 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800301 opts->media_description_options.push_back(
302 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700303}
304
Steve Anton4e70a722017-11-28 14:57:10 -0800305static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700306 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800307 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
308 opts);
309 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
310 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700311}
312
313static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800314 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700315 MediaSessionOptions* opts) {
316 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800317 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700318}
319
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800320static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700321 const std::string& mid,
322 MediaType type,
323 const std::string& track_id,
324 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800325 const std::vector<RidDescription>& rids,
326 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700327 int num_sim_layer,
328 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700329 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
330 switch (type) {
331 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700332 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700333 break;
334 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800335 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
336 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700337 break;
338 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700339 RTC_CHECK(stream_ids.size() == 1U);
340 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700341 break;
342 default:
343 RTC_NOTREACHED();
344 }
345}
346
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800347static void AttachSenderToMediaDescriptionOptions(
348 const std::string& mid,
349 MediaType type,
350 const std::string& track_id,
351 const std::vector<std::string>& stream_ids,
352 int num_sim_layer,
353 MediaSessionOptions* session_options) {
354 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
355 SimulcastLayerList(), num_sim_layer,
356 session_options);
357}
358
zhihuang1c378ed2017-08-17 14:10:50 -0700359static void DetachSenderFromMediaSection(const std::string& mid,
360 const std::string& track_id,
361 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700362 std::vector<cricket::SenderOptions>& sender_options_list =
363 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
364 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800365 absl::c_find_if(sender_options_list,
366 [track_id](const cricket::SenderOptions& sender_options) {
367 return sender_options.track_id == track_id;
368 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700369 RTC_DCHECK(sender_it != sender_options_list.end());
370 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700371}
372
373// Helper function used to create a default MediaSessionOptions for Plan B SDP.
374// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
375static MediaSessionOptions CreatePlanBMediaSessionOptions() {
376 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800377 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
378 RtpTransceiverDirection::kRecvOnly, kActive,
379 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700380 return session_options;
381}
382
383// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
384// was designed for Plan B SDP, where only one audio "m=" section and one video
385// "m=" section could be generated, and ordering couldn't be controlled. Many of
386// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387class MediaSessionDescriptionFactoryTest : public testing::Test {
388 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800389 MediaSessionDescriptionFactoryTest()
390 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700391 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
392 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000393 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
394 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700395 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
396 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000397 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
398 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200399 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700400 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200401 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700402 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403 }
404
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000405 // Create a video StreamParamsVec object with:
406 // - one video stream with 3 simulcast streams and FEC,
407 StreamParamsVec CreateComplexVideoStreamParamsVec() {
408 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
409 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
410 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
411 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
412
413 std::vector<SsrcGroup> ssrc_groups;
414 ssrc_groups.push_back(sim_group);
415 ssrc_groups.push_back(fec_group1);
416 ssrc_groups.push_back(fec_group2);
417 ssrc_groups.push_back(fec_group3);
418
419 StreamParams simulcast_params;
420 simulcast_params.id = kVideoTrack1;
421 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
422 simulcast_params.ssrc_groups = ssrc_groups;
423 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800424 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000425
426 StreamParamsVec video_streams;
427 video_streams.push_back(simulcast_params);
428
429 return video_streams;
430 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431
432 bool CompareCryptoParams(const CryptoParamsVec& c1,
433 const CryptoParamsVec& c2) {
434 if (c1.size() != c2.size())
435 return false;
436 for (size_t i = 0; i < c1.size(); ++i)
437 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
438 c1[i].key_params != c2[i].key_params ||
439 c1[i].session_params != c2[i].session_params)
440 return false;
441 return true;
442 }
443
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700444 // Returns true if the transport info contains "renomination" as an
445 // ICE option.
446 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800447 return absl::c_linear_search(transport_info->description.transport_options,
448 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700449 }
450
zhihuang1c378ed2017-08-17 14:10:50 -0700451 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700452 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453 bool has_current_desc) {
454 const std::string current_audio_ufrag = "current_audio_ufrag";
455 const std::string current_audio_pwd = "current_audio_pwd";
456 const std::string current_video_ufrag = "current_video_ufrag";
457 const std::string current_video_pwd = "current_video_pwd";
458 const std::string current_data_ufrag = "current_data_ufrag";
459 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800460 std::unique_ptr<SessionDescription> current_desc;
461 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800463 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800464 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200465 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800466 TransportDescription(current_audio_ufrag, current_audio_pwd)));
467 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200468 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800469 TransportDescription(current_video_ufrag, current_video_pwd)));
470 current_desc->AddTransportInfo(TransportInfo(
471 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000472 }
473 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800474 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475 } else {
kwiberg31022942016-03-11 14:18:21 -0800476 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800477 offer = f1_.CreateOffer(options, NULL);
478 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479 }
480 ASSERT_TRUE(desc.get() != NULL);
481 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000482 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483 EXPECT_TRUE(ti_audio != NULL);
484 if (has_current_desc) {
485 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
486 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
487 } else {
488 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
489 ti_audio->description.ice_ufrag.size());
490 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
491 ti_audio->description.ice_pwd.size());
492 }
zhihuang1c378ed2017-08-17 14:10:50 -0700493 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700494 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700495 EXPECT_EQ(
496 media_desc_options_it->transport_options.enable_ice_renomination,
497 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498
499 } else {
500 EXPECT_TRUE(ti_audio == NULL);
501 }
502 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000503 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 EXPECT_TRUE(ti_video != NULL);
505 if (options.bundle_enabled) {
506 EXPECT_EQ(ti_audio->description.ice_ufrag,
507 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200508 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 } else {
510 if (has_current_desc) {
511 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
512 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
513 } else {
514 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
515 ti_video->description.ice_ufrag.size());
516 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
517 ti_video->description.ice_pwd.size());
518 }
519 }
zhihuang1c378ed2017-08-17 14:10:50 -0700520 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700521 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700522 EXPECT_EQ(
523 media_desc_options_it->transport_options.enable_ice_renomination,
524 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525 } else {
526 EXPECT_TRUE(ti_video == NULL);
527 }
528 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
529 if (options.has_data()) {
530 EXPECT_TRUE(ti_data != NULL);
531 if (options.bundle_enabled) {
532 EXPECT_EQ(ti_audio->description.ice_ufrag,
533 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200534 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 } else {
536 if (has_current_desc) {
537 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
538 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
539 } else {
540 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
541 ti_data->description.ice_ufrag.size());
542 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
543 ti_data->description.ice_pwd.size());
544 }
545 }
zhihuang1c378ed2017-08-17 14:10:50 -0700546 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700547 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700548 EXPECT_EQ(
549 media_desc_options_it->transport_options.enable_ice_renomination,
550 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700551
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 } else {
553 EXPECT_TRUE(ti_video == NULL);
554 }
555 }
556
557 void TestCryptoWithBundle(bool offer) {
558 f1_.set_secure(SEC_ENABLED);
559 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800560 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
561 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
562 &options);
kwiberg31022942016-03-11 14:18:21 -0800563 std::unique_ptr<SessionDescription> ref_desc;
564 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 if (offer) {
566 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800567 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800569 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570 } else {
571 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800572 ref_desc = f1_.CreateOffer(options, NULL);
573 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800575 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800577 desc->GetContentDescriptionByName("audio");
578 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800580 desc->GetContentDescriptionByName("video");
581 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
583 video_media_desc->cryptos()));
584 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800585 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 audio_media_desc->cryptos()[0].cipher_suite);
587
588 // Verify the selected crypto is one from the reference audio
589 // media content.
590 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800591 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 bool found = false;
593 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
594 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200595 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 found = true;
597 break;
598 }
599 }
600 EXPECT_TRUE(found);
601 }
602
603 // This test that the audio and video media direction is set to
604 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700605 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800607 RtpTransceiverDirection direction_in_offer,
608 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700609 MediaSessionOptions offer_opts;
610 AddAudioVideoSections(direction_in_offer, &offer_opts);
611
Steve Anton6fe1fba2018-12-11 10:15:23 -0800612 std::unique_ptr<SessionDescription> offer =
613 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700615 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700617 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000618 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619
zhihuang1c378ed2017-08-17 14:10:50 -0700620 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800621 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800622 std::unique_ptr<SessionDescription> answer =
623 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 const AudioContentDescription* acd_answer =
625 GetFirstAudioContentDescription(answer.get());
626 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
627 const VideoContentDescription* vcd_answer =
628 GetFirstVideoContentDescription(answer.get());
629 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
630 }
631
632 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800633 RTC_DCHECK(content);
634 RTC_CHECK(content->media_description());
635 const cricket::AudioContentDescription* audio_desc =
636 content->media_description()->as_audio();
637 RTC_CHECK(audio_desc);
638 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
639 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800641 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 }
643 return true;
644 }
645
jbauchcb560652016-08-04 05:20:32 -0700646 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
647 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800648 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700649 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700650
jbauchcb560652016-08-04 05:20:32 -0700651 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800652 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700653 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700654
jbauchcb560652016-08-04 05:20:32 -0700655 f1_.set_secure(SEC_ENABLED);
656 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800657 std::unique_ptr<SessionDescription> offer =
658 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700659 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800660 std::unique_ptr<SessionDescription> answer =
661 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700662 const ContentInfo* ac = answer->GetContentByName("audio");
663 const ContentInfo* vc = answer->GetContentByName("video");
664 ASSERT_TRUE(ac != NULL);
665 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800666 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
667 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800668 const AudioContentDescription* acd = ac->media_description()->as_audio();
669 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700670 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800671 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700672 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700673 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700674 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
675 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700676 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700677 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700678 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700679 }
680 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800681 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200682 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
683 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700684 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700685 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700686 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700687 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700688 }
Steve Antone38a5a12018-11-21 16:05:15 -0800689 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700690 }
691
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800693 UniqueRandomIdGenerator ssrc_generator1;
694 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000695 MediaSessionDescriptionFactory f1_;
696 MediaSessionDescriptionFactory f2_;
697 TransportDescriptionFactory tdf1_;
698 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000699};
700
701// Create a typical audio offer, and ensure it matches what we expect.
702TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
703 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800704 std::unique_ptr<SessionDescription> offer =
705 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706 ASSERT_TRUE(offer.get() != NULL);
707 const ContentInfo* ac = offer->GetContentByName("audio");
708 const ContentInfo* vc = offer->GetContentByName("video");
709 ASSERT_TRUE(ac != NULL);
710 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800711 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800712 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000713 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700714 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700715 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000716 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
717 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700718 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800719 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720}
721
722// Create a typical video offer, and ensure it matches what we expect.
723TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
724 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800725 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800727 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728 ASSERT_TRUE(offer.get() != NULL);
729 const ContentInfo* ac = offer->GetContentByName("audio");
730 const ContentInfo* vc = offer->GetContentByName("video");
731 ASSERT_TRUE(ac != NULL);
732 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800733 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
734 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800735 const AudioContentDescription* acd = ac->media_description()->as_audio();
736 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700738 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700739 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000740 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
741 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700742 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800743 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000744 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
745 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700746 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
748 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700749 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800750 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751}
752
753// Test creating an offer with bundle where the Codecs have the same dynamic
754// RTP playlod type. The test verifies that the offer don't contain the
755// duplicate RTP payload types.
756TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
757 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700758 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
760 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
761 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
762
763 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800764 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
765 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800767 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 const VideoContentDescription* vcd =
769 GetFirstVideoContentDescription(offer.get());
770 const AudioContentDescription* acd =
771 GetFirstAudioContentDescription(offer.get());
772 const DataContentDescription* dcd =
773 GetFirstDataContentDescription(offer.get());
774 ASSERT_TRUE(NULL != vcd);
775 ASSERT_TRUE(NULL != acd);
776 ASSERT_TRUE(NULL != dcd);
777 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
778 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
779 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
780 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
781 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
782 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
783}
784
zhihuang1c378ed2017-08-17 14:10:50 -0700785// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786// after an audio only session has been negotiated.
787TEST_F(MediaSessionDescriptionFactoryTest,
788 TestCreateUpdatedVideoOfferWithBundle) {
789 f1_.set_secure(SEC_ENABLED);
790 f2_.set_secure(SEC_ENABLED);
791 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800792 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
793 RtpTransceiverDirection::kRecvOnly, kActive,
794 &opts);
795 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
796 RtpTransceiverDirection::kInactive, kStopped,
797 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 opts.data_channel_type = cricket::DCT_NONE;
799 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800800 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
801 std::unique_ptr<SessionDescription> answer =
802 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000803
804 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800805 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
806 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
807 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800809 std::unique_ptr<SessionDescription> updated_offer(
810 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811
812 const AudioContentDescription* acd =
813 GetFirstAudioContentDescription(updated_offer.get());
814 const VideoContentDescription* vcd =
815 GetFirstVideoContentDescription(updated_offer.get());
816 const DataContentDescription* dcd =
817 GetFirstDataContentDescription(updated_offer.get());
818 EXPECT_TRUE(NULL != vcd);
819 EXPECT_TRUE(NULL != acd);
820 EXPECT_TRUE(NULL != dcd);
821
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700822 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800823 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700824 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800825 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700826 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800827 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828}
deadbeef44f08192015-12-15 16:20:09 -0800829
wu@webrtc.org78187522013-10-07 23:32:02 +0000830// Create a RTP data offer, and ensure it matches what we expect.
831TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800833 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
834 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800836 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000837 ASSERT_TRUE(offer.get() != NULL);
838 const ContentInfo* ac = offer->GetContentByName("audio");
839 const ContentInfo* dc = offer->GetContentByName("data");
840 ASSERT_TRUE(ac != NULL);
841 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800842 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
843 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800844 const AudioContentDescription* acd = ac->media_description()->as_audio();
845 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700847 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700848 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
850 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700851 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800852 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
854 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700855 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200857 dcd->bandwidth()); // default bandwidth (auto)
858 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700859 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800860 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861}
862
wu@webrtc.org78187522013-10-07 23:32:02 +0000863// Create an SCTP data offer with bundle without error.
864TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
865 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000866 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800867 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000868 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800869 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000870 EXPECT_TRUE(offer.get() != NULL);
871 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
872}
873
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000874// Test creating an sctp data channel from an already generated offer.
875TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
876 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000877 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800878 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000879 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800880 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000881 ASSERT_TRUE(offer1.get() != NULL);
882 const ContentInfo* data = offer1->GetContentByName("data");
883 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800884 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000885
886 // Now set data_channel_type to 'none' (default) and make sure that the
887 // datachannel type that gets generated from the previous offer, is of the
888 // same type.
889 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800890 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000891 f1_.CreateOffer(opts, offer1.get()));
892 data = offer2->GetContentByName("data");
893 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800894 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000895}
896
Steve Anton2bed3972019-01-04 17:04:30 -0800897// Test that if BUNDLE is enabled and all media sections are rejected then the
898// BUNDLE group is not present in the re-offer.
899TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
900 MediaSessionOptions opts;
901 opts.bundle_enabled = true;
902 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
903 RtpTransceiverDirection::kSendRecv, kActive,
904 &opts);
905 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
906
907 opts.media_description_options[0].stopped = true;
908 std::unique_ptr<SessionDescription> reoffer =
909 f1_.CreateOffer(opts, offer.get());
910
911 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
912}
913
914// Test that if BUNDLE is enabled and the remote re-offer does not include a
915// BUNDLE group since all media sections are rejected, then the re-answer also
916// does not include a BUNDLE group.
917TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
918 MediaSessionOptions opts;
919 opts.bundle_enabled = true;
920 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
921 RtpTransceiverDirection::kSendRecv, kActive,
922 &opts);
923 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
924 std::unique_ptr<SessionDescription> answer =
925 f2_.CreateAnswer(offer.get(), opts, nullptr);
926
927 opts.media_description_options[0].stopped = true;
928 std::unique_ptr<SessionDescription> reoffer =
929 f1_.CreateOffer(opts, offer.get());
930 std::unique_ptr<SessionDescription> reanswer =
931 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
932
933 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
934}
935
936// Test that if BUNDLE is enabled and the previous offerer-tagged media section
937// was rejected then the new offerer-tagged media section is the non-rejected
938// media section.
939TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
940 MediaSessionOptions opts;
941 opts.bundle_enabled = true;
942 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
943 RtpTransceiverDirection::kSendRecv, kActive,
944 &opts);
945 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
946
947 // Reject the audio m= section and add a video m= section.
948 opts.media_description_options[0].stopped = true;
949 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
950 RtpTransceiverDirection::kSendRecv, kActive,
951 &opts);
952 std::unique_ptr<SessionDescription> reoffer =
953 f1_.CreateOffer(opts, offer.get());
954
955 const cricket::ContentGroup* bundle_group =
956 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
957 ASSERT_TRUE(bundle_group);
958 EXPECT_FALSE(bundle_group->HasContentName("audio"));
959 EXPECT_TRUE(bundle_group->HasContentName("video"));
960}
961
962// Test that if BUNDLE is enabled and the previous offerer-tagged media section
963// was rejected and a new media section is added, then the re-answer BUNDLE
964// group will contain only the non-rejected media section.
965TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
966 MediaSessionOptions opts;
967 opts.bundle_enabled = true;
968 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
969 RtpTransceiverDirection::kSendRecv, kActive,
970 &opts);
971 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
972 std::unique_ptr<SessionDescription> answer =
973 f2_.CreateAnswer(offer.get(), opts, nullptr);
974
975 // Reject the audio m= section and add a video m= section.
976 opts.media_description_options[0].stopped = true;
977 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
978 RtpTransceiverDirection::kSendRecv, kActive,
979 &opts);
980 std::unique_ptr<SessionDescription> reoffer =
981 f1_.CreateOffer(opts, offer.get());
982 std::unique_ptr<SessionDescription> reanswer =
983 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
984
985 const cricket::ContentGroup* bundle_group =
986 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
987 ASSERT_TRUE(bundle_group);
988 EXPECT_FALSE(bundle_group->HasContentName("audio"));
989 EXPECT_TRUE(bundle_group->HasContentName("video"));
990}
991
992// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
993// and there is still a non-rejected media section that was in the initial
994// offer, then the ICE credentials do not change in the reoffer offerer-tagged
995// media section.
996TEST_F(MediaSessionDescriptionFactoryTest,
997 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
998 MediaSessionOptions opts;
999 opts.bundle_enabled = true;
1000 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1001 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1002 std::unique_ptr<SessionDescription> answer =
1003 f2_.CreateAnswer(offer.get(), opts, nullptr);
1004
1005 // Reject the audio m= section.
1006 opts.media_description_options[0].stopped = true;
1007 std::unique_ptr<SessionDescription> reoffer =
1008 f1_.CreateOffer(opts, offer.get());
1009
1010 const TransportDescription* offer_tagged =
1011 offer->GetTransportDescriptionByName("audio");
1012 ASSERT_TRUE(offer_tagged);
1013 const TransportDescription* reoffer_tagged =
1014 reoffer->GetTransportDescriptionByName("video");
1015 ASSERT_TRUE(reoffer_tagged);
1016 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1017 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1018}
1019
1020// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1021// and there is still a non-rejected media section that was in the initial
1022// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1023// media section.
1024TEST_F(MediaSessionDescriptionFactoryTest,
1025 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1026 MediaSessionOptions opts;
1027 opts.bundle_enabled = true;
1028 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1029 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1030 std::unique_ptr<SessionDescription> answer =
1031 f2_.CreateAnswer(offer.get(), opts, nullptr);
1032
1033 // Reject the audio m= section.
1034 opts.media_description_options[0].stopped = true;
1035 std::unique_ptr<SessionDescription> reoffer =
1036 f1_.CreateOffer(opts, offer.get());
1037 std::unique_ptr<SessionDescription> reanswer =
1038 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1039
1040 const TransportDescription* answer_tagged =
1041 answer->GetTransportDescriptionByName("audio");
1042 ASSERT_TRUE(answer_tagged);
1043 const TransportDescription* reanswer_tagged =
1044 reanswer->GetTransportDescriptionByName("video");
1045 ASSERT_TRUE(reanswer_tagged);
1046 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1047 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1048}
1049
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001050// Create an audio, video offer without legacy StreamParams.
1051TEST_F(MediaSessionDescriptionFactoryTest,
1052 TestCreateOfferWithoutLegacyStreams) {
1053 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001054 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001055 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001056 ASSERT_TRUE(offer.get() != NULL);
1057 const ContentInfo* ac = offer->GetContentByName("audio");
1058 const ContentInfo* vc = offer->GetContentByName("video");
1059 ASSERT_TRUE(ac != NULL);
1060 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001061 const AudioContentDescription* acd = ac->media_description()->as_audio();
1062 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001063
Yves Gerey665174f2018-06-19 15:03:05 +02001064 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1065 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001066}
1067
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001068// Creates an audio+video sendonly offer.
1069TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001070 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001071 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001072 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1073 {kMediaStream1}, 1, &opts);
1074 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1075 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001076
Steve Anton6fe1fba2018-12-11 10:15:23 -08001077 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001078 ASSERT_TRUE(offer.get() != NULL);
1079 EXPECT_EQ(2u, offer->contents().size());
1080 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1081 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1082
Steve Anton4e70a722017-11-28 14:57:10 -08001083 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1084 GetMediaDirection(&offer->contents()[0]));
1085 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1086 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001087}
1088
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001089// Verifies that the order of the media contents in the current
1090// SessionDescription is preserved in the new SessionDescription.
1091TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1092 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001093 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001094
kwiberg31022942016-03-11 14:18:21 -08001095 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001096 ASSERT_TRUE(offer1.get() != NULL);
1097 EXPECT_EQ(1u, offer1->contents().size());
1098 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1099
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001100 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1101 RtpTransceiverDirection::kRecvOnly, kActive,
1102 &opts);
kwiberg31022942016-03-11 14:18:21 -08001103 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001104 f1_.CreateOffer(opts, offer1.get()));
1105 ASSERT_TRUE(offer2.get() != NULL);
1106 EXPECT_EQ(2u, offer2->contents().size());
1107 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1108 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1109
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001110 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1111 RtpTransceiverDirection::kRecvOnly, kActive,
1112 &opts);
kwiberg31022942016-03-11 14:18:21 -08001113 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001114 f1_.CreateOffer(opts, offer2.get()));
1115 ASSERT_TRUE(offer3.get() != NULL);
1116 EXPECT_EQ(3u, offer3->contents().size());
1117 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1118 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1119 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001120}
1121
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001122// Create a typical audio answer, and ensure it matches what we expect.
1123TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1124 f1_.set_secure(SEC_ENABLED);
1125 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001126 std::unique_ptr<SessionDescription> offer =
1127 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001128 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001129 std::unique_ptr<SessionDescription> answer =
1130 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 const ContentInfo* ac = answer->GetContentByName("audio");
1132 const ContentInfo* vc = answer->GetContentByName("video");
1133 ASSERT_TRUE(ac != NULL);
1134 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001135 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001136 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001138 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001139 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1141 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001142 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001143 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001144}
1145
jbauchcb560652016-08-04 05:20:32 -07001146// Create a typical audio answer with GCM ciphers enabled, and ensure it
1147// matches what we expect.
1148TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1149 f1_.set_secure(SEC_ENABLED);
1150 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001151 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001152 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001153 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001154 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001155 std::unique_ptr<SessionDescription> answer =
1156 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001157 const ContentInfo* ac = answer->GetContentByName("audio");
1158 const ContentInfo* vc = answer->GetContentByName("video");
1159 ASSERT_TRUE(ac != NULL);
1160 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001161 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001162 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001163 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001164 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001165 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001166 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1167 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001168 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001169 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001170}
1171
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001172// Create a typical video answer, and ensure it matches what we expect.
1173TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1174 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001175 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001176 f1_.set_secure(SEC_ENABLED);
1177 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001178 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001179 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001180 std::unique_ptr<SessionDescription> answer =
1181 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001182 const ContentInfo* ac = answer->GetContentByName("audio");
1183 const ContentInfo* vc = answer->GetContentByName("video");
1184 ASSERT_TRUE(ac != NULL);
1185 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001186 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1187 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001188 const AudioContentDescription* acd = ac->media_description()->as_audio();
1189 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001191 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001192 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001193 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001195 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001196 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001197 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001198 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1199 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001200 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001201 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202}
1203
jbauchcb560652016-08-04 05:20:32 -07001204// Create a typical video answer with GCM ciphers enabled, and ensure it
1205// matches what we expect.
1206TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1207 TestVideoGcmCipher(true, true);
1208}
1209
1210// Create a typical video answer with GCM ciphers enabled for the offer only,
1211// and ensure it matches what we expect.
1212TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1213 TestVideoGcmCipher(true, false);
1214}
1215
1216// Create a typical video answer with GCM ciphers enabled for the answer only,
1217// and ensure it matches what we expect.
1218TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1219 TestVideoGcmCipher(false, true);
1220}
1221
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001223 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001224 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225 f1_.set_secure(SEC_ENABLED);
1226 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001227 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001229 std::unique_ptr<SessionDescription> answer =
1230 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001232 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001233 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001234 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001235 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1236 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001237 const AudioContentDescription* acd = ac->media_description()->as_audio();
1238 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001240 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001241 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001242 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001244 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001245 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001246 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001247 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001248 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001249 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001250 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251}
1252
jbauchcb560652016-08-04 05:20:32 -07001253TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001254 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001255 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001256 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001257 f1_.set_secure(SEC_ENABLED);
1258 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001259 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001260 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001261 std::unique_ptr<SessionDescription> answer =
1262 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001263 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001264 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001265 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001266 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001267 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1268 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001269 const AudioContentDescription* acd = ac->media_description()->as_audio();
1270 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001271 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001272 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001273 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001274 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001275 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001276 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001277 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001278 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001279 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001280 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001281 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001282 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001283}
1284
1285// The use_sctpmap flag should be set in a DataContentDescription by default.
1286// The answer's use_sctpmap flag should match the offer's.
1287TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1288 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001289 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001290 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001291 ASSERT_TRUE(offer.get() != NULL);
1292 ContentInfo* dc_offer = offer->GetContentByName("data");
1293 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001294 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001295 EXPECT_TRUE(dcd_offer->use_sctpmap());
1296
Steve Anton6fe1fba2018-12-11 10:15:23 -08001297 std::unique_ptr<SessionDescription> answer =
1298 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001299 const ContentInfo* dc_answer = answer->GetContentByName("data");
1300 ASSERT_TRUE(dc_answer != NULL);
1301 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001302 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001303 EXPECT_TRUE(dcd_answer->use_sctpmap());
1304}
1305
1306// The answer's use_sctpmap flag should match the offer's.
1307TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1308 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001309 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001310 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001311 ASSERT_TRUE(offer.get() != NULL);
1312 ContentInfo* dc_offer = offer->GetContentByName("data");
1313 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001314 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001315 dcd_offer->set_use_sctpmap(false);
1316
Steve Anton6fe1fba2018-12-11 10:15:23 -08001317 std::unique_ptr<SessionDescription> answer =
1318 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001319 const ContentInfo* dc_answer = answer->GetContentByName("data");
1320 ASSERT_TRUE(dc_answer != NULL);
1321 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001322 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001323 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001324}
1325
deadbeef8b7e9ad2017-05-25 09:38:55 -07001326// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1327// and "TCP/DTLS/SCTP" offers.
1328TEST_F(MediaSessionDescriptionFactoryTest,
1329 TestCreateDataAnswerToDifferentOfferedProtos) {
1330 // Need to enable DTLS offer/answer generation (disabled by default in this
1331 // test).
1332 f1_.set_secure(SEC_ENABLED);
1333 f2_.set_secure(SEC_ENABLED);
1334 tdf1_.set_secure(SEC_ENABLED);
1335 tdf2_.set_secure(SEC_ENABLED);
1336
1337 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001338 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001339 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001340 ASSERT_TRUE(offer.get() != nullptr);
1341 ContentInfo* dc_offer = offer->GetContentByName("data");
1342 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001343 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001344
1345 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1346 "TCP/DTLS/SCTP"};
1347 for (const std::string& proto : protos) {
1348 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001349 std::unique_ptr<SessionDescription> answer =
1350 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001351 const ContentInfo* dc_answer = answer->GetContentByName("data");
1352 ASSERT_TRUE(dc_answer != nullptr);
1353 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001354 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001355 EXPECT_FALSE(dc_answer->rejected);
1356 EXPECT_EQ(proto, dcd_answer->protocol());
1357 }
1358}
1359
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001360// Verifies that the order of the media contents in the offer is preserved in
1361// the answer.
1362TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1363 MediaSessionOptions opts;
1364
1365 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001366 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001367 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001368 ASSERT_TRUE(offer1.get() != NULL);
1369
1370 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001371 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1372 RtpTransceiverDirection::kRecvOnly, kActive,
1373 &opts);
kwiberg31022942016-03-11 14:18:21 -08001374 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001375 f1_.CreateOffer(opts, offer1.get()));
1376 ASSERT_TRUE(offer2.get() != NULL);
1377
1378 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001379 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1380 RtpTransceiverDirection::kRecvOnly, kActive,
1381 &opts);
kwiberg31022942016-03-11 14:18:21 -08001382 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001383 f1_.CreateOffer(opts, offer2.get()));
1384 ASSERT_TRUE(offer3.get() != NULL);
1385
Steve Anton6fe1fba2018-12-11 10:15:23 -08001386 std::unique_ptr<SessionDescription> answer =
1387 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001388 ASSERT_TRUE(answer.get() != NULL);
1389 EXPECT_EQ(3u, answer->contents().size());
1390 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1391 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1392 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1393}
1394
ossu075af922016-06-14 03:29:38 -07001395// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1396// answerer settings.
1397
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001398// This test that the media direction is set to send/receive in an answer if
1399// the offer is send receive.
1400TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001401 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1402 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001403}
1404
1405// This test that the media direction is set to receive only in an answer if
1406// the offer is send only.
1407TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001408 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1409 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001410}
1411
1412// This test that the media direction is set to send only in an answer if
1413// the offer is recv only.
1414TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001415 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1416 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001417}
1418
1419// This test that the media direction is set to inactive in an answer if
1420// the offer is inactive.
1421TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001422 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1423 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001424}
1425
1426// Test that a data content with an unknown protocol is rejected in an answer.
1427TEST_F(MediaSessionDescriptionFactoryTest,
1428 CreateDataAnswerToOfferWithUnknownProtocol) {
1429 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001430 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001431 f1_.set_secure(SEC_ENABLED);
1432 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001433 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001434 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001435 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001436 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001437 ASSERT_TRUE(dcd_offer != NULL);
1438 std::string protocol = "a weird unknown protocol";
1439 dcd_offer->set_protocol(protocol);
1440
Steve Anton6fe1fba2018-12-11 10:15:23 -08001441 std::unique_ptr<SessionDescription> answer =
1442 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001443
1444 const ContentInfo* dc_answer = answer->GetContentByName("data");
1445 ASSERT_TRUE(dc_answer != NULL);
1446 EXPECT_TRUE(dc_answer->rejected);
1447 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001448 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001449 ASSERT_TRUE(dcd_answer != NULL);
1450 EXPECT_EQ(protocol, dcd_answer->protocol());
1451}
1452
1453// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1454TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001455 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001456 f1_.set_secure(SEC_DISABLED);
1457 f2_.set_secure(SEC_DISABLED);
1458 tdf1_.set_secure(SEC_DISABLED);
1459 tdf2_.set_secure(SEC_DISABLED);
1460
Steve Anton6fe1fba2018-12-11 10:15:23 -08001461 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001462 const AudioContentDescription* offer_acd =
1463 GetFirstAudioContentDescription(offer.get());
1464 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001465 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001466
Steve Anton6fe1fba2018-12-11 10:15:23 -08001467 std::unique_ptr<SessionDescription> answer =
1468 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001469
1470 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1471 ASSERT_TRUE(ac_answer != NULL);
1472 EXPECT_FALSE(ac_answer->rejected);
1473
1474 const AudioContentDescription* answer_acd =
1475 GetFirstAudioContentDescription(answer.get());
1476 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001477 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001478}
1479
1480// Create a video offer and answer and ensure the RTP header extensions
1481// matches what we expect.
1482TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1483 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001484 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001485 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1486 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1487 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1488 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1489
Steve Anton6fe1fba2018-12-11 10:15:23 -08001490 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001491 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001492 std::unique_ptr<SessionDescription> answer =
1493 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494
Yves Gerey665174f2018-06-19 15:03:05 +02001495 EXPECT_EQ(
1496 MAKE_VECTOR(kAudioRtpExtension1),
1497 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1498 EXPECT_EQ(
1499 MAKE_VECTOR(kVideoRtpExtension1),
1500 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1501 EXPECT_EQ(
1502 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1503 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1504 EXPECT_EQ(
1505 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1506 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507}
1508
jbauch5869f502017-06-29 12:31:36 -07001509TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001510 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001511 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001512 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001513
1514 f1_.set_enable_encrypted_rtp_header_extensions(true);
1515 f2_.set_enable_encrypted_rtp_header_extensions(true);
1516
Yves Gerey665174f2018-06-19 15:03:05 +02001517 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1518 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1519 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1520 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001521
Steve Anton6fe1fba2018-12-11 10:15:23 -08001522 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001523 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001524 std::unique_ptr<SessionDescription> answer =
1525 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001526
Yves Gerey665174f2018-06-19 15:03:05 +02001527 EXPECT_EQ(
1528 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1529 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1530 EXPECT_EQ(
1531 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1532 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1533 EXPECT_EQ(
1534 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1535 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1536 EXPECT_EQ(
1537 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1538 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001539}
1540
1541TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001542 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001543 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001544 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001545
1546 f1_.set_enable_encrypted_rtp_header_extensions(true);
1547
Yves Gerey665174f2018-06-19 15:03:05 +02001548 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1549 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1550 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1551 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001552
Steve Anton6fe1fba2018-12-11 10:15:23 -08001553 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001554 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001555 std::unique_ptr<SessionDescription> answer =
1556 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001557
Yves Gerey665174f2018-06-19 15:03:05 +02001558 EXPECT_EQ(
1559 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1560 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1561 EXPECT_EQ(
1562 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1563 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1564 EXPECT_EQ(
1565 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1566 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1567 EXPECT_EQ(
1568 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1569 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001570}
1571
1572TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001573 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001574 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001575 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001576
1577 f2_.set_enable_encrypted_rtp_header_extensions(true);
1578
Yves Gerey665174f2018-06-19 15:03:05 +02001579 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1580 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1581 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1582 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001583
Steve Anton6fe1fba2018-12-11 10:15:23 -08001584 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001585 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001586 std::unique_ptr<SessionDescription> answer =
1587 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001588
Yves Gerey665174f2018-06-19 15:03:05 +02001589 EXPECT_EQ(
1590 MAKE_VECTOR(kAudioRtpExtension1),
1591 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1592 EXPECT_EQ(
1593 MAKE_VECTOR(kVideoRtpExtension1),
1594 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1595 EXPECT_EQ(
1596 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1597 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1598 EXPECT_EQ(
1599 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1600 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001601}
1602
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001603// Create an audio, video, data answer without legacy StreamParams.
1604TEST_F(MediaSessionDescriptionFactoryTest,
1605 TestCreateAnswerWithoutLegacyStreams) {
1606 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001607 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1608 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001609 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001610 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001611 std::unique_ptr<SessionDescription> answer =
1612 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001613 const ContentInfo* ac = answer->GetContentByName("audio");
1614 const ContentInfo* vc = answer->GetContentByName("video");
1615 const ContentInfo* dc = answer->GetContentByName("data");
1616 ASSERT_TRUE(ac != NULL);
1617 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001618 const AudioContentDescription* acd = ac->media_description()->as_audio();
1619 const VideoContentDescription* vcd = vc->media_description()->as_video();
1620 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001621
1622 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1623 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1624 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1625}
1626
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001627// Create a typical video answer, and ensure it matches what we expect.
1628TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1629 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001630 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1631 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1632 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001633
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001635 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1636 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1637 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001638
kwiberg31022942016-03-11 14:18:21 -08001639 std::unique_ptr<SessionDescription> offer;
1640 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001641
1642 offer_opts.rtcp_mux_enabled = true;
1643 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001644 offer = f1_.CreateOffer(offer_opts, NULL);
1645 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001646 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1647 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1648 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1649 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1650 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1651 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1652 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1653 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1654 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1655 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1656 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1657 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1658
1659 offer_opts.rtcp_mux_enabled = true;
1660 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001661 offer = f1_.CreateOffer(offer_opts, NULL);
1662 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001663 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1664 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1665 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1666 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1667 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1668 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1669 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1670 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1671 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1672 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1673 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1674 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1675
1676 offer_opts.rtcp_mux_enabled = false;
1677 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001678 offer = f1_.CreateOffer(offer_opts, NULL);
1679 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001680 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1681 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1682 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1683 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1684 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1685 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1686 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1687 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1688 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1689 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1690 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1691 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1692
1693 offer_opts.rtcp_mux_enabled = false;
1694 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001695 offer = f1_.CreateOffer(offer_opts, NULL);
1696 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001697 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1698 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1699 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1700 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1701 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1702 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1703 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1704 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1705 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1706 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1707 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1708 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1709}
1710
1711// Create an audio-only answer to a video offer.
1712TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1713 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001714 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1715 RtpTransceiverDirection::kRecvOnly, kActive,
1716 &opts);
1717 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1718 RtpTransceiverDirection::kRecvOnly, kActive,
1719 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001720 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001721 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001722
1723 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001724 std::unique_ptr<SessionDescription> answer =
1725 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001726 const ContentInfo* ac = answer->GetContentByName("audio");
1727 const ContentInfo* vc = answer->GetContentByName("video");
1728 ASSERT_TRUE(ac != NULL);
1729 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001730 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001731 EXPECT_TRUE(vc->rejected);
1732}
1733
1734// Create an audio-only answer to an offer with data.
1735TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001736 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001737 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001738 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1739 RtpTransceiverDirection::kRecvOnly, kActive,
1740 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001741 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001742 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001743
1744 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001745 std::unique_ptr<SessionDescription> answer =
1746 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747 const ContentInfo* ac = answer->GetContentByName("audio");
1748 const ContentInfo* dc = answer->GetContentByName("data");
1749 ASSERT_TRUE(ac != NULL);
1750 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001751 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001752 EXPECT_TRUE(dc->rejected);
1753}
1754
1755// Create an answer that rejects the contents which are rejected in the offer.
1756TEST_F(MediaSessionDescriptionFactoryTest,
1757 CreateAnswerToOfferWithRejectedMedia) {
1758 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001759 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1760 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001761 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001762 ASSERT_TRUE(offer.get() != NULL);
1763 ContentInfo* ac = offer->GetContentByName("audio");
1764 ContentInfo* vc = offer->GetContentByName("video");
1765 ContentInfo* dc = offer->GetContentByName("data");
1766 ASSERT_TRUE(ac != NULL);
1767 ASSERT_TRUE(vc != NULL);
1768 ASSERT_TRUE(dc != NULL);
1769 ac->rejected = true;
1770 vc->rejected = true;
1771 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001772 std::unique_ptr<SessionDescription> answer =
1773 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 ac = answer->GetContentByName("audio");
1775 vc = answer->GetContentByName("video");
1776 dc = answer->GetContentByName("data");
1777 ASSERT_TRUE(ac != NULL);
1778 ASSERT_TRUE(vc != NULL);
1779 ASSERT_TRUE(dc != NULL);
1780 EXPECT_TRUE(ac->rejected);
1781 EXPECT_TRUE(vc->rejected);
1782 EXPECT_TRUE(dc->rejected);
1783}
1784
Johannes Kron0854eb62018-10-10 22:33:20 +02001785TEST_F(MediaSessionDescriptionFactoryTest,
1786 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1787 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001788 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001789 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001790 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001791 ASSERT_TRUE(offer.get() != NULL);
1792 std::unique_ptr<SessionDescription> answer_no_support(
1793 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001794 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001795
1796 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001797 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001798 ASSERT_TRUE(offer.get() != NULL);
1799 std::unique_ptr<SessionDescription> answer_support(
1800 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001801 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001802}
1803
1804TEST_F(MediaSessionDescriptionFactoryTest,
1805 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1806 MediaSessionOptions opts;
1807 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001808 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001809 MediaContentDescription* video_offer =
1810 offer->GetContentDescriptionByName("video");
1811 ASSERT_TRUE(video_offer);
1812 MediaContentDescription* audio_offer =
1813 offer->GetContentDescriptionByName("audio");
1814 ASSERT_TRUE(audio_offer);
1815
1816 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001817 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1818 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001819
1820 ASSERT_TRUE(offer.get() != NULL);
1821 std::unique_ptr<SessionDescription> answer_no_support(
1822 f2_.CreateAnswer(offer.get(), opts, NULL));
1823 MediaContentDescription* video_answer =
1824 answer_no_support->GetContentDescriptionByName("video");
1825 MediaContentDescription* audio_answer =
1826 answer_no_support->GetContentDescriptionByName("audio");
1827 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001828 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001829 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001830 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001831
1832 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001833 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1834 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001835 ASSERT_TRUE(offer.get() != NULL);
1836 std::unique_ptr<SessionDescription> answer_support(
1837 f2_.CreateAnswer(offer.get(), opts, NULL));
1838 video_answer = answer_support->GetContentDescriptionByName("video");
1839 audio_answer = answer_support->GetContentDescriptionByName("audio");
1840 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001841 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001842 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001843 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001844}
1845
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001846// Create an audio and video offer with:
1847// - one video track
1848// - two audio tracks
1849// - two data tracks
1850// and ensure it matches what we expect. Also updates the initial offer by
1851// adding a new video track and replaces one of the audio tracks.
1852TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1853 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001854 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001855 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1856 {kMediaStream1}, 1, &opts);
1857 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1858 {kMediaStream1}, 1, &opts);
1859 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1860 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001861
Steve Anton4e70a722017-11-28 14:57:10 -08001862 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001863 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1864 {kMediaStream1}, 1, &opts);
1865 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1866 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001867
1868 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001869 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001870
1871 ASSERT_TRUE(offer.get() != NULL);
1872 const ContentInfo* ac = offer->GetContentByName("audio");
1873 const ContentInfo* vc = offer->GetContentByName("video");
1874 const ContentInfo* dc = offer->GetContentByName("data");
1875 ASSERT_TRUE(ac != NULL);
1876 ASSERT_TRUE(vc != NULL);
1877 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001878 const AudioContentDescription* acd = ac->media_description()->as_audio();
1879 const VideoContentDescription* vcd = vc->media_description()->as_video();
1880 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001881 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001882 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001883
1884 const StreamParamsVec& audio_streams = acd->streams();
1885 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001886 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001887 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1888 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1889 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1890 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1891 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1892 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1893
1894 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1895 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001896 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001897
1898 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1899 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001900 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001901
1902 const StreamParamsVec& video_streams = vcd->streams();
1903 ASSERT_EQ(1U, video_streams.size());
1904 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1905 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1906 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1907 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1908
1909 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1910 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001911 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001912
1913 const StreamParamsVec& data_streams = dcd->streams();
1914 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001915 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001916 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1917 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1918 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1919 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1920 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1921 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1922
1923 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001924 dcd->bandwidth()); // default bandwidth (auto)
1925 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001926 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001927
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001928 // Update the offer. Add a new video track that is not synched to the
1929 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001930 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
1931 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001932 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001933 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
1934 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001935 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001936 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
1937 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001938 std::unique_ptr<SessionDescription> updated_offer(
1939 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001940
1941 ASSERT_TRUE(updated_offer.get() != NULL);
1942 ac = updated_offer->GetContentByName("audio");
1943 vc = updated_offer->GetContentByName("video");
1944 dc = updated_offer->GetContentByName("data");
1945 ASSERT_TRUE(ac != NULL);
1946 ASSERT_TRUE(vc != NULL);
1947 ASSERT_TRUE(dc != NULL);
1948 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001949 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001951 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001952 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001953 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001954
1955 EXPECT_EQ(acd->type(), updated_acd->type());
1956 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1957 EXPECT_EQ(vcd->type(), updated_vcd->type());
1958 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1959 EXPECT_EQ(dcd->type(), updated_dcd->type());
1960 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001961 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001962 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001963 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001964 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001965 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001966 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1967
1968 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1969 ASSERT_EQ(2U, updated_audio_streams.size());
1970 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1971 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1972 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1973 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1974 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1975
1976 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1977 ASSERT_EQ(2U, updated_video_streams.size());
1978 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1979 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001980 // All the media streams in one PeerConnection share one RTCP CNAME.
1981 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001982
1983 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1984 ASSERT_EQ(2U, updated_data_streams.size());
1985 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1986 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1987 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1988 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1989 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001990 // The stream correctly got the CNAME from the MediaSessionOptions.
1991 // The Expected RTCP CNAME is the default one as we are using the default
1992 // MediaSessionOptions.
1993 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994}
1995
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001996// Create an offer with simulcast video stream.
1997TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1998 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001999 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2000 RtpTransceiverDirection::kRecvOnly, kActive,
2001 &opts);
2002 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2003 RtpTransceiverDirection::kSendRecv, kActive,
2004 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002005 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002006 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2007 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002008 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002009
2010 ASSERT_TRUE(offer.get() != NULL);
2011 const ContentInfo* vc = offer->GetContentByName("video");
2012 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002013 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002014
2015 const StreamParamsVec& video_streams = vcd->streams();
2016 ASSERT_EQ(1U, video_streams.size());
2017 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2018 const SsrcGroup* sim_ssrc_group =
2019 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2020 ASSERT_TRUE(sim_ssrc_group != NULL);
2021 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2022}
2023
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002024MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2025 const RidDescription& rid1 = ::testing::get<0>(arg);
2026 const RidDescription& rid2 = ::testing::get<1>(arg);
2027 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2028}
2029
2030static void CheckSimulcastInSessionDescription(
2031 const SessionDescription* description,
2032 const std::string& content_name,
2033 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002034 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002035 ASSERT_NE(description, nullptr);
2036 const ContentInfo* content = description->GetContentByName(content_name);
2037 ASSERT_NE(content, nullptr);
2038 const MediaContentDescription* cd = content->media_description();
2039 ASSERT_NE(cd, nullptr);
2040 const StreamParamsVec& streams = cd->streams();
2041 ASSERT_THAT(streams, SizeIs(1));
2042 const StreamParams& stream = streams[0];
2043 ASSERT_THAT(stream.ssrcs, IsEmpty());
2044 EXPECT_TRUE(stream.has_rids());
2045 const std::vector<RidDescription> rids = stream.rids();
2046
2047 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2048
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002049 EXPECT_TRUE(cd->HasSimulcast());
2050 const SimulcastDescription& simulcast = cd->simulcast_description();
2051 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2052 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2053
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002054 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002055}
2056
2057// Create an offer with spec-compliant simulcast video stream.
2058TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2059 MediaSessionOptions opts;
2060 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2061 RtpTransceiverDirection::kSendRecv, kActive,
2062 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002063 std::vector<RidDescription> send_rids;
2064 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2065 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2066 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2067 SimulcastLayerList simulcast_layers;
2068 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2069 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2070 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2071 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2072 {kMediaStream1}, send_rids,
2073 simulcast_layers, 0, &opts);
2074 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2075
2076 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002077 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002078}
2079
2080// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2081// In this scenario, RIDs do not need to be negotiated (there is only one).
2082TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2083 MediaSessionOptions opts;
2084 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2085 RtpTransceiverDirection::kSendRecv, kActive,
2086 &opts);
2087 RidDescription rid("f", RidDirection::kSend);
2088 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2089 {kMediaStream1}, {rid},
2090 SimulcastLayerList(), 0, &opts);
2091 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2092
2093 ASSERT_NE(offer.get(), nullptr);
2094 const ContentInfo* content = offer->GetContentByName("video");
2095 ASSERT_NE(content, nullptr);
2096 const MediaContentDescription* cd = content->media_description();
2097 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002098 const StreamParamsVec& streams = cd->streams();
2099 ASSERT_THAT(streams, SizeIs(1));
2100 const StreamParams& stream = streams[0];
2101 ASSERT_THAT(stream.ssrcs, IsEmpty());
2102 EXPECT_FALSE(stream.has_rids());
2103 EXPECT_FALSE(cd->HasSimulcast());
2104}
2105
2106// Create an answer with spec-compliant simulcast video stream.
2107// In this scenario, the SFU is the caller requesting that we send Simulcast.
2108TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2109 MediaSessionOptions offer_opts;
2110 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2111 RtpTransceiverDirection::kSendRecv, kActive,
2112 &offer_opts);
2113 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2114 {kMediaStream1}, 1, &offer_opts);
2115 std::unique_ptr<SessionDescription> offer =
2116 f1_.CreateOffer(offer_opts, nullptr);
2117
2118 MediaSessionOptions answer_opts;
2119 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2120 RtpTransceiverDirection::kSendRecv, kActive,
2121 &answer_opts);
2122
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002123 std::vector<RidDescription> rid_descriptions{
2124 RidDescription("f", RidDirection::kSend),
2125 RidDescription("h", RidDirection::kSend),
2126 RidDescription("q", RidDirection::kSend),
2127 };
2128 SimulcastLayerList simulcast_layers;
2129 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2130 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2131 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2132 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2133 {kMediaStream1}, rid_descriptions,
2134 simulcast_layers, 0, &answer_opts);
2135 std::unique_ptr<SessionDescription> answer =
2136 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2137
2138 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002139 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002140}
2141
2142// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2143// In this scenario, RIDs do not need to be negotiated (there is only one).
2144// Note that RID Direction is not the same as the transceiver direction.
2145TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2146 MediaSessionOptions offer_opts;
2147 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2148 RtpTransceiverDirection::kSendRecv, kActive,
2149 &offer_opts);
2150 RidDescription rid_offer("f", RidDirection::kSend);
2151 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2152 {kMediaStream1}, {rid_offer},
2153 SimulcastLayerList(), 0, &offer_opts);
2154 std::unique_ptr<SessionDescription> offer =
2155 f1_.CreateOffer(offer_opts, nullptr);
2156
2157 MediaSessionOptions answer_opts;
2158 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2159 RtpTransceiverDirection::kSendRecv, kActive,
2160 &answer_opts);
2161
2162 RidDescription rid_answer("f", RidDirection::kReceive);
2163 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2164 {kMediaStream1}, {rid_answer},
2165 SimulcastLayerList(), 0, &answer_opts);
2166 std::unique_ptr<SessionDescription> answer =
2167 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2168
2169 ASSERT_NE(answer.get(), nullptr);
2170 const ContentInfo* content = offer->GetContentByName("video");
2171 ASSERT_NE(content, nullptr);
2172 const MediaContentDescription* cd = content->media_description();
2173 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002174 const StreamParamsVec& streams = cd->streams();
2175 ASSERT_THAT(streams, SizeIs(1));
2176 const StreamParams& stream = streams[0];
2177 ASSERT_THAT(stream.ssrcs, IsEmpty());
2178 EXPECT_FALSE(stream.has_rids());
2179 EXPECT_FALSE(cd->HasSimulcast());
2180}
2181
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002182// Create an audio and video answer to a standard video offer with:
2183// - one video track
2184// - two audio tracks
2185// - two data tracks
2186// and ensure it matches what we expect. Also updates the initial answer by
2187// adding a new video track and removes one of the audio tracks.
2188TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2189 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002190 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2191 RtpTransceiverDirection::kRecvOnly, kActive,
2192 &offer_opts);
2193 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2194 RtpTransceiverDirection::kRecvOnly, kActive,
2195 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002196 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002197 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2198 RtpTransceiverDirection::kRecvOnly, kActive,
2199 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002200 f1_.set_secure(SEC_ENABLED);
2201 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002202 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002203
zhihuang1c378ed2017-08-17 14:10:50 -07002204 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002205 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2206 RtpTransceiverDirection::kSendRecv, kActive,
2207 &answer_opts);
2208 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2209 RtpTransceiverDirection::kSendRecv, kActive,
2210 &answer_opts);
2211 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2212 {kMediaStream1}, 1, &answer_opts);
2213 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2214 {kMediaStream1}, 1, &answer_opts);
2215 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2216 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002217
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002218 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2219 RtpTransceiverDirection::kSendRecv, kActive,
2220 &answer_opts);
2221 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2222 {kMediaStream1}, 1, &answer_opts);
2223 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2224 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002225 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002226
Steve Anton6fe1fba2018-12-11 10:15:23 -08002227 std::unique_ptr<SessionDescription> answer =
2228 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002229
2230 ASSERT_TRUE(answer.get() != NULL);
2231 const ContentInfo* ac = answer->GetContentByName("audio");
2232 const ContentInfo* vc = answer->GetContentByName("video");
2233 const ContentInfo* dc = answer->GetContentByName("data");
2234 ASSERT_TRUE(ac != NULL);
2235 ASSERT_TRUE(vc != NULL);
2236 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002237 const AudioContentDescription* acd = ac->media_description()->as_audio();
2238 const VideoContentDescription* vcd = vc->media_description()->as_video();
2239 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002240 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2241 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2242 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002243
2244 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002245 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002246
2247 const StreamParamsVec& audio_streams = acd->streams();
2248 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002249 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002250 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2251 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2252 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2253 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2254 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2255 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2256
2257 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2258 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2259
2260 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002261 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002262
2263 const StreamParamsVec& video_streams = vcd->streams();
2264 ASSERT_EQ(1U, video_streams.size());
2265 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2266 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2267 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2268 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2269
2270 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002271 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002272
2273 const StreamParamsVec& data_streams = dcd->streams();
2274 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002275 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002276 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2277 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2278 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2279 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2280 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2281 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2282
2283 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002284 dcd->bandwidth()); // default bandwidth (auto)
2285 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002286
2287 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002288 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002289 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2290 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002291 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2292 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002293 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002294 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002295
2296 ASSERT_TRUE(updated_answer.get() != NULL);
2297 ac = updated_answer->GetContentByName("audio");
2298 vc = updated_answer->GetContentByName("video");
2299 dc = updated_answer->GetContentByName("data");
2300 ASSERT_TRUE(ac != NULL);
2301 ASSERT_TRUE(vc != NULL);
2302 ASSERT_TRUE(dc != NULL);
2303 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002304 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002305 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002306 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002307 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002308 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002309
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002310 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002311 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002312 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002313 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002314 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002315 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2316
2317 EXPECT_EQ(acd->type(), updated_acd->type());
2318 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2319 EXPECT_EQ(vcd->type(), updated_vcd->type());
2320 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2321 EXPECT_EQ(dcd->type(), updated_dcd->type());
2322 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2323
2324 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2325 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002326 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002327
2328 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2329 ASSERT_EQ(2U, updated_video_streams.size());
2330 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2331 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002332 // All media streams in one PeerConnection share one CNAME.
2333 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002334
2335 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2336 ASSERT_EQ(1U, updated_data_streams.size());
2337 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2338}
2339
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340// Create an updated offer after creating an answer to the original offer and
2341// verify that the codecs that were part of the original answer are not changed
2342// in the updated offer.
2343TEST_F(MediaSessionDescriptionFactoryTest,
2344 RespondentCreatesOfferAfterCreatingAnswer) {
2345 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002346 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002347
Steve Anton6fe1fba2018-12-11 10:15:23 -08002348 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2349 std::unique_ptr<SessionDescription> answer =
2350 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002351
2352 const AudioContentDescription* acd =
2353 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002354 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002355
2356 const VideoContentDescription* vcd =
2357 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002358 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002359
kwiberg31022942016-03-11 14:18:21 -08002360 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002361 f2_.CreateOffer(opts, answer.get()));
2362
2363 // The expected audio codecs are the common audio codecs from the first
2364 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2365 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002366 // TODO(wu): |updated_offer| should not include the codec
2367 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002368 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002369 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002370 };
2371
2372 // The expected video codecs are the common video codecs from the first
2373 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2374 // preference order.
2375 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002376 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002377 };
2378
2379 const AudioContentDescription* updated_acd =
2380 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002381 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382
2383 const VideoContentDescription* updated_vcd =
2384 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002385 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002386}
2387
Steve Anton5c72e712018-12-10 14:25:30 -08002388// Test that a reoffer does not reuse audio codecs from a previous media section
2389// that is being recycled.
2390TEST_F(MediaSessionDescriptionFactoryTest,
2391 ReOfferDoesNotReUseRecycledAudioCodecs) {
2392 f1_.set_video_codecs({});
2393 f2_.set_video_codecs({});
2394
2395 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002396 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2397 RtpTransceiverDirection::kSendRecv, kActive,
2398 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002399 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2400 std::unique_ptr<SessionDescription> answer =
2401 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002402
2403 // Recycle the media section by changing its mid.
2404 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002405 std::unique_ptr<SessionDescription> reoffer =
2406 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002407
2408 // Expect that the results of the first negotiation are ignored. If the m=
2409 // section was not recycled the payload types would match the initial offerer.
2410 const AudioContentDescription* acd =
2411 GetFirstAudioContentDescription(reoffer.get());
2412 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2413}
2414
2415// Test that a reoffer does not reuse video codecs from a previous media section
2416// that is being recycled.
2417TEST_F(MediaSessionDescriptionFactoryTest,
2418 ReOfferDoesNotReUseRecycledVideoCodecs) {
2419 f1_.set_audio_codecs({}, {});
2420 f2_.set_audio_codecs({}, {});
2421
2422 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002423 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2424 RtpTransceiverDirection::kSendRecv, kActive,
2425 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002426 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2427 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002428
2429 // Recycle the media section by changing its mid.
2430 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002431 std::unique_ptr<SessionDescription> reoffer =
2432 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002433
2434 // Expect that the results of the first negotiation are ignored. If the m=
2435 // section was not recycled the payload types would match the initial offerer.
2436 const VideoContentDescription* vcd =
2437 GetFirstVideoContentDescription(reoffer.get());
2438 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2439}
2440
2441// Test that a reanswer does not reuse audio codecs from a previous media
2442// section that is being recycled.
2443TEST_F(MediaSessionDescriptionFactoryTest,
2444 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2445 f1_.set_video_codecs({});
2446 f2_.set_video_codecs({});
2447
2448 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2449 // second offer/answer is forward (|f1_| as offerer).
2450 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002451 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2452 RtpTransceiverDirection::kSendRecv, kActive,
2453 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002454 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2455 std::unique_ptr<SessionDescription> answer =
2456 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002457
2458 // Recycle the media section by changing its mid.
2459 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002460 std::unique_ptr<SessionDescription> reoffer =
2461 f1_.CreateOffer(opts, answer.get());
2462 std::unique_ptr<SessionDescription> reanswer =
2463 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002464
2465 // Expect that the results of the first negotiation are ignored. If the m=
2466 // section was not recycled the payload types would match the initial offerer.
2467 const AudioContentDescription* acd =
2468 GetFirstAudioContentDescription(reanswer.get());
2469 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2470}
2471
2472// Test that a reanswer does not reuse video codecs from a previous media
2473// section that is being recycled.
2474TEST_F(MediaSessionDescriptionFactoryTest,
2475 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2476 f1_.set_audio_codecs({}, {});
2477 f2_.set_audio_codecs({}, {});
2478
2479 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2480 // second offer/answer is forward (|f1_| as offerer).
2481 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002482 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2483 RtpTransceiverDirection::kSendRecv, kActive,
2484 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002485 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2486 std::unique_ptr<SessionDescription> answer =
2487 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002488
2489 // Recycle the media section by changing its mid.
2490 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002491 std::unique_ptr<SessionDescription> reoffer =
2492 f1_.CreateOffer(opts, answer.get());
2493 std::unique_ptr<SessionDescription> reanswer =
2494 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002495
2496 // Expect that the results of the first negotiation are ignored. If the m=
2497 // section was not recycled the payload types would match the initial offerer.
2498 const VideoContentDescription* vcd =
2499 GetFirstVideoContentDescription(reanswer.get());
2500 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2501}
2502
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002503// Create an updated offer after creating an answer to the original offer and
2504// verify that the codecs that were part of the original answer are not changed
2505// in the updated offer. In this test Rtx is enabled.
2506TEST_F(MediaSessionDescriptionFactoryTest,
2507 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2508 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002509 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2510 RtpTransceiverDirection::kRecvOnly, kActive,
2511 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002512 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002513 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002514 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002515 f1_.set_video_codecs(f1_codecs);
2516
2517 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002518 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002519 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002520 f2_.set_video_codecs(f2_codecs);
2521
Steve Anton6fe1fba2018-12-11 10:15:23 -08002522 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002523 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002524 std::unique_ptr<SessionDescription> answer =
2525 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526
2527 const VideoContentDescription* vcd =
2528 GetFirstVideoContentDescription(answer.get());
2529
2530 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002531 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2532 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002533
2534 EXPECT_EQ(expected_codecs, vcd->codecs());
2535
deadbeef67cf2c12016-04-13 10:07:16 -07002536 // Now, make sure we get same result (except for the order) if |f2_| creates
2537 // an updated offer even though the default payload types between |f1_| and
2538 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002539 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002540 f2_.CreateOffer(opts, answer.get()));
2541 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002542 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002543 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2544
2545 const VideoContentDescription* updated_vcd =
2546 GetFirstVideoContentDescription(updated_answer.get());
2547
2548 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2549}
2550
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002551// Regression test for:
2552// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2553// Existing codecs should always appear before new codecs in re-offers. But
2554// under a specific set of circumstances, the existing RTX codec was ending up
2555// added to the end of the list.
2556TEST_F(MediaSessionDescriptionFactoryTest,
2557 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2558 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002559 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2560 RtpTransceiverDirection::kRecvOnly, kActive,
2561 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002562 // We specifically choose different preferred payload types for VP8 to
2563 // trigger the issue.
2564 cricket::VideoCodec vp8_offerer(100, "VP8");
2565 cricket::VideoCodec vp8_offerer_rtx =
2566 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2567 cricket::VideoCodec vp8_answerer(110, "VP8");
2568 cricket::VideoCodec vp8_answerer_rtx =
2569 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2570 cricket::VideoCodec vp9(120, "VP9");
2571 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2572
2573 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2574 // We also specifically cause the answerer to prefer VP9, such that if it
2575 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2576 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2577 vp8_answerer_rtx};
2578
2579 f1_.set_video_codecs(f1_codecs);
2580 f2_.set_video_codecs(f2_codecs);
2581 std::vector<AudioCodec> audio_codecs;
2582 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2583 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2584
2585 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002586 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002587 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002588 std::unique_ptr<SessionDescription> answer =
2589 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002590
2591 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2592 // But if the bug is triggered, RTX for VP8 ends up last.
2593 std::unique_ptr<SessionDescription> updated_offer(
2594 f2_.CreateOffer(opts, answer.get()));
2595
2596 const VideoContentDescription* vcd =
2597 GetFirstVideoContentDescription(updated_offer.get());
2598 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2599 ASSERT_EQ(4u, codecs.size());
2600 EXPECT_EQ(vp8_offerer, codecs[0]);
2601 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2602 EXPECT_EQ(vp9, codecs[2]);
2603 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002604}
2605
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002606// Create an updated offer that adds video after creating an audio only answer
2607// to the original offer. This test verifies that if a video codec and the RTX
2608// codec have the same default payload type as an audio codec that is already in
2609// use, the added codecs payload types are changed.
2610TEST_F(MediaSessionDescriptionFactoryTest,
2611 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2612 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002613 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002614 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002615 f1_.set_video_codecs(f1_codecs);
2616
2617 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002618 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2619 RtpTransceiverDirection::kRecvOnly, kActive,
2620 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002621
Steve Anton6fe1fba2018-12-11 10:15:23 -08002622 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2623 std::unique_ptr<SessionDescription> answer =
2624 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002625
2626 const AudioContentDescription* acd =
2627 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002628 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002629
2630 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2631 // reference be the same as an audio codec that was negotiated in the
2632 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002633 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002634 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002635
2636 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2637 int used_pl_type = acd->codecs()[0].id;
2638 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002639 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002640 f2_.set_video_codecs(f2_codecs);
2641
kwiberg31022942016-03-11 14:18:21 -08002642 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002643 f2_.CreateOffer(opts, answer.get()));
2644 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002645 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002646 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2647
2648 const AudioContentDescription* updated_acd =
2649 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002650 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002651
2652 const VideoContentDescription* updated_vcd =
2653 GetFirstVideoContentDescription(updated_answer.get());
2654
2655 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002656 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002657 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002658 EXPECT_NE(used_pl_type, new_h264_pl_type);
2659 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002660 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2662 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2663}
2664
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002665// Create an updated offer with RTX after creating an answer to an offer
2666// without RTX, and with different default payload types.
2667// Verify that the added RTX codec references the correct payload type.
2668TEST_F(MediaSessionDescriptionFactoryTest,
2669 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2670 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002671 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002672
2673 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2674 // This creates rtx for H264 with the payload type |f2_| uses.
2675 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2676 f2_.set_video_codecs(f2_codecs);
2677
Steve Anton6fe1fba2018-12-11 10:15:23 -08002678 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002679 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002680 std::unique_ptr<SessionDescription> answer =
2681 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002682
2683 const VideoContentDescription* vcd =
2684 GetFirstVideoContentDescription(answer.get());
2685
2686 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2687 EXPECT_EQ(expected_codecs, vcd->codecs());
2688
2689 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2690 // updated offer, even though the default payload types are different from
2691 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002692 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002693 f2_.CreateOffer(opts, answer.get()));
2694 ASSERT_TRUE(updated_offer);
2695
2696 const VideoContentDescription* updated_vcd =
2697 GetFirstVideoContentDescription(updated_offer.get());
2698
2699 // New offer should attempt to add H263, and RTX for H264.
2700 expected_codecs.push_back(kVideoCodecs2[1]);
2701 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2702 &expected_codecs);
2703 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2704}
2705
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002706// Test that RTX is ignored when there is no associated payload type parameter.
2707TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2708 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002709 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2710 RtpTransceiverDirection::kRecvOnly, kActive,
2711 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002712 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002713 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002714 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002715 f1_.set_video_codecs(f1_codecs);
2716
2717 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002718 // This creates RTX for H264 with the payload type |f2_| uses.
2719 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720 f2_.set_video_codecs(f2_codecs);
2721
Steve Anton6fe1fba2018-12-11 10:15:23 -08002722 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002723 ASSERT_TRUE(offer.get() != NULL);
2724 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2725 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2726 // is possible to test that that RTX is dropped when
2727 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002728 MediaContentDescription* media_desc =
2729 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2730 ASSERT_TRUE(media_desc);
2731 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002732 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002733 for (VideoCodec& codec : codecs) {
2734 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2735 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002736 }
2737 }
2738 desc->set_codecs(codecs);
2739
Steve Anton6fe1fba2018-12-11 10:15:23 -08002740 std::unique_ptr<SessionDescription> answer =
2741 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002742
Steve Anton64b626b2019-01-28 17:25:26 -08002743 EXPECT_THAT(
2744 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2745 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002746}
2747
2748// Test that RTX will be filtered out in the answer if its associated payload
2749// type doesn't match the local value.
2750TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2751 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002752 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2753 RtpTransceiverDirection::kRecvOnly, kActive,
2754 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002755 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2756 // This creates RTX for H264 in sender.
2757 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2758 f1_.set_video_codecs(f1_codecs);
2759
2760 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2761 // This creates RTX for H263 in receiver.
2762 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2763 f2_.set_video_codecs(f2_codecs);
2764
Steve Anton6fe1fba2018-12-11 10:15:23 -08002765 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002766 ASSERT_TRUE(offer.get() != NULL);
2767 // Associated payload type doesn't match, therefore, RTX codec is removed in
2768 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002769 std::unique_ptr<SessionDescription> answer =
2770 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002771
Steve Anton64b626b2019-01-28 17:25:26 -08002772 EXPECT_THAT(
2773 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2774 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002775}
2776
2777// Test that when multiple RTX codecs are offered, only the matched RTX codec
2778// is added in the answer, and the unsupported RTX codec is filtered out.
2779TEST_F(MediaSessionDescriptionFactoryTest,
2780 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2781 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002782 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2783 RtpTransceiverDirection::kRecvOnly, kActive,
2784 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002785 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2786 // This creates RTX for H264-SVC in sender.
2787 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2788 f1_.set_video_codecs(f1_codecs);
2789
2790 // This creates RTX for H264 in sender.
2791 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2792 f1_.set_video_codecs(f1_codecs);
2793
2794 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2795 // This creates RTX for H264 in receiver.
2796 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2797 f2_.set_video_codecs(f2_codecs);
2798
2799 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2800 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002801 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002802 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002803 std::unique_ptr<SessionDescription> answer =
2804 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805 const VideoContentDescription* vcd =
2806 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002807 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2808 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2809 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002810
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002811 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002812}
2813
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002814// Test that after one RTX codec has been negotiated, a new offer can attempt
2815// to add another.
2816TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2817 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002818 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2819 RtpTransceiverDirection::kRecvOnly, kActive,
2820 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002821 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2822 // This creates RTX for H264 for the offerer.
2823 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2824 f1_.set_video_codecs(f1_codecs);
2825
Steve Anton6fe1fba2018-12-11 10:15:23 -08002826 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002827 ASSERT_TRUE(offer);
2828 const VideoContentDescription* vcd =
2829 GetFirstVideoContentDescription(offer.get());
2830
2831 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2832 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2833 &expected_codecs);
2834 EXPECT_EQ(expected_codecs, vcd->codecs());
2835
2836 // Now, attempt to add RTX for H264-SVC.
2837 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2838 f1_.set_video_codecs(f1_codecs);
2839
kwiberg31022942016-03-11 14:18:21 -08002840 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002841 f1_.CreateOffer(opts, offer.get()));
2842 ASSERT_TRUE(updated_offer);
2843 vcd = GetFirstVideoContentDescription(updated_offer.get());
2844
2845 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2846 &expected_codecs);
2847 EXPECT_EQ(expected_codecs, vcd->codecs());
2848}
2849
Noah Richards2e7a0982015-05-18 14:02:54 -07002850// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2851// generated for each simulcast ssrc and correctly grouped.
2852TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2853 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002854 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2855 RtpTransceiverDirection::kSendRecv, kActive,
2856 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002857 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002858 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2859 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002860
2861 // Use a single real codec, and then add RTX for it.
2862 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002863 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002864 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2865 f1_.set_video_codecs(f1_codecs);
2866
2867 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2868 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002869 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002870 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002871 MediaContentDescription* media_desc =
2872 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2873 ASSERT_TRUE(media_desc);
2874 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002875 const StreamParamsVec& streams = desc->streams();
2876 // Single stream.
2877 ASSERT_EQ(1u, streams.size());
2878 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2879 EXPECT_EQ(6u, streams[0].ssrcs.size());
2880 // And should have a SIM group for the simulcast.
2881 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2882 // And a FID group for RTX.
2883 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002884 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002885 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2886 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002887 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002888 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2889 EXPECT_EQ(3u, fid_ssrcs.size());
2890}
2891
brandtr03d5fb12016-11-22 03:37:59 -08002892// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2893// together with a FEC-FR grouping.
2894TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2895 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002896 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2897 RtpTransceiverDirection::kSendRecv, kActive,
2898 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002899 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002900 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2901 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002902
2903 // Use a single real codec, and then add FlexFEC for it.
2904 std::vector<VideoCodec> f1_codecs;
2905 f1_codecs.push_back(VideoCodec(97, "H264"));
2906 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2907 f1_.set_video_codecs(f1_codecs);
2908
2909 // Ensure that the offer has a single FlexFEC ssrc and that
2910 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002911 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002912 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002913 MediaContentDescription* media_desc =
2914 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2915 ASSERT_TRUE(media_desc);
2916 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002917 const StreamParamsVec& streams = desc->streams();
2918 // Single stream.
2919 ASSERT_EQ(1u, streams.size());
2920 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2921 EXPECT_EQ(2u, streams[0].ssrcs.size());
2922 // And should have a FEC-FR group for FlexFEC.
2923 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2924 std::vector<uint32_t> primary_ssrcs;
2925 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2926 ASSERT_EQ(1u, primary_ssrcs.size());
2927 uint32_t flexfec_ssrc;
2928 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2929 EXPECT_NE(flexfec_ssrc, 0u);
2930}
2931
2932// Test that FlexFEC is disabled for simulcast.
2933// TODO(brandtr): Remove this test when we support simulcast, either through
2934// multiple FlexfecSenders, or through multistream protection.
2935TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2936 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002937 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2938 RtpTransceiverDirection::kSendRecv, kActive,
2939 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002940 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002941 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2942 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002943
2944 // Use a single real codec, and then add FlexFEC for it.
2945 std::vector<VideoCodec> f1_codecs;
2946 f1_codecs.push_back(VideoCodec(97, "H264"));
2947 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2948 f1_.set_video_codecs(f1_codecs);
2949
2950 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2951 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002952 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002953 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002954 MediaContentDescription* media_desc =
2955 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2956 ASSERT_TRUE(media_desc);
2957 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002958 const StreamParamsVec& streams = desc->streams();
2959 // Single stream.
2960 ASSERT_EQ(1u, streams.size());
2961 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2962 EXPECT_EQ(3u, streams[0].ssrcs.size());
2963 // And should have a SIM group for the simulcast.
2964 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2965 // And not a FEC-FR group for FlexFEC.
2966 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2967 std::vector<uint32_t> primary_ssrcs;
2968 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2969 EXPECT_EQ(3u, primary_ssrcs.size());
2970 for (uint32_t primary_ssrc : primary_ssrcs) {
2971 uint32_t flexfec_ssrc;
2972 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2973 }
2974}
2975
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002976// Create an updated offer after creating an answer to the original offer and
2977// verify that the RTP header extensions that were part of the original answer
2978// are not changed in the updated offer.
2979TEST_F(MediaSessionDescriptionFactoryTest,
2980 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2981 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002982 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002983
2984 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2985 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2986 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2987 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2988
Steve Anton6fe1fba2018-12-11 10:15:23 -08002989 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2990 std::unique_ptr<SessionDescription> answer =
2991 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002992
Yves Gerey665174f2018-06-19 15:03:05 +02002993 EXPECT_EQ(
2994 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2995 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2996 EXPECT_EQ(
2997 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2998 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002999
kwiberg31022942016-03-11 14:18:21 -08003000 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003001 f2_.CreateOffer(opts, answer.get()));
3002
3003 // The expected RTP header extensions in the new offer are the resulting
3004 // extensions from the first offer/answer exchange plus the extensions only
3005 // |f2_| offer.
3006 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003007 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003008 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3009 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3010 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003011 };
3012
3013 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003014 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003015 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3016 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3017 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003018 };
3019
3020 const AudioContentDescription* updated_acd =
3021 GetFirstAudioContentDescription(updated_offer.get());
3022 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3023 updated_acd->rtp_header_extensions());
3024
3025 const VideoContentDescription* updated_vcd =
3026 GetFirstVideoContentDescription(updated_offer.get());
3027 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3028 updated_vcd->rtp_header_extensions());
3029}
3030
deadbeefa5b273a2015-08-20 17:30:13 -07003031// Verify that if the same RTP extension URI is used for audio and video, the
3032// same ID is used. Also verify that the ID isn't changed when creating an
3033// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003034TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003035 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003036 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003037
3038 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3039 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3040
Steve Anton6fe1fba2018-12-11 10:15:23 -08003041 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003042
3043 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3044 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003045 const RtpExtension kExpectedVideoRtpExtension[] = {
3046 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003047 };
3048
Yves Gerey665174f2018-06-19 15:03:05 +02003049 EXPECT_EQ(
3050 MAKE_VECTOR(kAudioRtpExtension3),
3051 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3052 EXPECT_EQ(
3053 MAKE_VECTOR(kExpectedVideoRtpExtension),
3054 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003055
3056 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003057 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003058 f1_.CreateOffer(opts, offer.get()));
3059
3060 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003061 GetFirstAudioContentDescription(updated_offer.get())
3062 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003063 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003064 GetFirstVideoContentDescription(updated_offer.get())
3065 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003066}
3067
jbauch5869f502017-06-29 12:31:36 -07003068// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3069TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3070 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003071 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003072
3073 f1_.set_enable_encrypted_rtp_header_extensions(true);
3074 f2_.set_enable_encrypted_rtp_header_extensions(true);
3075
3076 f1_.set_audio_rtp_header_extensions(
3077 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3078 f1_.set_video_rtp_header_extensions(
3079 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3080
Steve Anton6fe1fba2018-12-11 10:15:23 -08003081 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003082
3083 // The extensions that are shared between audio and video should use the same
3084 // id.
3085 const RtpExtension kExpectedVideoRtpExtension[] = {
3086 kVideoRtpExtension3ForEncryption[0],
3087 kAudioRtpExtension3ForEncryptionOffer[1],
3088 kAudioRtpExtension3ForEncryptionOffer[2],
3089 };
3090
Yves Gerey665174f2018-06-19 15:03:05 +02003091 EXPECT_EQ(
3092 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3093 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3094 EXPECT_EQ(
3095 MAKE_VECTOR(kExpectedVideoRtpExtension),
3096 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003097
3098 // Nothing should change when creating a new offer
3099 std::unique_ptr<SessionDescription> updated_offer(
3100 f1_.CreateOffer(opts, offer.get()));
3101
3102 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003103 GetFirstAudioContentDescription(updated_offer.get())
3104 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003105 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003106 GetFirstVideoContentDescription(updated_offer.get())
3107 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003108}
3109
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003110TEST(MediaSessionDescription, CopySessionDescription) {
3111 SessionDescription source;
3112 cricket::ContentGroup group(cricket::CN_AUDIO);
3113 source.AddGroup(group);
3114 AudioContentDescription* acd(new AudioContentDescription());
3115 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3116 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003117 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003118 VideoContentDescription* vcd(new VideoContentDescription());
3119 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3120 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003121 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003122
kwiberg31022942016-03-11 14:18:21 -08003123 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003124 ASSERT_TRUE(copy.get() != NULL);
3125 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3126 const ContentInfo* ac = copy->GetContentByName("audio");
3127 const ContentInfo* vc = copy->GetContentByName("video");
3128 ASSERT_TRUE(ac != NULL);
3129 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003130 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003131 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003132 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3133 EXPECT_EQ(1u, acd->first_ssrc());
3134
Steve Anton5adfafd2017-12-20 16:34:00 -08003135 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003136 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003137 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3138 EXPECT_EQ(2u, vcd->first_ssrc());
3139}
3140
3141// The below TestTransportInfoXXX tests create different offers/answers, and
3142// ensure the TransportInfo in the SessionDescription matches what we expect.
3143TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3144 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003145 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3146 RtpTransceiverDirection::kRecvOnly, kActive,
3147 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003148 TestTransportInfo(true, options, false);
3149}
3150
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003151TEST_F(MediaSessionDescriptionFactoryTest,
3152 TestTransportInfoOfferIceRenomination) {
3153 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003154 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3155 RtpTransceiverDirection::kRecvOnly, kActive,
3156 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003157 options.media_description_options[0]
3158 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003159 TestTransportInfo(true, options, false);
3160}
3161
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003162TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3163 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003164 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3165 RtpTransceiverDirection::kRecvOnly, kActive,
3166 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003167 TestTransportInfo(true, options, true);
3168}
3169
3170TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3171 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003172 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3173 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3174 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003175 TestTransportInfo(true, options, false);
3176}
3177
3178TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003179 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003180 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003181 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3182 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3183 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003184 TestTransportInfo(true, options, true);
3185}
3186
3187TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3188 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003189 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3190 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3191 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003192 options.bundle_enabled = true;
3193 TestTransportInfo(true, options, false);
3194}
3195
3196TEST_F(MediaSessionDescriptionFactoryTest,
3197 TestTransportInfoOfferBundleCurrent) {
3198 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003199 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3200 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3201 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003202 options.bundle_enabled = true;
3203 TestTransportInfo(true, options, true);
3204}
3205
3206TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3207 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003208 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3209 RtpTransceiverDirection::kRecvOnly, kActive,
3210 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003211 TestTransportInfo(false, options, false);
3212}
3213
3214TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003215 TestTransportInfoAnswerIceRenomination) {
3216 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003217 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3218 RtpTransceiverDirection::kRecvOnly, kActive,
3219 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003220 options.media_description_options[0]
3221 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003222 TestTransportInfo(false, options, false);
3223}
3224
3225TEST_F(MediaSessionDescriptionFactoryTest,
3226 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003227 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003228 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3229 RtpTransceiverDirection::kRecvOnly, kActive,
3230 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003231 TestTransportInfo(false, options, true);
3232}
3233
3234TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3235 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003236 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3237 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3238 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003239 TestTransportInfo(false, options, false);
3240}
3241
3242TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003243 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003244 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003245 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3246 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3247 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003248 TestTransportInfo(false, options, true);
3249}
3250
3251TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3252 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003253 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3254 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3255 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003256 options.bundle_enabled = true;
3257 TestTransportInfo(false, options, false);
3258}
3259
3260TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003261 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003262 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003263 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3264 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3265 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003266 options.bundle_enabled = true;
3267 TestTransportInfo(false, options, true);
3268}
3269
3270// Create an offer with bundle enabled and verify the crypto parameters are
3271// the common set of the available cryptos.
3272TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3273 TestCryptoWithBundle(true);
3274}
3275
3276// Create an answer with bundle enabled and verify the crypto parameters are
3277// the common set of the available cryptos.
3278TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3279 TestCryptoWithBundle(false);
3280}
3281
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003282// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3283// DTLS is not enabled locally.
3284TEST_F(MediaSessionDescriptionFactoryTest,
3285 TestOfferDtlsSavpfWithoutDtlsFailed) {
3286 f1_.set_secure(SEC_ENABLED);
3287 f2_.set_secure(SEC_ENABLED);
3288 tdf1_.set_secure(SEC_DISABLED);
3289 tdf2_.set_secure(SEC_DISABLED);
3290
Steve Anton6fe1fba2018-12-11 10:15:23 -08003291 std::unique_ptr<SessionDescription> offer =
3292 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003293 ASSERT_TRUE(offer.get() != NULL);
3294 ContentInfo* offer_content = offer->GetContentByName("audio");
3295 ASSERT_TRUE(offer_content != NULL);
3296 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003297 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003298 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3299
Steve Anton6fe1fba2018-12-11 10:15:23 -08003300 std::unique_ptr<SessionDescription> answer =
3301 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003302 ASSERT_TRUE(answer != NULL);
3303 ContentInfo* answer_content = answer->GetContentByName("audio");
3304 ASSERT_TRUE(answer_content != NULL);
3305
3306 ASSERT_TRUE(answer_content->rejected);
3307}
3308
3309// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3310// UDP/TLS/RTP/SAVPF.
3311TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3312 f1_.set_secure(SEC_ENABLED);
3313 f2_.set_secure(SEC_ENABLED);
3314 tdf1_.set_secure(SEC_ENABLED);
3315 tdf2_.set_secure(SEC_ENABLED);
3316
Steve Anton6fe1fba2018-12-11 10:15:23 -08003317 std::unique_ptr<SessionDescription> offer =
3318 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003319 ASSERT_TRUE(offer.get() != NULL);
3320 ContentInfo* offer_content = offer->GetContentByName("audio");
3321 ASSERT_TRUE(offer_content != NULL);
3322 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003323 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003324 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3325
Steve Anton6fe1fba2018-12-11 10:15:23 -08003326 std::unique_ptr<SessionDescription> answer =
3327 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003328 ASSERT_TRUE(answer != NULL);
3329
3330 const ContentInfo* answer_content = answer->GetContentByName("audio");
3331 ASSERT_TRUE(answer_content != NULL);
3332 ASSERT_FALSE(answer_content->rejected);
3333
3334 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003335 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003336 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003337}
3338
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003339// Test that we include both SDES and DTLS in the offer, but only include SDES
3340// in the answer if DTLS isn't negotiated.
3341TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3342 f1_.set_secure(SEC_ENABLED);
3343 f2_.set_secure(SEC_ENABLED);
3344 tdf1_.set_secure(SEC_ENABLED);
3345 tdf2_.set_secure(SEC_DISABLED);
3346 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003347 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003348 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003349 const cricket::MediaContentDescription* audio_media_desc;
3350 const cricket::MediaContentDescription* video_media_desc;
3351 const cricket::TransportDescription* audio_trans_desc;
3352 const cricket::TransportDescription* video_trans_desc;
3353
3354 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003355 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003356 ASSERT_TRUE(offer.get() != NULL);
3357
Steve Antonb1c1de12017-12-21 15:14:30 -08003358 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003359 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003360 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003361 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003362 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003363 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3364
3365 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3366 ASSERT_TRUE(audio_trans_desc != NULL);
3367 video_trans_desc = offer->GetTransportDescriptionByName("video");
3368 ASSERT_TRUE(video_trans_desc != NULL);
3369 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3370 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3371
3372 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003373 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003374 ASSERT_TRUE(answer.get() != NULL);
3375
Steve Antonb1c1de12017-12-21 15:14:30 -08003376 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003377 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003378 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003379 ASSERT_TRUE(video_media_desc != NULL);
3380 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3381 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3382
3383 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3384 ASSERT_TRUE(audio_trans_desc != NULL);
3385 video_trans_desc = answer->GetTransportDescriptionByName("video");
3386 ASSERT_TRUE(video_trans_desc != NULL);
3387 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3388 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3389
3390 // Enable DTLS; the answer should now only have DTLS support.
3391 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003392 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003393 ASSERT_TRUE(answer.get() != NULL);
3394
Steve Antonb1c1de12017-12-21 15:14:30 -08003395 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003396 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003397 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003398 ASSERT_TRUE(video_media_desc != NULL);
3399 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3400 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003401 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3402 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003403
3404 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3405 ASSERT_TRUE(audio_trans_desc != NULL);
3406 video_trans_desc = answer->GetTransportDescriptionByName("video");
3407 ASSERT_TRUE(video_trans_desc != NULL);
3408 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3409 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003410
3411 // Try creating offer again. DTLS enabled now, crypto's should be empty
3412 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003413 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003414 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003415 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003416 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003417 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003418 ASSERT_TRUE(video_media_desc != NULL);
3419 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3420 EXPECT_TRUE(video_media_desc->cryptos().empty());
3421
3422 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3423 ASSERT_TRUE(audio_trans_desc != NULL);
3424 video_trans_desc = offer->GetTransportDescriptionByName("video");
3425 ASSERT_TRUE(video_trans_desc != NULL);
3426 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3427 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003428}
3429
3430// Test that an answer can't be created if cryptos are required but the offer is
3431// unsecure.
3432TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003433 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003434 f1_.set_secure(SEC_DISABLED);
3435 tdf1_.set_secure(SEC_DISABLED);
3436 f2_.set_secure(SEC_REQUIRED);
3437 tdf1_.set_secure(SEC_ENABLED);
3438
Steve Anton6fe1fba2018-12-11 10:15:23 -08003439 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003440 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003441 std::unique_ptr<SessionDescription> answer =
3442 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003443 EXPECT_TRUE(answer.get() == NULL);
3444}
3445
3446// Test that we accept a DTLS offer without SDES and create an appropriate
3447// answer.
3448TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3449 f1_.set_secure(SEC_DISABLED);
3450 f2_.set_secure(SEC_ENABLED);
3451 tdf1_.set_secure(SEC_ENABLED);
3452 tdf2_.set_secure(SEC_ENABLED);
3453 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003454 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3455 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3456 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003457
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003458 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003459 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003460 ASSERT_TRUE(offer.get() != NULL);
3461
3462 const AudioContentDescription* audio_offer =
3463 GetFirstAudioContentDescription(offer.get());
3464 ASSERT_TRUE(audio_offer->cryptos().empty());
3465 const VideoContentDescription* video_offer =
3466 GetFirstVideoContentDescription(offer.get());
3467 ASSERT_TRUE(video_offer->cryptos().empty());
3468 const DataContentDescription* data_offer =
3469 GetFirstDataContentDescription(offer.get());
3470 ASSERT_TRUE(data_offer->cryptos().empty());
3471
3472 const cricket::TransportDescription* audio_offer_trans_desc =
3473 offer->GetTransportDescriptionByName("audio");
3474 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3475 const cricket::TransportDescription* video_offer_trans_desc =
3476 offer->GetTransportDescriptionByName("video");
3477 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3478 const cricket::TransportDescription* data_offer_trans_desc =
3479 offer->GetTransportDescriptionByName("data");
3480 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3481
3482 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003483 std::unique_ptr<SessionDescription> answer =
3484 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003485 ASSERT_TRUE(answer.get() != NULL);
3486
3487 const cricket::TransportDescription* audio_answer_trans_desc =
3488 answer->GetTransportDescriptionByName("audio");
3489 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3490 const cricket::TransportDescription* video_answer_trans_desc =
3491 answer->GetTransportDescriptionByName("video");
3492 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3493 const cricket::TransportDescription* data_answer_trans_desc =
3494 answer->GetTransportDescriptionByName("data");
3495 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3496}
3497
3498// Verifies if vad_enabled option is set to false, CN codecs are not present in
3499// offer or answer.
3500TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3501 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003502 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003503 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003504 ASSERT_TRUE(offer.get() != NULL);
3505 const ContentInfo* audio_content = offer->GetContentByName("audio");
3506 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3507
3508 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003509 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003510 ASSERT_TRUE(offer.get() != NULL);
3511 audio_content = offer->GetContentByName("audio");
3512 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003513 std::unique_ptr<SessionDescription> answer =
3514 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003515 ASSERT_TRUE(answer.get() != NULL);
3516 audio_content = answer->GetContentByName("audio");
3517 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3518}
deadbeef44f08192015-12-15 16:20:09 -08003519
zhihuang1c378ed2017-08-17 14:10:50 -07003520// Test that the generated MIDs match the existing offer.
3521TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003522 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003523 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3524 RtpTransceiverDirection::kRecvOnly, kActive,
3525 &opts);
3526 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3527 RtpTransceiverDirection::kRecvOnly, kActive,
3528 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003529 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003530 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3531 RtpTransceiverDirection::kSendRecv, kActive,
3532 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003533 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003534 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003535 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003536 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003537
deadbeef44f08192015-12-15 16:20:09 -08003538 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3539 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3540 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3541 ASSERT_TRUE(audio_content != nullptr);
3542 ASSERT_TRUE(video_content != nullptr);
3543 ASSERT_TRUE(data_content != nullptr);
3544 EXPECT_EQ("audio_modified", audio_content->name);
3545 EXPECT_EQ("video_modified", video_content->name);
3546 EXPECT_EQ("data_modified", data_content->name);
3547}
zhihuangcf5b37c2016-05-05 11:44:35 -07003548
zhihuang1c378ed2017-08-17 14:10:50 -07003549// The following tests verify that the unified plan SDP is supported.
3550// Test that we can create an offer with multiple media sections of same media
3551// type.
3552TEST_F(MediaSessionDescriptionFactoryTest,
3553 CreateOfferWithMultipleAVMediaSections) {
3554 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003555 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3556 RtpTransceiverDirection::kSendRecv, kActive,
3557 &opts);
3558 AttachSenderToMediaDescriptionOptions(
3559 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003560
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003561 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3562 RtpTransceiverDirection::kSendRecv, kActive,
3563 &opts);
3564 AttachSenderToMediaDescriptionOptions(
3565 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003566
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003567 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3568 RtpTransceiverDirection::kSendRecv, kActive,
3569 &opts);
3570 AttachSenderToMediaDescriptionOptions(
3571 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003572
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003573 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3574 RtpTransceiverDirection::kSendRecv, kActive,
3575 &opts);
3576 AttachSenderToMediaDescriptionOptions(
3577 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003578 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003579 ASSERT_TRUE(offer);
3580
3581 ASSERT_EQ(4u, offer->contents().size());
3582 EXPECT_FALSE(offer->contents()[0].rejected);
3583 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003584 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003585 ASSERT_EQ(1u, acd->streams().size());
3586 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003587 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003588
3589 EXPECT_FALSE(offer->contents()[1].rejected);
3590 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003591 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003592 ASSERT_EQ(1u, vcd->streams().size());
3593 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003594 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003595
3596 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003597 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003598 ASSERT_EQ(1u, acd->streams().size());
3599 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003600 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003601
3602 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003603 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003604 ASSERT_EQ(1u, vcd->streams().size());
3605 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003606 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003607}
3608
3609// Test that we can create an answer with multiple media sections of same media
3610// type.
3611TEST_F(MediaSessionDescriptionFactoryTest,
3612 CreateAnswerWithMultipleAVMediaSections) {
3613 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003614 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3615 RtpTransceiverDirection::kSendRecv, kActive,
3616 &opts);
3617 AttachSenderToMediaDescriptionOptions(
3618 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003619
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003620 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3621 RtpTransceiverDirection::kSendRecv, kActive,
3622 &opts);
3623 AttachSenderToMediaDescriptionOptions(
3624 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003625
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003626 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3627 RtpTransceiverDirection::kSendRecv, kActive,
3628 &opts);
3629 AttachSenderToMediaDescriptionOptions(
3630 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003631
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003632 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3633 RtpTransceiverDirection::kSendRecv, kActive,
3634 &opts);
3635 AttachSenderToMediaDescriptionOptions(
3636 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003637
Steve Anton6fe1fba2018-12-11 10:15:23 -08003638 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003639 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003640 std::unique_ptr<SessionDescription> answer =
3641 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003642
3643 ASSERT_EQ(4u, answer->contents().size());
3644 EXPECT_FALSE(answer->contents()[0].rejected);
3645 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003646 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003647 ASSERT_EQ(1u, acd->streams().size());
3648 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003649 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003650
3651 EXPECT_FALSE(answer->contents()[1].rejected);
3652 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003653 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003654 ASSERT_EQ(1u, vcd->streams().size());
3655 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003656 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003657
3658 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003659 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003660 ASSERT_EQ(1u, acd->streams().size());
3661 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003662 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003663
3664 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003665 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003666 ASSERT_EQ(1u, vcd->streams().size());
3667 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003668 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003669}
3670
3671// Test that the media section will be rejected in offer if the corresponding
3672// MediaDescriptionOptions is stopped by the offerer.
3673TEST_F(MediaSessionDescriptionFactoryTest,
3674 CreateOfferWithMediaSectionStoppedByOfferer) {
3675 // Create an offer with two audio sections and one of them is stopped.
3676 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003677 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3678 RtpTransceiverDirection::kSendRecv, kActive,
3679 &offer_opts);
3680 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3681 RtpTransceiverDirection::kInactive, kStopped,
3682 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003683 std::unique_ptr<SessionDescription> offer =
3684 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003685 ASSERT_TRUE(offer);
3686 ASSERT_EQ(2u, offer->contents().size());
3687 EXPECT_FALSE(offer->contents()[0].rejected);
3688 EXPECT_TRUE(offer->contents()[1].rejected);
3689}
3690
3691// Test that the media section will be rejected in answer if the corresponding
3692// MediaDescriptionOptions is stopped by the offerer.
3693TEST_F(MediaSessionDescriptionFactoryTest,
3694 CreateAnswerWithMediaSectionStoppedByOfferer) {
3695 // Create an offer with two audio sections and one of them is stopped.
3696 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003697 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3698 RtpTransceiverDirection::kSendRecv, kActive,
3699 &offer_opts);
3700 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3701 RtpTransceiverDirection::kInactive, kStopped,
3702 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003703 std::unique_ptr<SessionDescription> offer =
3704 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003705 ASSERT_TRUE(offer);
3706 ASSERT_EQ(2u, offer->contents().size());
3707 EXPECT_FALSE(offer->contents()[0].rejected);
3708 EXPECT_TRUE(offer->contents()[1].rejected);
3709
3710 // Create an answer based on the offer.
3711 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003712 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3713 RtpTransceiverDirection::kSendRecv, kActive,
3714 &answer_opts);
3715 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3716 RtpTransceiverDirection::kSendRecv, kActive,
3717 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003718 std::unique_ptr<SessionDescription> answer =
3719 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003720 ASSERT_EQ(2u, answer->contents().size());
3721 EXPECT_FALSE(answer->contents()[0].rejected);
3722 EXPECT_TRUE(answer->contents()[1].rejected);
3723}
3724
3725// Test that the media section will be rejected in answer if the corresponding
3726// MediaDescriptionOptions is stopped by the answerer.
3727TEST_F(MediaSessionDescriptionFactoryTest,
3728 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3729 // Create an offer with two audio sections.
3730 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003731 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3732 RtpTransceiverDirection::kSendRecv, kActive,
3733 &offer_opts);
3734 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3735 RtpTransceiverDirection::kSendRecv, kActive,
3736 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003737 std::unique_ptr<SessionDescription> offer =
3738 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003739 ASSERT_TRUE(offer);
3740 ASSERT_EQ(2u, offer->contents().size());
3741 ASSERT_FALSE(offer->contents()[0].rejected);
3742 ASSERT_FALSE(offer->contents()[1].rejected);
3743
3744 // The answerer rejects one of the audio sections.
3745 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003746 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3747 RtpTransceiverDirection::kSendRecv, kActive,
3748 &answer_opts);
3749 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3750 RtpTransceiverDirection::kInactive, kStopped,
3751 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003752 std::unique_ptr<SessionDescription> answer =
3753 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003754 ASSERT_EQ(2u, answer->contents().size());
3755 EXPECT_FALSE(answer->contents()[0].rejected);
3756 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003757
3758 // The TransportInfo of the rejected m= section is expected to be added in the
3759 // answer.
3760 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003761}
3762
3763// Test the generated media sections has the same order of the
3764// corresponding MediaDescriptionOptions.
3765TEST_F(MediaSessionDescriptionFactoryTest,
3766 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3767 MediaSessionOptions opts;
3768 // This tests put video section first because normally audio comes first by
3769 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003770 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3771 RtpTransceiverDirection::kSendRecv, kActive,
3772 &opts);
3773 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3774 RtpTransceiverDirection::kSendRecv, kActive,
3775 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003776 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003777
3778 ASSERT_TRUE(offer);
3779 ASSERT_EQ(2u, offer->contents().size());
3780 EXPECT_EQ("video", offer->contents()[0].name);
3781 EXPECT_EQ("audio", offer->contents()[1].name);
3782}
3783
3784// Test that different media sections using the same codec have same payload
3785// type.
3786TEST_F(MediaSessionDescriptionFactoryTest,
3787 PayloadTypesSharedByMediaSectionsOfSameType) {
3788 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003789 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3790 RtpTransceiverDirection::kSendRecv, kActive,
3791 &opts);
3792 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3793 RtpTransceiverDirection::kSendRecv, kActive,
3794 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003795 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003796 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003797 ASSERT_TRUE(offer);
3798 ASSERT_EQ(2u, offer->contents().size());
3799 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003800 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003801 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003802 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003803 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3804 ASSERT_EQ(2u, vcd1->codecs().size());
3805 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3806 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3807 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3808 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3809
3810 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003811 std::unique_ptr<SessionDescription> answer =
3812 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003813 ASSERT_TRUE(answer);
3814 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003815 vcd1 = answer->contents()[0].media_description()->as_video();
3816 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003817 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3818 ASSERT_EQ(1u, vcd1->codecs().size());
3819 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3820 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3821}
3822
3823// Test that the codec preference order per media section is respected in
3824// subsequent offer.
3825TEST_F(MediaSessionDescriptionFactoryTest,
3826 CreateOfferRespectsCodecPreferenceOrder) {
3827 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003828 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3829 RtpTransceiverDirection::kSendRecv, kActive,
3830 &opts);
3831 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3832 RtpTransceiverDirection::kSendRecv, kActive,
3833 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003834 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003835 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003836 ASSERT_TRUE(offer);
3837 ASSERT_EQ(2u, offer->contents().size());
3838 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003839 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003840 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003841 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003842 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3843 EXPECT_EQ(video_codecs, vcd1->codecs());
3844 EXPECT_EQ(video_codecs, vcd2->codecs());
3845
3846 // Change the codec preference of the first video section and create a
3847 // follow-up offer.
3848 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3849 vcd1->set_codecs(video_codecs_reverse);
3850 std::unique_ptr<SessionDescription> updated_offer(
3851 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003852 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3853 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003854 // The video codec preference order should be respected.
3855 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3856 EXPECT_EQ(video_codecs, vcd2->codecs());
3857}
3858
3859// Test that the codec preference order per media section is respected in
3860// the answer.
3861TEST_F(MediaSessionDescriptionFactoryTest,
3862 CreateAnswerRespectsCodecPreferenceOrder) {
3863 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003864 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3865 RtpTransceiverDirection::kSendRecv, kActive,
3866 &opts);
3867 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3868 RtpTransceiverDirection::kSendRecv, kActive,
3869 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003870 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003871 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003872 ASSERT_TRUE(offer);
3873 ASSERT_EQ(2u, offer->contents().size());
3874 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003875 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003876 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003877 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003878 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3879 EXPECT_EQ(video_codecs, vcd1->codecs());
3880 EXPECT_EQ(video_codecs, vcd2->codecs());
3881
3882 // Change the codec preference of the first video section and create an
3883 // answer.
3884 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3885 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003886 std::unique_ptr<SessionDescription> answer =
3887 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003888 vcd1 = answer->contents()[0].media_description()->as_video();
3889 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003890 // The video codec preference order should be respected.
3891 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3892 EXPECT_EQ(video_codecs, vcd2->codecs());
3893}
3894
Zhi Huang6f367472017-11-22 13:20:02 -08003895// Test that when creating an answer, the codecs use local parameters instead of
3896// the remote ones.
3897TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3898 const std::string audio_param_name = "audio_param";
3899 const std::string audio_value1 = "audio_v1";
3900 const std::string audio_value2 = "audio_v2";
3901 const std::string video_param_name = "video_param";
3902 const std::string video_value1 = "video_v1";
3903 const std::string video_value2 = "video_v2";
3904
3905 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3906 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3907 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3908 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3909
3910 // Set the parameters for codecs.
3911 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3912 video_codecs1[0].SetParam(video_param_name, video_value1);
3913 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3914 video_codecs2[0].SetParam(video_param_name, video_value2);
3915
3916 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3917 f1_.set_video_codecs(video_codecs1);
3918 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3919 f2_.set_video_codecs(video_codecs2);
3920
3921 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003922 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3923 RtpTransceiverDirection::kSendRecv, kActive,
3924 &opts);
3925 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3926 RtpTransceiverDirection::kSendRecv, kActive,
3927 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003928
Steve Anton6fe1fba2018-12-11 10:15:23 -08003929 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003930 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003931 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3932 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003933 std::string value;
3934 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3935 EXPECT_EQ(audio_value1, value);
3936 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3937 EXPECT_EQ(video_value1, value);
3938
Steve Anton6fe1fba2018-12-11 10:15:23 -08003939 std::unique_ptr<SessionDescription> answer =
3940 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003941 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003942 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3943 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003944 // Use the parameters from the local codecs.
3945 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3946 EXPECT_EQ(audio_value2, value);
3947 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3948 EXPECT_EQ(video_value2, value);
3949}
3950
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003951// Test that matching packetization-mode is part of the criteria for matching
3952// H264 codecs (in addition to profile-level-id). Previously, this was not the
3953// case, so the first H264 codec with the same profile-level-id would match and
3954// the payload type in the answer would be incorrect.
3955// This is a regression test for bugs.webrtc.org/8808
3956TEST_F(MediaSessionDescriptionFactoryTest,
3957 H264MatchCriteriaIncludesPacketizationMode) {
3958 // Create two H264 codecs with the same profile level ID and different
3959 // packetization modes.
3960 VideoCodec h264_pm0(96, "H264");
3961 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3962 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3963 VideoCodec h264_pm1(97, "H264");
3964 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3965 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3966
3967 // Offerer will send both codecs, answerer should choose the one with matching
3968 // packetization mode (and not the first one it sees).
3969 f1_.set_video_codecs({h264_pm0, h264_pm1});
3970 f2_.set_video_codecs({h264_pm1});
3971
3972 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003973 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3974 RtpTransceiverDirection::kSendRecv, kActive,
3975 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003976
Steve Anton6fe1fba2018-12-11 10:15:23 -08003977 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003978 ASSERT_TRUE(offer);
3979
Steve Anton6fe1fba2018-12-11 10:15:23 -08003980 std::unique_ptr<SessionDescription> answer =
3981 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003982 ASSERT_TRUE(answer);
3983
3984 // Answer should have one negotiated codec with packetization-mode=1 using the
3985 // offered payload type.
3986 ASSERT_EQ(1u, answer->contents().size());
3987 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3988 ASSERT_EQ(1u, answer_vcd->codecs().size());
3989 auto answer_codec = answer_vcd->codecs()[0];
3990 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3991}
3992
zhihuangcf5b37c2016-05-05 11:44:35 -07003993class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3994 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08003995 MediaProtocolTest()
3996 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07003997 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3998 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003999 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
4000 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004001 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4002 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004003 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
4004 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
4005 f1_.set_secure(SEC_ENABLED);
4006 f2_.set_secure(SEC_ENABLED);
4007 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004008 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004009 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004010 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004011 tdf1_.set_secure(SEC_ENABLED);
4012 tdf2_.set_secure(SEC_ENABLED);
4013 }
4014
4015 protected:
4016 MediaSessionDescriptionFactory f1_;
4017 MediaSessionDescriptionFactory f2_;
4018 TransportDescriptionFactory tdf1_;
4019 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004020 UniqueRandomIdGenerator ssrc_generator1;
4021 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004022};
4023
4024TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4025 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004026 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004027 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004028 ASSERT_TRUE(offer.get() != nullptr);
4029 // Set the protocol for all the contents.
4030 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004031 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004032 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004033 std::unique_ptr<SessionDescription> answer =
4034 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004035 const ContentInfo* ac = answer->GetContentByName("audio");
4036 const ContentInfo* vc = answer->GetContentByName("video");
4037 ASSERT_TRUE(ac != nullptr);
4038 ASSERT_TRUE(vc != nullptr);
4039 EXPECT_FALSE(ac->rejected); // the offer is accepted
4040 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004041 const AudioContentDescription* acd = ac->media_description()->as_audio();
4042 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004043 EXPECT_EQ(GetParam(), acd->protocol());
4044 EXPECT_EQ(GetParam(), vcd->protocol());
4045}
4046
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004047INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4048 MediaProtocolTest,
4049 ::testing::ValuesIn(kMediaProtocols));
4050INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4051 MediaProtocolTest,
4052 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004053
4054TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4055 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004056 UniqueRandomIdGenerator ssrc_generator;
4057 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004058 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4059 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4060
4061 // The merged list of codecs should contain any send codecs that are also
4062 // nominally in the recieve codecs list. Payload types should be picked from
4063 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4064 // (set to 1). This equals what happens when the send codecs are used in an
4065 // offer and the receive codecs are used in the following answer.
4066 const std::vector<AudioCodec> sendrecv_codecs =
4067 MAKE_VECTOR(kAudioCodecsAnswer);
4068 const std::vector<AudioCodec> no_codecs;
4069
4070 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4071 << "Please don't change shared test data!";
4072 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4073 << "Please don't change shared test data!";
4074 // Alter iLBC send codec to have zero channels, to test that that is handled
4075 // properly.
4076 send_codecs[1].channels = 0;
4077
4078 // Alther iLBC receive codec to be lowercase, to test that case conversions
4079 // are handled properly.
4080 recv_codecs[2].name = "ilbc";
4081
4082 // Test proper merge
4083 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004084 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4085 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4086 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004087
4088 // Test empty send codecs list
4089 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004090 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4091 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4092 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004093
4094 // Test empty recv codecs list
4095 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004096 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4097 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4098 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004099
4100 // Test all empty codec lists
4101 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004102 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4103 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4104 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004105}
4106
Amit Hilbuch77938e62018-12-21 09:23:38 -08004107// Checks that the RID extensions are added to the video RTP header extensions.
4108// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4109// not very well defined, as calling set() and immediately get() will yield
4110// an object that is not semantically equivalent to the set object.
4111TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4112 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004113 UniqueRandomIdGenerator ssrc_generator;
4114 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004115 sf.set_is_unified_plan(true);
4116 cricket::RtpHeaderExtensions extensions;
4117 sf.set_video_rtp_header_extensions(extensions);
4118 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4119 // Check to see that RID extensions were added to the extension list
4120 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004121 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4122 RtpExtension::kRidUri)));
4123 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4124 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004125}
4126
4127// Checks that the RID extensions are added to the audio RTP header extensions.
4128// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4129// not very well defined, as calling set() and immediately get() will yield
4130// an object that is not semantically equivalent to the set object.
4131TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4132 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004133 UniqueRandomIdGenerator ssrc_generator;
4134 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004135 sf.set_is_unified_plan(true);
4136 cricket::RtpHeaderExtensions extensions;
4137 sf.set_audio_rtp_header_extensions(extensions);
4138 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4139 // Check to see that RID extensions were added to the extension list
4140 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004141 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4142 RtpExtension::kRidUri)));
4143 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4144 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004145}
4146
ossu075af922016-06-14 03:29:38 -07004147namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004148// Compare the two vectors of codecs ignoring the payload type.
4149template <class Codec>
4150bool CodecsMatch(const std::vector<Codec>& codecs1,
4151 const std::vector<Codec>& codecs2) {
4152 if (codecs1.size() != codecs2.size()) {
4153 return false;
4154 }
4155
4156 for (size_t i = 0; i < codecs1.size(); ++i) {
4157 if (!codecs1[i].Matches(codecs2[i])) {
4158 return false;
4159 }
4160 }
4161 return true;
4162}
4163
Steve Anton4e70a722017-11-28 14:57:10 -08004164void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004165 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004166 UniqueRandomIdGenerator ssrc_generator;
4167 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004168 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4169 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4170 const std::vector<AudioCodec> sendrecv_codecs =
4171 MAKE_VECTOR(kAudioCodecsAnswer);
4172 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004173
4174 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004175 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4176 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004177
Steve Anton4e70a722017-11-28 14:57:10 -08004178 if (direction == RtpTransceiverDirection::kSendRecv ||
4179 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004180 AttachSenderToMediaDescriptionOptions(
4181 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004182 }
ossu075af922016-06-14 03:29:38 -07004183
Steve Anton6fe1fba2018-12-11 10:15:23 -08004184 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004185 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004186 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004187
4188 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004189 // that the codecs put in are right. This happens when we neither want to
4190 // send nor receive audio. The checks are still in place if at some point
4191 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004192 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004193 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004194 // sendrecv and inactive should both present lists as if the channel was
4195 // to be used for sending and receiving. Inactive essentially means it
4196 // might eventually be used anything, but we don't know more at this
4197 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004198 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004199 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004200 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004201 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004202 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004203 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004204 }
4205 }
4206}
4207
4208static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004209 AudioCodec(0, "codec0", 16000, -1, 1),
4210 AudioCodec(1, "codec1", 8000, 13300, 1),
4211 AudioCodec(2, "codec2", 8000, 64000, 1),
4212 AudioCodec(3, "codec3", 8000, 64000, 1),
4213 AudioCodec(4, "codec4", 8000, 0, 2),
4214 AudioCodec(5, "codec5", 32000, 0, 1),
4215 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004216
zhihuang1c378ed2017-08-17 14:10:50 -07004217/* The codecs groups below are chosen as per the matrix below. The objective
4218 * is to have different sets of codecs in the inputs, to get unique sets of
4219 * codecs after negotiation, depending on offer and answer communication
4220 * directions. One-way directions in the offer should either result in the
4221 * opposite direction in the answer, or an inactive answer. Regardless, the
4222 * choice of codecs should be as if the answer contained the opposite
4223 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004224 *
4225 * | Offer | Answer | Result
4226 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4227 * 0 | x - - | - x - | x - - - -
4228 * 1 | x x x | - x - | x - - x -
4229 * 2 | - x - | x - - | - x - - -
4230 * 3 | x x x | x - - | - x x - -
4231 * 4 | - x - | x x x | - x - - -
4232 * 5 | x - - | x x x | x - - - -
4233 * 6 | x x x | x x x | x x x x x
4234 */
4235// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004236static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4237static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004238// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4239// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004240static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4241static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004242// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004243static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4244static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4245static const int kResultSendrecv_SendCodecs[] = {3, 6};
4246static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4247static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004248
4249template <typename T, int IDXS>
4250std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4251 std::vector<T> out;
4252 out.reserve(IDXS);
4253 for (int idx : indices)
4254 out.push_back(array[idx]);
4255
4256 return out;
4257}
4258
Steve Anton4e70a722017-11-28 14:57:10 -08004259void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4260 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004261 bool add_legacy_stream) {
4262 TransportDescriptionFactory offer_tdf;
4263 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004264 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4265 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4266 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004267 offer_factory.set_audio_codecs(
4268 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4269 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4270 answer_factory.set_audio_codecs(
4271 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4272 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4273
ossu075af922016-06-14 03:29:38 -07004274 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004275 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4276 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004277
Steve Anton4e70a722017-11-28 14:57:10 -08004278 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004279 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4280 kAudioTrack1, {kMediaStream1}, 1,
4281 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004282 }
4283
Steve Anton6fe1fba2018-12-11 10:15:23 -08004284 std::unique_ptr<SessionDescription> offer =
4285 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004286 ASSERT_TRUE(offer.get() != NULL);
4287
4288 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004289 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4290 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004291
Steve Anton4e70a722017-11-28 14:57:10 -08004292 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004293 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4294 kAudioTrack1, {kMediaStream1}, 1,
4295 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004296 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004297 std::unique_ptr<SessionDescription> answer =
4298 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004299 const ContentInfo* ac = answer->GetContentByName("audio");
4300
zhihuang1c378ed2017-08-17 14:10:50 -07004301 // If the factory didn't add any audio content to the answer, we cannot
4302 // check that the codecs put in are right. This happens when we neither want
4303 // to send nor receive audio. The checks are still in place if at some point
4304 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004305 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004306 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4307 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004308
ossu075af922016-06-14 03:29:38 -07004309 std::vector<AudioCodec> target_codecs;
4310 // For offers with sendrecv or inactive, we should never reply with more
4311 // codecs than offered, with these codec sets.
4312 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004313 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004314 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4315 kResultSendrecv_SendrecvCodecs);
4316 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004317 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004318 target_codecs =
4319 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004320 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004321 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004322 target_codecs =
4323 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004324 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004325 case RtpTransceiverDirection::kSendRecv:
4326 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004327 target_codecs =
4328 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004329 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004330 target_codecs =
4331 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004332 } else {
4333 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4334 kResultSendrecv_SendrecvCodecs);
4335 }
4336 break;
4337 }
4338
zhihuang1c378ed2017-08-17 14:10:50 -07004339 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004340 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004341 bool first = true;
4342 os << "{";
4343 for (const auto& c : codecs) {
4344 os << (first ? " " : ", ") << c.id;
4345 first = false;
4346 }
4347 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004348 return os.Release();
ossu075af922016-06-14 03:29:38 -07004349 };
4350
4351 EXPECT_TRUE(acd->codecs() == target_codecs)
4352 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004353 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4354 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004355 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004356 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4357 << "; got: "
4358 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004359 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004360 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004361 << "Only inactive offers are allowed to not generate any audio "
4362 "content";
ossu075af922016-06-14 03:29:38 -07004363 }
4364}
brandtr03d5fb12016-11-22 03:37:59 -08004365
4366} // namespace
ossu075af922016-06-14 03:29:38 -07004367
4368class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004369 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004370
4371TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004372 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004373}
4374
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004375INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4376 AudioCodecsOfferTest,
4377 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4378 RtpTransceiverDirection::kRecvOnly,
4379 RtpTransceiverDirection::kSendRecv,
4380 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004381
4382class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004383 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4384 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004385 bool>> {};
ossu075af922016-06-14 03:29:38 -07004386
4387TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004388 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4389 ::testing::get<1>(GetParam()),
4390 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004391}
4392
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004393INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004394 MediaSessionDescriptionFactoryTest,
4395 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004396 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4397 RtpTransceiverDirection::kRecvOnly,
4398 RtpTransceiverDirection::kSendRecv,
4399 RtpTransceiverDirection::kInactive),
4400 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4401 RtpTransceiverDirection::kRecvOnly,
4402 RtpTransceiverDirection::kSendRecv,
4403 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004404 ::testing::Bool()));