blob: 534e4fc8391c6f5dbd9519de9d60e49541681358 [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;
269 for (const auto& codec : codecs) {
270 codec_names.push_back(codec.name);
271 }
272 return codec_names;
273}
274
zhihuang1c378ed2017-08-17 14:10:50 -0700275// This is used for test only. MIDs are not the identification of the
276// MediaDescriptionOptions since some end points may not support MID and the SDP
277// may not contain 'mid'.
278std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
279 const std::string& mid,
280 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800281 return absl::c_find_if(
282 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700283 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
284}
285
286std::vector<MediaDescriptionOptions>::const_iterator
287FindFirstMediaDescriptionByMid(const std::string& mid,
288 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800289 return absl::c_find_if(
290 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700291 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700292}
293
294// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800295static void AddMediaDescriptionOptions(MediaType type,
296 const std::string& mid,
297 RtpTransceiverDirection direction,
298 bool stopped,
299 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800300 opts->media_description_options.push_back(
301 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700302}
303
Steve Anton4e70a722017-11-28 14:57:10 -0800304static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700305 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800306 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
307 opts);
308 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
309 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700310}
311
312static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800313 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700314 MediaSessionOptions* opts) {
315 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800316 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700317}
318
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800319static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700320 const std::string& mid,
321 MediaType type,
322 const std::string& track_id,
323 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800324 const std::vector<RidDescription>& rids,
325 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700326 int num_sim_layer,
327 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700328 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
329 switch (type) {
330 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700331 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700332 break;
333 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800334 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
335 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700336 break;
337 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700338 RTC_CHECK(stream_ids.size() == 1U);
339 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700340 break;
341 default:
342 RTC_NOTREACHED();
343 }
344}
345
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800346static void AttachSenderToMediaDescriptionOptions(
347 const std::string& mid,
348 MediaType type,
349 const std::string& track_id,
350 const std::vector<std::string>& stream_ids,
351 int num_sim_layer,
352 MediaSessionOptions* session_options) {
353 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
354 SimulcastLayerList(), num_sim_layer,
355 session_options);
356}
357
zhihuang1c378ed2017-08-17 14:10:50 -0700358static void DetachSenderFromMediaSection(const std::string& mid,
359 const std::string& track_id,
360 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700361 std::vector<cricket::SenderOptions>& sender_options_list =
362 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
363 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800364 absl::c_find_if(sender_options_list,
365 [track_id](const cricket::SenderOptions& sender_options) {
366 return sender_options.track_id == track_id;
367 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700368 RTC_DCHECK(sender_it != sender_options_list.end());
369 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700370}
371
372// Helper function used to create a default MediaSessionOptions for Plan B SDP.
373// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
374static MediaSessionOptions CreatePlanBMediaSessionOptions() {
375 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800376 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
377 RtpTransceiverDirection::kRecvOnly, kActive,
378 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700379 return session_options;
380}
381
382// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
383// was designed for Plan B SDP, where only one audio "m=" section and one video
384// "m=" section could be generated, and ordering couldn't be controlled. Many of
385// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386class MediaSessionDescriptionFactoryTest : public testing::Test {
387 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800388 MediaSessionDescriptionFactoryTest()
389 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700390 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
391 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000392 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
393 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700394 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
395 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
397 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200398 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700399 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200400 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700401 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000402 }
403
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000404 // Create a video StreamParamsVec object with:
405 // - one video stream with 3 simulcast streams and FEC,
406 StreamParamsVec CreateComplexVideoStreamParamsVec() {
407 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
408 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
409 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
410 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
411
412 std::vector<SsrcGroup> ssrc_groups;
413 ssrc_groups.push_back(sim_group);
414 ssrc_groups.push_back(fec_group1);
415 ssrc_groups.push_back(fec_group2);
416 ssrc_groups.push_back(fec_group3);
417
418 StreamParams simulcast_params;
419 simulcast_params.id = kVideoTrack1;
420 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
421 simulcast_params.ssrc_groups = ssrc_groups;
422 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800423 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000424
425 StreamParamsVec video_streams;
426 video_streams.push_back(simulcast_params);
427
428 return video_streams;
429 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430
431 bool CompareCryptoParams(const CryptoParamsVec& c1,
432 const CryptoParamsVec& c2) {
433 if (c1.size() != c2.size())
434 return false;
435 for (size_t i = 0; i < c1.size(); ++i)
436 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
437 c1[i].key_params != c2[i].key_params ||
438 c1[i].session_params != c2[i].session_params)
439 return false;
440 return true;
441 }
442
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700443 // Returns true if the transport info contains "renomination" as an
444 // ICE option.
445 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800446 return absl::c_linear_search(transport_info->description.transport_options,
447 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700448 }
449
zhihuang1c378ed2017-08-17 14:10:50 -0700450 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700451 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452 bool has_current_desc) {
453 const std::string current_audio_ufrag = "current_audio_ufrag";
454 const std::string current_audio_pwd = "current_audio_pwd";
455 const std::string current_video_ufrag = "current_video_ufrag";
456 const std::string current_video_pwd = "current_video_pwd";
457 const std::string current_data_ufrag = "current_data_ufrag";
458 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800459 std::unique_ptr<SessionDescription> current_desc;
460 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800462 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800463 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200464 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800465 TransportDescription(current_audio_ufrag, current_audio_pwd)));
466 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200467 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800468 TransportDescription(current_video_ufrag, current_video_pwd)));
469 current_desc->AddTransportInfo(TransportInfo(
470 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 }
472 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800473 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474 } else {
kwiberg31022942016-03-11 14:18:21 -0800475 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800476 offer = f1_.CreateOffer(options, NULL);
477 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000478 }
479 ASSERT_TRUE(desc.get() != NULL);
480 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000481 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000482 EXPECT_TRUE(ti_audio != NULL);
483 if (has_current_desc) {
484 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
485 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
486 } else {
487 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
488 ti_audio->description.ice_ufrag.size());
489 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
490 ti_audio->description.ice_pwd.size());
491 }
zhihuang1c378ed2017-08-17 14:10:50 -0700492 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700493 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700494 EXPECT_EQ(
495 media_desc_options_it->transport_options.enable_ice_renomination,
496 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497
498 } else {
499 EXPECT_TRUE(ti_audio == NULL);
500 }
501 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000502 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000503 EXPECT_TRUE(ti_video != NULL);
504 if (options.bundle_enabled) {
505 EXPECT_EQ(ti_audio->description.ice_ufrag,
506 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200507 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508 } else {
509 if (has_current_desc) {
510 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
511 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
512 } else {
513 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
514 ti_video->description.ice_ufrag.size());
515 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
516 ti_video->description.ice_pwd.size());
517 }
518 }
zhihuang1c378ed2017-08-17 14:10:50 -0700519 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700520 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700521 EXPECT_EQ(
522 media_desc_options_it->transport_options.enable_ice_renomination,
523 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000524 } else {
525 EXPECT_TRUE(ti_video == NULL);
526 }
527 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
528 if (options.has_data()) {
529 EXPECT_TRUE(ti_data != NULL);
530 if (options.bundle_enabled) {
531 EXPECT_EQ(ti_audio->description.ice_ufrag,
532 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200533 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 } else {
535 if (has_current_desc) {
536 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
537 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
538 } else {
539 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
540 ti_data->description.ice_ufrag.size());
541 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
542 ti_data->description.ice_pwd.size());
543 }
544 }
zhihuang1c378ed2017-08-17 14:10:50 -0700545 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700546 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700547 EXPECT_EQ(
548 media_desc_options_it->transport_options.enable_ice_renomination,
549 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700550
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000551 } else {
552 EXPECT_TRUE(ti_video == NULL);
553 }
554 }
555
556 void TestCryptoWithBundle(bool offer) {
557 f1_.set_secure(SEC_ENABLED);
558 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800559 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
560 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
561 &options);
kwiberg31022942016-03-11 14:18:21 -0800562 std::unique_ptr<SessionDescription> ref_desc;
563 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 if (offer) {
565 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800566 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800568 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 } else {
570 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800571 ref_desc = f1_.CreateOffer(options, NULL);
572 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800574 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800576 desc->GetContentDescriptionByName("audio");
577 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800579 desc->GetContentDescriptionByName("video");
580 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
582 video_media_desc->cryptos()));
583 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800584 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 audio_media_desc->cryptos()[0].cipher_suite);
586
587 // Verify the selected crypto is one from the reference audio
588 // media content.
589 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800590 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 bool found = false;
592 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
593 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200594 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 found = true;
596 break;
597 }
598 }
599 EXPECT_TRUE(found);
600 }
601
602 // This test that the audio and video media direction is set to
603 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700604 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800606 RtpTransceiverDirection direction_in_offer,
607 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700608 MediaSessionOptions offer_opts;
609 AddAudioVideoSections(direction_in_offer, &offer_opts);
610
Steve Anton6fe1fba2018-12-11 10:15:23 -0800611 std::unique_ptr<SessionDescription> offer =
612 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700614 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700616 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000618
zhihuang1c378ed2017-08-17 14:10:50 -0700619 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800620 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800621 std::unique_ptr<SessionDescription> answer =
622 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 const AudioContentDescription* acd_answer =
624 GetFirstAudioContentDescription(answer.get());
625 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
626 const VideoContentDescription* vcd_answer =
627 GetFirstVideoContentDescription(answer.get());
628 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
629 }
630
631 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800632 RTC_DCHECK(content);
633 RTC_CHECK(content->media_description());
634 const cricket::AudioContentDescription* audio_desc =
635 content->media_description()->as_audio();
636 RTC_CHECK(audio_desc);
637 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
638 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800640 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 }
642 return true;
643 }
644
jbauchcb560652016-08-04 05:20:32 -0700645 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
646 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800647 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700648 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700649
jbauchcb560652016-08-04 05:20:32 -0700650 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800651 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700652 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700653
jbauchcb560652016-08-04 05:20:32 -0700654 f1_.set_secure(SEC_ENABLED);
655 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800656 std::unique_ptr<SessionDescription> offer =
657 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700658 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800659 std::unique_ptr<SessionDescription> answer =
660 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700661 const ContentInfo* ac = answer->GetContentByName("audio");
662 const ContentInfo* vc = answer->GetContentByName("video");
663 ASSERT_TRUE(ac != NULL);
664 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800665 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
666 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800667 const AudioContentDescription* acd = ac->media_description()->as_audio();
668 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700669 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800670 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700671 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700672 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700673 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
674 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700675 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700676 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700677 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700678 }
679 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800680 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200681 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
682 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700683 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700684 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700685 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700686 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700687 }
Steve Antone38a5a12018-11-21 16:05:15 -0800688 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700689 }
690
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000691 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800692 UniqueRandomIdGenerator ssrc_generator1;
693 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 MediaSessionDescriptionFactory f1_;
695 MediaSessionDescriptionFactory f2_;
696 TransportDescriptionFactory tdf1_;
697 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698};
699
700// Create a typical audio offer, and ensure it matches what we expect.
701TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
702 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800703 std::unique_ptr<SessionDescription> offer =
704 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000705 ASSERT_TRUE(offer.get() != NULL);
706 const ContentInfo* ac = offer->GetContentByName("audio");
707 const ContentInfo* vc = offer->GetContentByName("video");
708 ASSERT_TRUE(ac != NULL);
709 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800710 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800711 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000712 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700713 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700714 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000715 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
716 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700717 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800718 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000719}
720
721// Create a typical video offer, and ensure it matches what we expect.
722TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
723 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800724 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000725 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800726 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 ASSERT_TRUE(offer.get() != NULL);
728 const ContentInfo* ac = offer->GetContentByName("audio");
729 const ContentInfo* vc = offer->GetContentByName("video");
730 ASSERT_TRUE(ac != NULL);
731 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800732 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
733 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800734 const AudioContentDescription* acd = ac->media_description()->as_audio();
735 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700737 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700738 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
740 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700741 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800742 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000743 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
744 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700745 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
747 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700748 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800749 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750}
751
752// Test creating an offer with bundle where the Codecs have the same dynamic
753// RTP playlod type. The test verifies that the offer don't contain the
754// duplicate RTP payload types.
755TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
756 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700757 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
759 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
760 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
761
762 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800763 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
764 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000765 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800766 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 const VideoContentDescription* vcd =
768 GetFirstVideoContentDescription(offer.get());
769 const AudioContentDescription* acd =
770 GetFirstAudioContentDescription(offer.get());
771 const DataContentDescription* dcd =
772 GetFirstDataContentDescription(offer.get());
773 ASSERT_TRUE(NULL != vcd);
774 ASSERT_TRUE(NULL != acd);
775 ASSERT_TRUE(NULL != dcd);
776 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
777 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
778 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
779 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
780 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
781 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
782}
783
zhihuang1c378ed2017-08-17 14:10:50 -0700784// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785// after an audio only session has been negotiated.
786TEST_F(MediaSessionDescriptionFactoryTest,
787 TestCreateUpdatedVideoOfferWithBundle) {
788 f1_.set_secure(SEC_ENABLED);
789 f2_.set_secure(SEC_ENABLED);
790 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800791 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
792 RtpTransceiverDirection::kRecvOnly, kActive,
793 &opts);
794 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
795 RtpTransceiverDirection::kInactive, kStopped,
796 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 opts.data_channel_type = cricket::DCT_NONE;
798 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800799 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
800 std::unique_ptr<SessionDescription> answer =
801 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802
803 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800804 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
805 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
806 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800808 std::unique_ptr<SessionDescription> updated_offer(
809 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810
811 const AudioContentDescription* acd =
812 GetFirstAudioContentDescription(updated_offer.get());
813 const VideoContentDescription* vcd =
814 GetFirstVideoContentDescription(updated_offer.get());
815 const DataContentDescription* dcd =
816 GetFirstDataContentDescription(updated_offer.get());
817 EXPECT_TRUE(NULL != vcd);
818 EXPECT_TRUE(NULL != acd);
819 EXPECT_TRUE(NULL != dcd);
820
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700821 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800822 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700823 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800824 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700825 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800826 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827}
deadbeef44f08192015-12-15 16:20:09 -0800828
wu@webrtc.org78187522013-10-07 23:32:02 +0000829// Create a RTP data offer, and ensure it matches what we expect.
830TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800832 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
833 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800835 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836 ASSERT_TRUE(offer.get() != NULL);
837 const ContentInfo* ac = offer->GetContentByName("audio");
838 const ContentInfo* dc = offer->GetContentByName("data");
839 ASSERT_TRUE(ac != NULL);
840 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800841 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
842 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800843 const AudioContentDescription* acd = ac->media_description()->as_audio();
844 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700846 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700847 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
849 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700850 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800851 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
853 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700854 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200856 dcd->bandwidth()); // default bandwidth (auto)
857 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700858 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800859 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860}
861
wu@webrtc.org78187522013-10-07 23:32:02 +0000862// Create an SCTP data offer with bundle without error.
863TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
864 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000865 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800866 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000867 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800868 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000869 EXPECT_TRUE(offer.get() != NULL);
870 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
871}
872
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000873// Test creating an sctp data channel from an already generated offer.
874TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
875 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000876 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800877 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000878 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800879 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000880 ASSERT_TRUE(offer1.get() != NULL);
881 const ContentInfo* data = offer1->GetContentByName("data");
882 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800883 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000884
885 // Now set data_channel_type to 'none' (default) and make sure that the
886 // datachannel type that gets generated from the previous offer, is of the
887 // same type.
888 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800889 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000890 f1_.CreateOffer(opts, offer1.get()));
891 data = offer2->GetContentByName("data");
892 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800893 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000894}
895
Steve Anton2bed3972019-01-04 17:04:30 -0800896// Test that if BUNDLE is enabled and all media sections are rejected then the
897// BUNDLE group is not present in the re-offer.
898TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
899 MediaSessionOptions opts;
900 opts.bundle_enabled = true;
901 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
902 RtpTransceiverDirection::kSendRecv, kActive,
903 &opts);
904 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
905
906 opts.media_description_options[0].stopped = true;
907 std::unique_ptr<SessionDescription> reoffer =
908 f1_.CreateOffer(opts, offer.get());
909
910 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
911}
912
913// Test that if BUNDLE is enabled and the remote re-offer does not include a
914// BUNDLE group since all media sections are rejected, then the re-answer also
915// does not include a BUNDLE group.
916TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
917 MediaSessionOptions opts;
918 opts.bundle_enabled = true;
919 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
920 RtpTransceiverDirection::kSendRecv, kActive,
921 &opts);
922 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
923 std::unique_ptr<SessionDescription> answer =
924 f2_.CreateAnswer(offer.get(), opts, nullptr);
925
926 opts.media_description_options[0].stopped = true;
927 std::unique_ptr<SessionDescription> reoffer =
928 f1_.CreateOffer(opts, offer.get());
929 std::unique_ptr<SessionDescription> reanswer =
930 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
931
932 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
933}
934
935// Test that if BUNDLE is enabled and the previous offerer-tagged media section
936// was rejected then the new offerer-tagged media section is the non-rejected
937// media section.
938TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
939 MediaSessionOptions opts;
940 opts.bundle_enabled = true;
941 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
942 RtpTransceiverDirection::kSendRecv, kActive,
943 &opts);
944 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
945
946 // Reject the audio m= section and add a video m= section.
947 opts.media_description_options[0].stopped = true;
948 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
949 RtpTransceiverDirection::kSendRecv, kActive,
950 &opts);
951 std::unique_ptr<SessionDescription> reoffer =
952 f1_.CreateOffer(opts, offer.get());
953
954 const cricket::ContentGroup* bundle_group =
955 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
956 ASSERT_TRUE(bundle_group);
957 EXPECT_FALSE(bundle_group->HasContentName("audio"));
958 EXPECT_TRUE(bundle_group->HasContentName("video"));
959}
960
961// Test that if BUNDLE is enabled and the previous offerer-tagged media section
962// was rejected and a new media section is added, then the re-answer BUNDLE
963// group will contain only the non-rejected media section.
964TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
965 MediaSessionOptions opts;
966 opts.bundle_enabled = true;
967 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
968 RtpTransceiverDirection::kSendRecv, kActive,
969 &opts);
970 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
971 std::unique_ptr<SessionDescription> answer =
972 f2_.CreateAnswer(offer.get(), opts, nullptr);
973
974 // Reject the audio m= section and add a video m= section.
975 opts.media_description_options[0].stopped = true;
976 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
977 RtpTransceiverDirection::kSendRecv, kActive,
978 &opts);
979 std::unique_ptr<SessionDescription> reoffer =
980 f1_.CreateOffer(opts, offer.get());
981 std::unique_ptr<SessionDescription> reanswer =
982 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
983
984 const cricket::ContentGroup* bundle_group =
985 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
986 ASSERT_TRUE(bundle_group);
987 EXPECT_FALSE(bundle_group->HasContentName("audio"));
988 EXPECT_TRUE(bundle_group->HasContentName("video"));
989}
990
991// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
992// and there is still a non-rejected media section that was in the initial
993// offer, then the ICE credentials do not change in the reoffer offerer-tagged
994// media section.
995TEST_F(MediaSessionDescriptionFactoryTest,
996 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
997 MediaSessionOptions opts;
998 opts.bundle_enabled = true;
999 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1000 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1001 std::unique_ptr<SessionDescription> answer =
1002 f2_.CreateAnswer(offer.get(), opts, nullptr);
1003
1004 // Reject the audio m= section.
1005 opts.media_description_options[0].stopped = true;
1006 std::unique_ptr<SessionDescription> reoffer =
1007 f1_.CreateOffer(opts, offer.get());
1008
1009 const TransportDescription* offer_tagged =
1010 offer->GetTransportDescriptionByName("audio");
1011 ASSERT_TRUE(offer_tagged);
1012 const TransportDescription* reoffer_tagged =
1013 reoffer->GetTransportDescriptionByName("video");
1014 ASSERT_TRUE(reoffer_tagged);
1015 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1016 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1017}
1018
1019// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1020// and there is still a non-rejected media section that was in the initial
1021// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1022// media section.
1023TEST_F(MediaSessionDescriptionFactoryTest,
1024 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1025 MediaSessionOptions opts;
1026 opts.bundle_enabled = true;
1027 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1028 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1029 std::unique_ptr<SessionDescription> answer =
1030 f2_.CreateAnswer(offer.get(), opts, nullptr);
1031
1032 // Reject the audio m= section.
1033 opts.media_description_options[0].stopped = true;
1034 std::unique_ptr<SessionDescription> reoffer =
1035 f1_.CreateOffer(opts, offer.get());
1036 std::unique_ptr<SessionDescription> reanswer =
1037 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1038
1039 const TransportDescription* answer_tagged =
1040 answer->GetTransportDescriptionByName("audio");
1041 ASSERT_TRUE(answer_tagged);
1042 const TransportDescription* reanswer_tagged =
1043 reanswer->GetTransportDescriptionByName("video");
1044 ASSERT_TRUE(reanswer_tagged);
1045 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1046 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1047}
1048
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049// Create an audio, video offer without legacy StreamParams.
1050TEST_F(MediaSessionDescriptionFactoryTest,
1051 TestCreateOfferWithoutLegacyStreams) {
1052 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001053 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001054 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055 ASSERT_TRUE(offer.get() != NULL);
1056 const ContentInfo* ac = offer->GetContentByName("audio");
1057 const ContentInfo* vc = offer->GetContentByName("video");
1058 ASSERT_TRUE(ac != NULL);
1059 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001060 const AudioContentDescription* acd = ac->media_description()->as_audio();
1061 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062
Yves Gerey665174f2018-06-19 15:03:05 +02001063 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1064 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001065}
1066
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001067// Creates an audio+video sendonly offer.
1068TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001069 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001070 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001071 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1072 {kMediaStream1}, 1, &opts);
1073 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1074 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001075
Steve Anton6fe1fba2018-12-11 10:15:23 -08001076 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001077 ASSERT_TRUE(offer.get() != NULL);
1078 EXPECT_EQ(2u, offer->contents().size());
1079 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1080 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1081
Steve Anton4e70a722017-11-28 14:57:10 -08001082 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1083 GetMediaDirection(&offer->contents()[0]));
1084 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1085 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001086}
1087
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001088// Verifies that the order of the media contents in the current
1089// SessionDescription is preserved in the new SessionDescription.
1090TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1091 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001092 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001093
kwiberg31022942016-03-11 14:18:21 -08001094 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001095 ASSERT_TRUE(offer1.get() != NULL);
1096 EXPECT_EQ(1u, offer1->contents().size());
1097 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1098
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001099 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1100 RtpTransceiverDirection::kRecvOnly, kActive,
1101 &opts);
kwiberg31022942016-03-11 14:18:21 -08001102 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001103 f1_.CreateOffer(opts, offer1.get()));
1104 ASSERT_TRUE(offer2.get() != NULL);
1105 EXPECT_EQ(2u, offer2->contents().size());
1106 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1107 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1108
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001109 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1110 RtpTransceiverDirection::kRecvOnly, kActive,
1111 &opts);
kwiberg31022942016-03-11 14:18:21 -08001112 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001113 f1_.CreateOffer(opts, offer2.get()));
1114 ASSERT_TRUE(offer3.get() != NULL);
1115 EXPECT_EQ(3u, offer3->contents().size());
1116 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1117 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1118 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001119}
1120
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001121// Create a typical audio answer, and ensure it matches what we expect.
1122TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1123 f1_.set_secure(SEC_ENABLED);
1124 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001125 std::unique_ptr<SessionDescription> offer =
1126 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001127 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001128 std::unique_ptr<SessionDescription> answer =
1129 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001130 const ContentInfo* ac = answer->GetContentByName("audio");
1131 const ContentInfo* vc = answer->GetContentByName("video");
1132 ASSERT_TRUE(ac != NULL);
1133 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001134 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001135 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001136 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001137 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001138 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001139 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1140 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001141 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001142 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143}
1144
jbauchcb560652016-08-04 05:20:32 -07001145// Create a typical audio answer with GCM ciphers enabled, and ensure it
1146// matches what we expect.
1147TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1148 f1_.set_secure(SEC_ENABLED);
1149 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001150 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001151 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001152 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001153 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001154 std::unique_ptr<SessionDescription> answer =
1155 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001156 const ContentInfo* ac = answer->GetContentByName("audio");
1157 const ContentInfo* vc = answer->GetContentByName("video");
1158 ASSERT_TRUE(ac != NULL);
1159 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001160 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001161 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001162 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001163 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001164 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001165 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1166 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001167 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001168 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001169}
1170
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001171// Create a typical video answer, and ensure it matches what we expect.
1172TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1173 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001174 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175 f1_.set_secure(SEC_ENABLED);
1176 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001177 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001179 std::unique_ptr<SessionDescription> answer =
1180 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181 const ContentInfo* ac = answer->GetContentByName("audio");
1182 const ContentInfo* vc = answer->GetContentByName("video");
1183 ASSERT_TRUE(ac != NULL);
1184 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001185 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1186 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001187 const AudioContentDescription* acd = ac->media_description()->as_audio();
1188 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001190 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001192 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001193 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001194 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001196 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001197 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1198 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001199 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001200 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001201}
1202
jbauchcb560652016-08-04 05:20:32 -07001203// Create a typical video answer with GCM ciphers enabled, and ensure it
1204// matches what we expect.
1205TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1206 TestVideoGcmCipher(true, true);
1207}
1208
1209// Create a typical video answer with GCM ciphers enabled for the offer only,
1210// and ensure it matches what we expect.
1211TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1212 TestVideoGcmCipher(true, false);
1213}
1214
1215// Create a typical video answer with GCM ciphers enabled for the answer only,
1216// and ensure it matches what we expect.
1217TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1218 TestVideoGcmCipher(false, true);
1219}
1220
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001222 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001223 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224 f1_.set_secure(SEC_ENABLED);
1225 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001226 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001228 std::unique_ptr<SessionDescription> answer =
1229 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001230 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001231 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001232 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001233 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001234 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1235 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001236 const AudioContentDescription* acd = ac->media_description()->as_audio();
1237 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001239 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001241 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001243 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001244 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001245 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001246 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001247 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001248 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001249 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250}
1251
jbauchcb560652016-08-04 05:20:32 -07001252TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001253 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001254 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001255 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001256 f1_.set_secure(SEC_ENABLED);
1257 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001258 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001259 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001260 std::unique_ptr<SessionDescription> answer =
1261 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001262 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001263 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001264 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001265 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001266 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1267 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001268 const AudioContentDescription* acd = ac->media_description()->as_audio();
1269 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001270 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001271 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001272 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001273 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001274 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001275 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001276 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001277 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001278 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001279 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001280 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001281 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001282}
1283
1284// The use_sctpmap flag should be set in a DataContentDescription by default.
1285// The answer's use_sctpmap flag should match the offer's.
1286TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1287 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001288 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001289 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001290 ASSERT_TRUE(offer.get() != NULL);
1291 ContentInfo* dc_offer = offer->GetContentByName("data");
1292 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001293 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001294 EXPECT_TRUE(dcd_offer->use_sctpmap());
1295
Steve Anton6fe1fba2018-12-11 10:15:23 -08001296 std::unique_ptr<SessionDescription> answer =
1297 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001298 const ContentInfo* dc_answer = answer->GetContentByName("data");
1299 ASSERT_TRUE(dc_answer != NULL);
1300 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001301 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001302 EXPECT_TRUE(dcd_answer->use_sctpmap());
1303}
1304
1305// The answer's use_sctpmap flag should match the offer's.
1306TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1307 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001308 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001309 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001310 ASSERT_TRUE(offer.get() != NULL);
1311 ContentInfo* dc_offer = offer->GetContentByName("data");
1312 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001313 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001314 dcd_offer->set_use_sctpmap(false);
1315
Steve Anton6fe1fba2018-12-11 10:15:23 -08001316 std::unique_ptr<SessionDescription> answer =
1317 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001318 const ContentInfo* dc_answer = answer->GetContentByName("data");
1319 ASSERT_TRUE(dc_answer != NULL);
1320 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001321 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001322 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001323}
1324
deadbeef8b7e9ad2017-05-25 09:38:55 -07001325// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1326// and "TCP/DTLS/SCTP" offers.
1327TEST_F(MediaSessionDescriptionFactoryTest,
1328 TestCreateDataAnswerToDifferentOfferedProtos) {
1329 // Need to enable DTLS offer/answer generation (disabled by default in this
1330 // test).
1331 f1_.set_secure(SEC_ENABLED);
1332 f2_.set_secure(SEC_ENABLED);
1333 tdf1_.set_secure(SEC_ENABLED);
1334 tdf2_.set_secure(SEC_ENABLED);
1335
1336 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001337 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001338 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001339 ASSERT_TRUE(offer.get() != nullptr);
1340 ContentInfo* dc_offer = offer->GetContentByName("data");
1341 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001342 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001343
1344 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1345 "TCP/DTLS/SCTP"};
1346 for (const std::string& proto : protos) {
1347 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001348 std::unique_ptr<SessionDescription> answer =
1349 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001350 const ContentInfo* dc_answer = answer->GetContentByName("data");
1351 ASSERT_TRUE(dc_answer != nullptr);
1352 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001353 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001354 EXPECT_FALSE(dc_answer->rejected);
1355 EXPECT_EQ(proto, dcd_answer->protocol());
1356 }
1357}
1358
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001359// Verifies that the order of the media contents in the offer is preserved in
1360// the answer.
1361TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1362 MediaSessionOptions opts;
1363
1364 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001365 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001366 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001367 ASSERT_TRUE(offer1.get() != NULL);
1368
1369 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001370 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1371 RtpTransceiverDirection::kRecvOnly, kActive,
1372 &opts);
kwiberg31022942016-03-11 14:18:21 -08001373 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001374 f1_.CreateOffer(opts, offer1.get()));
1375 ASSERT_TRUE(offer2.get() != NULL);
1376
1377 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001378 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1379 RtpTransceiverDirection::kRecvOnly, kActive,
1380 &opts);
kwiberg31022942016-03-11 14:18:21 -08001381 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001382 f1_.CreateOffer(opts, offer2.get()));
1383 ASSERT_TRUE(offer3.get() != NULL);
1384
Steve Anton6fe1fba2018-12-11 10:15:23 -08001385 std::unique_ptr<SessionDescription> answer =
1386 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001387 ASSERT_TRUE(answer.get() != NULL);
1388 EXPECT_EQ(3u, answer->contents().size());
1389 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1390 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1391 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1392}
1393
ossu075af922016-06-14 03:29:38 -07001394// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1395// answerer settings.
1396
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001397// This test that the media direction is set to send/receive in an answer if
1398// the offer is send receive.
1399TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001400 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1401 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001402}
1403
1404// This test that the media direction is set to receive only in an answer if
1405// the offer is send only.
1406TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001407 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1408 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409}
1410
1411// This test that the media direction is set to send only in an answer if
1412// the offer is recv only.
1413TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001414 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1415 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001416}
1417
1418// This test that the media direction is set to inactive in an answer if
1419// the offer is inactive.
1420TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001421 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1422 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001423}
1424
1425// Test that a data content with an unknown protocol is rejected in an answer.
1426TEST_F(MediaSessionDescriptionFactoryTest,
1427 CreateDataAnswerToOfferWithUnknownProtocol) {
1428 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001429 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001430 f1_.set_secure(SEC_ENABLED);
1431 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001432 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001433 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001434 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001435 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001436 ASSERT_TRUE(dcd_offer != NULL);
1437 std::string protocol = "a weird unknown protocol";
1438 dcd_offer->set_protocol(protocol);
1439
Steve Anton6fe1fba2018-12-11 10:15:23 -08001440 std::unique_ptr<SessionDescription> answer =
1441 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001442
1443 const ContentInfo* dc_answer = answer->GetContentByName("data");
1444 ASSERT_TRUE(dc_answer != NULL);
1445 EXPECT_TRUE(dc_answer->rejected);
1446 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001447 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001448 ASSERT_TRUE(dcd_answer != NULL);
1449 EXPECT_EQ(protocol, dcd_answer->protocol());
1450}
1451
1452// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1453TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001454 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001455 f1_.set_secure(SEC_DISABLED);
1456 f2_.set_secure(SEC_DISABLED);
1457 tdf1_.set_secure(SEC_DISABLED);
1458 tdf2_.set_secure(SEC_DISABLED);
1459
Steve Anton6fe1fba2018-12-11 10:15:23 -08001460 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001461 const AudioContentDescription* offer_acd =
1462 GetFirstAudioContentDescription(offer.get());
1463 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001464 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001465
Steve Anton6fe1fba2018-12-11 10:15:23 -08001466 std::unique_ptr<SessionDescription> answer =
1467 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001468
1469 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1470 ASSERT_TRUE(ac_answer != NULL);
1471 EXPECT_FALSE(ac_answer->rejected);
1472
1473 const AudioContentDescription* answer_acd =
1474 GetFirstAudioContentDescription(answer.get());
1475 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001476 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001477}
1478
1479// Create a video offer and answer and ensure the RTP header extensions
1480// matches what we expect.
1481TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1482 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001483 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001484 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1485 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1486 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1487 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1488
Steve Anton6fe1fba2018-12-11 10:15:23 -08001489 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001490 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001491 std::unique_ptr<SessionDescription> answer =
1492 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001493
Yves Gerey665174f2018-06-19 15:03:05 +02001494 EXPECT_EQ(
1495 MAKE_VECTOR(kAudioRtpExtension1),
1496 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1497 EXPECT_EQ(
1498 MAKE_VECTOR(kVideoRtpExtension1),
1499 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1500 EXPECT_EQ(
1501 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1502 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1503 EXPECT_EQ(
1504 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1505 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001506}
1507
jbauch5869f502017-06-29 12:31:36 -07001508TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001509 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001510 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001511 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001512
1513 f1_.set_enable_encrypted_rtp_header_extensions(true);
1514 f2_.set_enable_encrypted_rtp_header_extensions(true);
1515
Yves Gerey665174f2018-06-19 15:03:05 +02001516 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1517 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1518 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1519 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001520
Steve Anton6fe1fba2018-12-11 10:15:23 -08001521 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001522 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001523 std::unique_ptr<SessionDescription> answer =
1524 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001525
Yves Gerey665174f2018-06-19 15:03:05 +02001526 EXPECT_EQ(
1527 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1528 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1529 EXPECT_EQ(
1530 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1531 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1532 EXPECT_EQ(
1533 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1534 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1535 EXPECT_EQ(
1536 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1537 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001538}
1539
1540TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001541 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001542 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001543 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001544
1545 f1_.set_enable_encrypted_rtp_header_extensions(true);
1546
Yves Gerey665174f2018-06-19 15:03:05 +02001547 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1548 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1549 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1550 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001551
Steve Anton6fe1fba2018-12-11 10:15:23 -08001552 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001553 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001554 std::unique_ptr<SessionDescription> answer =
1555 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001556
Yves Gerey665174f2018-06-19 15:03:05 +02001557 EXPECT_EQ(
1558 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1559 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1560 EXPECT_EQ(
1561 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1562 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1563 EXPECT_EQ(
1564 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1565 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1566 EXPECT_EQ(
1567 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1568 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001569}
1570
1571TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001572 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001573 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001574 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001575
1576 f2_.set_enable_encrypted_rtp_header_extensions(true);
1577
Yves Gerey665174f2018-06-19 15:03:05 +02001578 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1579 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1580 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1581 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001582
Steve Anton6fe1fba2018-12-11 10:15:23 -08001583 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001584 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001585 std::unique_ptr<SessionDescription> answer =
1586 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001587
Yves Gerey665174f2018-06-19 15:03:05 +02001588 EXPECT_EQ(
1589 MAKE_VECTOR(kAudioRtpExtension1),
1590 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1591 EXPECT_EQ(
1592 MAKE_VECTOR(kVideoRtpExtension1),
1593 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1594 EXPECT_EQ(
1595 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1596 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1597 EXPECT_EQ(
1598 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1599 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001600}
1601
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001602// Create an audio, video, data answer without legacy StreamParams.
1603TEST_F(MediaSessionDescriptionFactoryTest,
1604 TestCreateAnswerWithoutLegacyStreams) {
1605 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1607 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001608 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001609 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001610 std::unique_ptr<SessionDescription> answer =
1611 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001612 const ContentInfo* ac = answer->GetContentByName("audio");
1613 const ContentInfo* vc = answer->GetContentByName("video");
1614 const ContentInfo* dc = answer->GetContentByName("data");
1615 ASSERT_TRUE(ac != NULL);
1616 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001617 const AudioContentDescription* acd = ac->media_description()->as_audio();
1618 const VideoContentDescription* vcd = vc->media_description()->as_video();
1619 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620
1621 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1622 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1623 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1624}
1625
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626// Create a typical video answer, and ensure it matches what we expect.
1627TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1628 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001629 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1630 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1631 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001632
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001634 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1635 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1636 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001637
kwiberg31022942016-03-11 14:18:21 -08001638 std::unique_ptr<SessionDescription> offer;
1639 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640
1641 offer_opts.rtcp_mux_enabled = true;
1642 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001643 offer = f1_.CreateOffer(offer_opts, NULL);
1644 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001645 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1646 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1647 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1648 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1649 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1650 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1651 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1652 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1653 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1654 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1655 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1656 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1657
1658 offer_opts.rtcp_mux_enabled = true;
1659 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001660 offer = f1_.CreateOffer(offer_opts, NULL);
1661 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001662 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1663 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1664 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1665 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1666 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1667 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1668 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1669 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1670 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1671 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1672 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1673 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1674
1675 offer_opts.rtcp_mux_enabled = false;
1676 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001677 offer = f1_.CreateOffer(offer_opts, NULL);
1678 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001679 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1680 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1681 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1682 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1683 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1684 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1685 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1686 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1687 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1688 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1689 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1690 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1691
1692 offer_opts.rtcp_mux_enabled = false;
1693 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001694 offer = f1_.CreateOffer(offer_opts, NULL);
1695 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001696 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1697 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1698 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1699 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1700 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1701 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1702 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1703 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1704 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1705 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1706 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1707 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1708}
1709
1710// Create an audio-only answer to a video offer.
1711TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1712 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001713 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1714 RtpTransceiverDirection::kRecvOnly, kActive,
1715 &opts);
1716 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1717 RtpTransceiverDirection::kRecvOnly, kActive,
1718 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001719 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001720 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001721
1722 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001723 std::unique_ptr<SessionDescription> answer =
1724 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001725 const ContentInfo* ac = answer->GetContentByName("audio");
1726 const ContentInfo* vc = answer->GetContentByName("video");
1727 ASSERT_TRUE(ac != NULL);
1728 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001729 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730 EXPECT_TRUE(vc->rejected);
1731}
1732
1733// Create an audio-only answer to an offer with data.
1734TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001735 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001736 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001737 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1738 RtpTransceiverDirection::kRecvOnly, kActive,
1739 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001740 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001741 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001742
1743 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001744 std::unique_ptr<SessionDescription> answer =
1745 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001746 const ContentInfo* ac = answer->GetContentByName("audio");
1747 const ContentInfo* dc = answer->GetContentByName("data");
1748 ASSERT_TRUE(ac != NULL);
1749 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001750 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001751 EXPECT_TRUE(dc->rejected);
1752}
1753
1754// Create an answer that rejects the contents which are rejected in the offer.
1755TEST_F(MediaSessionDescriptionFactoryTest,
1756 CreateAnswerToOfferWithRejectedMedia) {
1757 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001758 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1759 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001760 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001761 ASSERT_TRUE(offer.get() != NULL);
1762 ContentInfo* ac = offer->GetContentByName("audio");
1763 ContentInfo* vc = offer->GetContentByName("video");
1764 ContentInfo* dc = offer->GetContentByName("data");
1765 ASSERT_TRUE(ac != NULL);
1766 ASSERT_TRUE(vc != NULL);
1767 ASSERT_TRUE(dc != NULL);
1768 ac->rejected = true;
1769 vc->rejected = true;
1770 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001771 std::unique_ptr<SessionDescription> answer =
1772 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001773 ac = answer->GetContentByName("audio");
1774 vc = answer->GetContentByName("video");
1775 dc = answer->GetContentByName("data");
1776 ASSERT_TRUE(ac != NULL);
1777 ASSERT_TRUE(vc != NULL);
1778 ASSERT_TRUE(dc != NULL);
1779 EXPECT_TRUE(ac->rejected);
1780 EXPECT_TRUE(vc->rejected);
1781 EXPECT_TRUE(dc->rejected);
1782}
1783
Johannes Kron0854eb62018-10-10 22:33:20 +02001784TEST_F(MediaSessionDescriptionFactoryTest,
1785 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1786 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001787 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001788 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001789 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001790 ASSERT_TRUE(offer.get() != NULL);
1791 std::unique_ptr<SessionDescription> answer_no_support(
1792 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001793 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001794
1795 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001796 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001797 ASSERT_TRUE(offer.get() != NULL);
1798 std::unique_ptr<SessionDescription> answer_support(
1799 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001800 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001801}
1802
1803TEST_F(MediaSessionDescriptionFactoryTest,
1804 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1805 MediaSessionOptions opts;
1806 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001807 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001808 MediaContentDescription* video_offer =
1809 offer->GetContentDescriptionByName("video");
1810 ASSERT_TRUE(video_offer);
1811 MediaContentDescription* audio_offer =
1812 offer->GetContentDescriptionByName("audio");
1813 ASSERT_TRUE(audio_offer);
1814
1815 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001816 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1817 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001818
1819 ASSERT_TRUE(offer.get() != NULL);
1820 std::unique_ptr<SessionDescription> answer_no_support(
1821 f2_.CreateAnswer(offer.get(), opts, NULL));
1822 MediaContentDescription* video_answer =
1823 answer_no_support->GetContentDescriptionByName("video");
1824 MediaContentDescription* audio_answer =
1825 answer_no_support->GetContentDescriptionByName("audio");
1826 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001827 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001828 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001829 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001830
1831 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001832 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1833 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001834 ASSERT_TRUE(offer.get() != NULL);
1835 std::unique_ptr<SessionDescription> answer_support(
1836 f2_.CreateAnswer(offer.get(), opts, NULL));
1837 video_answer = answer_support->GetContentDescriptionByName("video");
1838 audio_answer = answer_support->GetContentDescriptionByName("audio");
1839 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001840 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001841 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001842 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001843}
1844
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001845// Create an audio and video offer with:
1846// - one video track
1847// - two audio tracks
1848// - two data tracks
1849// and ensure it matches what we expect. Also updates the initial offer by
1850// adding a new video track and replaces one of the audio tracks.
1851TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1852 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001853 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001854 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1855 {kMediaStream1}, 1, &opts);
1856 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1857 {kMediaStream1}, 1, &opts);
1858 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1859 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001860
Steve Anton4e70a722017-11-28 14:57:10 -08001861 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001862 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1863 {kMediaStream1}, 1, &opts);
1864 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1865 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001866
1867 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001868 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001869
1870 ASSERT_TRUE(offer.get() != NULL);
1871 const ContentInfo* ac = offer->GetContentByName("audio");
1872 const ContentInfo* vc = offer->GetContentByName("video");
1873 const ContentInfo* dc = offer->GetContentByName("data");
1874 ASSERT_TRUE(ac != NULL);
1875 ASSERT_TRUE(vc != NULL);
1876 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001877 const AudioContentDescription* acd = ac->media_description()->as_audio();
1878 const VideoContentDescription* vcd = vc->media_description()->as_video();
1879 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001880 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001881 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001882
1883 const StreamParamsVec& audio_streams = acd->streams();
1884 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001885 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001886 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1887 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1888 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1889 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1890 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1891 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1892
1893 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1894 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001895 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001896
1897 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1898 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001899 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001900
1901 const StreamParamsVec& video_streams = vcd->streams();
1902 ASSERT_EQ(1U, video_streams.size());
1903 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1904 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1905 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1906 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1907
1908 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1909 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001910 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001911
1912 const StreamParamsVec& data_streams = dcd->streams();
1913 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001914 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001915 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1916 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1917 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1918 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1919 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1920 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1921
1922 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001923 dcd->bandwidth()); // default bandwidth (auto)
1924 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001925 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001926
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001927 // Update the offer. Add a new video track that is not synched to the
1928 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001929 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
1930 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001931 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001932 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
1933 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001934 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001935 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
1936 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001937 std::unique_ptr<SessionDescription> updated_offer(
1938 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939
1940 ASSERT_TRUE(updated_offer.get() != NULL);
1941 ac = updated_offer->GetContentByName("audio");
1942 vc = updated_offer->GetContentByName("video");
1943 dc = updated_offer->GetContentByName("data");
1944 ASSERT_TRUE(ac != NULL);
1945 ASSERT_TRUE(vc != NULL);
1946 ASSERT_TRUE(dc != NULL);
1947 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001948 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001949 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001950 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001952 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953
1954 EXPECT_EQ(acd->type(), updated_acd->type());
1955 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1956 EXPECT_EQ(vcd->type(), updated_vcd->type());
1957 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1958 EXPECT_EQ(dcd->type(), updated_dcd->type());
1959 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001960 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001961 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001962 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001963 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001964 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1966
1967 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1968 ASSERT_EQ(2U, updated_audio_streams.size());
1969 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1970 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1971 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1972 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1973 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1974
1975 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1976 ASSERT_EQ(2U, updated_video_streams.size());
1977 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1978 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001979 // All the media streams in one PeerConnection share one RTCP CNAME.
1980 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001981
1982 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1983 ASSERT_EQ(2U, updated_data_streams.size());
1984 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1985 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1986 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1987 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1988 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001989 // The stream correctly got the CNAME from the MediaSessionOptions.
1990 // The Expected RTCP CNAME is the default one as we are using the default
1991 // MediaSessionOptions.
1992 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001993}
1994
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001995// Create an offer with simulcast video stream.
1996TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1997 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001998 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1999 RtpTransceiverDirection::kRecvOnly, kActive,
2000 &opts);
2001 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2002 RtpTransceiverDirection::kSendRecv, kActive,
2003 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002004 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002005 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2006 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002007 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002008
2009 ASSERT_TRUE(offer.get() != NULL);
2010 const ContentInfo* vc = offer->GetContentByName("video");
2011 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002012 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002013
2014 const StreamParamsVec& video_streams = vcd->streams();
2015 ASSERT_EQ(1U, video_streams.size());
2016 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2017 const SsrcGroup* sim_ssrc_group =
2018 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2019 ASSERT_TRUE(sim_ssrc_group != NULL);
2020 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2021}
2022
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002023MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2024 const RidDescription& rid1 = ::testing::get<0>(arg);
2025 const RidDescription& rid2 = ::testing::get<1>(arg);
2026 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2027}
2028
2029static void CheckSimulcastInSessionDescription(
2030 const SessionDescription* description,
2031 const std::string& content_name,
2032 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002033 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002034 ASSERT_NE(description, nullptr);
2035 const ContentInfo* content = description->GetContentByName(content_name);
2036 ASSERT_NE(content, nullptr);
2037 const MediaContentDescription* cd = content->media_description();
2038 ASSERT_NE(cd, nullptr);
2039 const StreamParamsVec& streams = cd->streams();
2040 ASSERT_THAT(streams, SizeIs(1));
2041 const StreamParams& stream = streams[0];
2042 ASSERT_THAT(stream.ssrcs, IsEmpty());
2043 EXPECT_TRUE(stream.has_rids());
2044 const std::vector<RidDescription> rids = stream.rids();
2045
2046 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2047
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002048 EXPECT_TRUE(cd->HasSimulcast());
2049 const SimulcastDescription& simulcast = cd->simulcast_description();
2050 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2051 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2052
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002053 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002054}
2055
2056// Create an offer with spec-compliant simulcast video stream.
2057TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2058 MediaSessionOptions opts;
2059 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2060 RtpTransceiverDirection::kSendRecv, kActive,
2061 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002062 std::vector<RidDescription> send_rids;
2063 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2064 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2065 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2066 SimulcastLayerList simulcast_layers;
2067 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2068 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2069 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2070 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2071 {kMediaStream1}, send_rids,
2072 simulcast_layers, 0, &opts);
2073 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2074
2075 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002076 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002077}
2078
2079// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2080// In this scenario, RIDs do not need to be negotiated (there is only one).
2081TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2082 MediaSessionOptions opts;
2083 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2084 RtpTransceiverDirection::kSendRecv, kActive,
2085 &opts);
2086 RidDescription rid("f", RidDirection::kSend);
2087 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2088 {kMediaStream1}, {rid},
2089 SimulcastLayerList(), 0, &opts);
2090 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2091
2092 ASSERT_NE(offer.get(), nullptr);
2093 const ContentInfo* content = offer->GetContentByName("video");
2094 ASSERT_NE(content, nullptr);
2095 const MediaContentDescription* cd = content->media_description();
2096 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002097 const StreamParamsVec& streams = cd->streams();
2098 ASSERT_THAT(streams, SizeIs(1));
2099 const StreamParams& stream = streams[0];
2100 ASSERT_THAT(stream.ssrcs, IsEmpty());
2101 EXPECT_FALSE(stream.has_rids());
2102 EXPECT_FALSE(cd->HasSimulcast());
2103}
2104
2105// Create an answer with spec-compliant simulcast video stream.
2106// In this scenario, the SFU is the caller requesting that we send Simulcast.
2107TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2108 MediaSessionOptions offer_opts;
2109 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2110 RtpTransceiverDirection::kSendRecv, kActive,
2111 &offer_opts);
2112 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2113 {kMediaStream1}, 1, &offer_opts);
2114 std::unique_ptr<SessionDescription> offer =
2115 f1_.CreateOffer(offer_opts, nullptr);
2116
2117 MediaSessionOptions answer_opts;
2118 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2119 RtpTransceiverDirection::kSendRecv, kActive,
2120 &answer_opts);
2121
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002122 std::vector<RidDescription> rid_descriptions{
2123 RidDescription("f", RidDirection::kSend),
2124 RidDescription("h", RidDirection::kSend),
2125 RidDescription("q", RidDirection::kSend),
2126 };
2127 SimulcastLayerList simulcast_layers;
2128 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2129 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2130 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2131 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2132 {kMediaStream1}, rid_descriptions,
2133 simulcast_layers, 0, &answer_opts);
2134 std::unique_ptr<SessionDescription> answer =
2135 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2136
2137 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002138 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002139}
2140
2141// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2142// In this scenario, RIDs do not need to be negotiated (there is only one).
2143// Note that RID Direction is not the same as the transceiver direction.
2144TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2145 MediaSessionOptions offer_opts;
2146 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2147 RtpTransceiverDirection::kSendRecv, kActive,
2148 &offer_opts);
2149 RidDescription rid_offer("f", RidDirection::kSend);
2150 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2151 {kMediaStream1}, {rid_offer},
2152 SimulcastLayerList(), 0, &offer_opts);
2153 std::unique_ptr<SessionDescription> offer =
2154 f1_.CreateOffer(offer_opts, nullptr);
2155
2156 MediaSessionOptions answer_opts;
2157 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2158 RtpTransceiverDirection::kSendRecv, kActive,
2159 &answer_opts);
2160
2161 RidDescription rid_answer("f", RidDirection::kReceive);
2162 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2163 {kMediaStream1}, {rid_answer},
2164 SimulcastLayerList(), 0, &answer_opts);
2165 std::unique_ptr<SessionDescription> answer =
2166 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2167
2168 ASSERT_NE(answer.get(), nullptr);
2169 const ContentInfo* content = offer->GetContentByName("video");
2170 ASSERT_NE(content, nullptr);
2171 const MediaContentDescription* cd = content->media_description();
2172 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002173 const StreamParamsVec& streams = cd->streams();
2174 ASSERT_THAT(streams, SizeIs(1));
2175 const StreamParams& stream = streams[0];
2176 ASSERT_THAT(stream.ssrcs, IsEmpty());
2177 EXPECT_FALSE(stream.has_rids());
2178 EXPECT_FALSE(cd->HasSimulcast());
2179}
2180
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002181// Create an audio and video answer to a standard video offer with:
2182// - one video track
2183// - two audio tracks
2184// - two data tracks
2185// and ensure it matches what we expect. Also updates the initial answer by
2186// adding a new video track and removes one of the audio tracks.
2187TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2188 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002189 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2190 RtpTransceiverDirection::kRecvOnly, kActive,
2191 &offer_opts);
2192 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2193 RtpTransceiverDirection::kRecvOnly, kActive,
2194 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002195 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002196 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2197 RtpTransceiverDirection::kRecvOnly, kActive,
2198 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002199 f1_.set_secure(SEC_ENABLED);
2200 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002201 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002202
zhihuang1c378ed2017-08-17 14:10:50 -07002203 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002204 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2205 RtpTransceiverDirection::kSendRecv, kActive,
2206 &answer_opts);
2207 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2208 RtpTransceiverDirection::kSendRecv, kActive,
2209 &answer_opts);
2210 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2211 {kMediaStream1}, 1, &answer_opts);
2212 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2213 {kMediaStream1}, 1, &answer_opts);
2214 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2215 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002216
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002217 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2218 RtpTransceiverDirection::kSendRecv, kActive,
2219 &answer_opts);
2220 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2221 {kMediaStream1}, 1, &answer_opts);
2222 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2223 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002224 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002225
Steve Anton6fe1fba2018-12-11 10:15:23 -08002226 std::unique_ptr<SessionDescription> answer =
2227 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002228
2229 ASSERT_TRUE(answer.get() != NULL);
2230 const ContentInfo* ac = answer->GetContentByName("audio");
2231 const ContentInfo* vc = answer->GetContentByName("video");
2232 const ContentInfo* dc = answer->GetContentByName("data");
2233 ASSERT_TRUE(ac != NULL);
2234 ASSERT_TRUE(vc != NULL);
2235 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002236 const AudioContentDescription* acd = ac->media_description()->as_audio();
2237 const VideoContentDescription* vcd = vc->media_description()->as_video();
2238 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002239 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2240 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2241 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002242
2243 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002244 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002245
2246 const StreamParamsVec& audio_streams = acd->streams();
2247 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002248 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002249 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2250 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2251 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2252 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2253 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2254 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2255
2256 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2257 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2258
2259 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002260 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002261
2262 const StreamParamsVec& video_streams = vcd->streams();
2263 ASSERT_EQ(1U, video_streams.size());
2264 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2265 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2266 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2267 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2268
2269 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002270 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002271
2272 const StreamParamsVec& data_streams = dcd->streams();
2273 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002274 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002275 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2276 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2277 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2278 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2279 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2280 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2281
2282 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002283 dcd->bandwidth()); // default bandwidth (auto)
2284 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002285
2286 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002287 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002288 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2289 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002290 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2291 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002292 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002293 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002294
2295 ASSERT_TRUE(updated_answer.get() != NULL);
2296 ac = updated_answer->GetContentByName("audio");
2297 vc = updated_answer->GetContentByName("video");
2298 dc = updated_answer->GetContentByName("data");
2299 ASSERT_TRUE(ac != NULL);
2300 ASSERT_TRUE(vc != NULL);
2301 ASSERT_TRUE(dc != NULL);
2302 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002303 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002304 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002305 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002306 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002307 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002308
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002309 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002311 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002312 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002313 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002314 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2315
2316 EXPECT_EQ(acd->type(), updated_acd->type());
2317 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2318 EXPECT_EQ(vcd->type(), updated_vcd->type());
2319 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2320 EXPECT_EQ(dcd->type(), updated_dcd->type());
2321 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2322
2323 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2324 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002325 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002326
2327 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2328 ASSERT_EQ(2U, updated_video_streams.size());
2329 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2330 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002331 // All media streams in one PeerConnection share one CNAME.
2332 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002333
2334 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2335 ASSERT_EQ(1U, updated_data_streams.size());
2336 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2337}
2338
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002339// Create an updated offer after creating an answer to the original offer and
2340// verify that the codecs that were part of the original answer are not changed
2341// in the updated offer.
2342TEST_F(MediaSessionDescriptionFactoryTest,
2343 RespondentCreatesOfferAfterCreatingAnswer) {
2344 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002345 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002346
Steve Anton6fe1fba2018-12-11 10:15:23 -08002347 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2348 std::unique_ptr<SessionDescription> answer =
2349 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002350
2351 const AudioContentDescription* acd =
2352 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002353 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002354
2355 const VideoContentDescription* vcd =
2356 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002357 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002358
kwiberg31022942016-03-11 14:18:21 -08002359 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360 f2_.CreateOffer(opts, answer.get()));
2361
2362 // The expected audio codecs are the common audio codecs from the first
2363 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2364 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002365 // TODO(wu): |updated_offer| should not include the codec
2366 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002367 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002368 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002369 };
2370
2371 // The expected video codecs are the common video codecs from the first
2372 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2373 // preference order.
2374 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002375 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002376 };
2377
2378 const AudioContentDescription* updated_acd =
2379 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002380 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002381
2382 const VideoContentDescription* updated_vcd =
2383 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002384 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002385}
2386
Steve Anton5c72e712018-12-10 14:25:30 -08002387// Test that a reoffer does not reuse audio codecs from a previous media section
2388// that is being recycled.
2389TEST_F(MediaSessionDescriptionFactoryTest,
2390 ReOfferDoesNotReUseRecycledAudioCodecs) {
2391 f1_.set_video_codecs({});
2392 f2_.set_video_codecs({});
2393
2394 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002395 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2396 RtpTransceiverDirection::kSendRecv, kActive,
2397 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002398 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2399 std::unique_ptr<SessionDescription> answer =
2400 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002401
2402 // Recycle the media section by changing its mid.
2403 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002404 std::unique_ptr<SessionDescription> reoffer =
2405 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002406
2407 // Expect that the results of the first negotiation are ignored. If the m=
2408 // section was not recycled the payload types would match the initial offerer.
2409 const AudioContentDescription* acd =
2410 GetFirstAudioContentDescription(reoffer.get());
2411 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2412}
2413
2414// Test that a reoffer does not reuse video codecs from a previous media section
2415// that is being recycled.
2416TEST_F(MediaSessionDescriptionFactoryTest,
2417 ReOfferDoesNotReUseRecycledVideoCodecs) {
2418 f1_.set_audio_codecs({}, {});
2419 f2_.set_audio_codecs({}, {});
2420
2421 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002422 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2423 RtpTransceiverDirection::kSendRecv, kActive,
2424 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002425 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2426 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002427
2428 // Recycle the media section by changing its mid.
2429 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002430 std::unique_ptr<SessionDescription> reoffer =
2431 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002432
2433 // Expect that the results of the first negotiation are ignored. If the m=
2434 // section was not recycled the payload types would match the initial offerer.
2435 const VideoContentDescription* vcd =
2436 GetFirstVideoContentDescription(reoffer.get());
2437 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2438}
2439
2440// Test that a reanswer does not reuse audio codecs from a previous media
2441// section that is being recycled.
2442TEST_F(MediaSessionDescriptionFactoryTest,
2443 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2444 f1_.set_video_codecs({});
2445 f2_.set_video_codecs({});
2446
2447 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2448 // second offer/answer is forward (|f1_| as offerer).
2449 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002450 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2451 RtpTransceiverDirection::kSendRecv, kActive,
2452 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002453 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2454 std::unique_ptr<SessionDescription> answer =
2455 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002456
2457 // Recycle the media section by changing its mid.
2458 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002459 std::unique_ptr<SessionDescription> reoffer =
2460 f1_.CreateOffer(opts, answer.get());
2461 std::unique_ptr<SessionDescription> reanswer =
2462 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002463
2464 // Expect that the results of the first negotiation are ignored. If the m=
2465 // section was not recycled the payload types would match the initial offerer.
2466 const AudioContentDescription* acd =
2467 GetFirstAudioContentDescription(reanswer.get());
2468 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2469}
2470
2471// Test that a reanswer does not reuse video codecs from a previous media
2472// section that is being recycled.
2473TEST_F(MediaSessionDescriptionFactoryTest,
2474 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2475 f1_.set_audio_codecs({}, {});
2476 f2_.set_audio_codecs({}, {});
2477
2478 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2479 // second offer/answer is forward (|f1_| as offerer).
2480 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002481 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2482 RtpTransceiverDirection::kSendRecv, kActive,
2483 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002484 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2485 std::unique_ptr<SessionDescription> answer =
2486 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002487
2488 // Recycle the media section by changing its mid.
2489 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002490 std::unique_ptr<SessionDescription> reoffer =
2491 f1_.CreateOffer(opts, answer.get());
2492 std::unique_ptr<SessionDescription> reanswer =
2493 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002494
2495 // Expect that the results of the first negotiation are ignored. If the m=
2496 // section was not recycled the payload types would match the initial offerer.
2497 const VideoContentDescription* vcd =
2498 GetFirstVideoContentDescription(reanswer.get());
2499 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2500}
2501
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002502// Create an updated offer after creating an answer to the original offer and
2503// verify that the codecs that were part of the original answer are not changed
2504// in the updated offer. In this test Rtx is enabled.
2505TEST_F(MediaSessionDescriptionFactoryTest,
2506 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2507 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002508 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2509 RtpTransceiverDirection::kRecvOnly, kActive,
2510 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002511 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002512 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002513 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514 f1_.set_video_codecs(f1_codecs);
2515
2516 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002517 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002518 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002519 f2_.set_video_codecs(f2_codecs);
2520
Steve Anton6fe1fba2018-12-11 10:15:23 -08002521 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002522 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002523 std::unique_ptr<SessionDescription> answer =
2524 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002525
2526 const VideoContentDescription* vcd =
2527 GetFirstVideoContentDescription(answer.get());
2528
2529 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002530 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2531 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002532
2533 EXPECT_EQ(expected_codecs, vcd->codecs());
2534
deadbeef67cf2c12016-04-13 10:07:16 -07002535 // Now, make sure we get same result (except for the order) if |f2_| creates
2536 // an updated offer even though the default payload types between |f1_| and
2537 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002538 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002539 f2_.CreateOffer(opts, answer.get()));
2540 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002541 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002542 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2543
2544 const VideoContentDescription* updated_vcd =
2545 GetFirstVideoContentDescription(updated_answer.get());
2546
2547 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2548}
2549
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002550// Regression test for:
2551// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2552// Existing codecs should always appear before new codecs in re-offers. But
2553// under a specific set of circumstances, the existing RTX codec was ending up
2554// added to the end of the list.
2555TEST_F(MediaSessionDescriptionFactoryTest,
2556 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2557 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002558 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2559 RtpTransceiverDirection::kRecvOnly, kActive,
2560 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002561 // We specifically choose different preferred payload types for VP8 to
2562 // trigger the issue.
2563 cricket::VideoCodec vp8_offerer(100, "VP8");
2564 cricket::VideoCodec vp8_offerer_rtx =
2565 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2566 cricket::VideoCodec vp8_answerer(110, "VP8");
2567 cricket::VideoCodec vp8_answerer_rtx =
2568 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2569 cricket::VideoCodec vp9(120, "VP9");
2570 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2571
2572 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2573 // We also specifically cause the answerer to prefer VP9, such that if it
2574 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2575 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2576 vp8_answerer_rtx};
2577
2578 f1_.set_video_codecs(f1_codecs);
2579 f2_.set_video_codecs(f2_codecs);
2580 std::vector<AudioCodec> audio_codecs;
2581 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2582 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2583
2584 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002585 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002586 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002587 std::unique_ptr<SessionDescription> answer =
2588 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002589
2590 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2591 // But if the bug is triggered, RTX for VP8 ends up last.
2592 std::unique_ptr<SessionDescription> updated_offer(
2593 f2_.CreateOffer(opts, answer.get()));
2594
2595 const VideoContentDescription* vcd =
2596 GetFirstVideoContentDescription(updated_offer.get());
2597 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2598 ASSERT_EQ(4u, codecs.size());
2599 EXPECT_EQ(vp8_offerer, codecs[0]);
2600 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2601 EXPECT_EQ(vp9, codecs[2]);
2602 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002603}
2604
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002605// Create an updated offer that adds video after creating an audio only answer
2606// to the original offer. This test verifies that if a video codec and the RTX
2607// codec have the same default payload type as an audio codec that is already in
2608// use, the added codecs payload types are changed.
2609TEST_F(MediaSessionDescriptionFactoryTest,
2610 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2611 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002612 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002613 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002614 f1_.set_video_codecs(f1_codecs);
2615
2616 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002617 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2618 RtpTransceiverDirection::kRecvOnly, kActive,
2619 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002620
Steve Anton6fe1fba2018-12-11 10:15:23 -08002621 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2622 std::unique_ptr<SessionDescription> answer =
2623 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002624
2625 const AudioContentDescription* acd =
2626 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002627 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002628
2629 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2630 // reference be the same as an audio codec that was negotiated in the
2631 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002632 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002633 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002634
2635 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2636 int used_pl_type = acd->codecs()[0].id;
2637 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002638 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639 f2_.set_video_codecs(f2_codecs);
2640
kwiberg31022942016-03-11 14:18:21 -08002641 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642 f2_.CreateOffer(opts, answer.get()));
2643 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002644 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002645 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2646
2647 const AudioContentDescription* updated_acd =
2648 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002649 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002650
2651 const VideoContentDescription* updated_vcd =
2652 GetFirstVideoContentDescription(updated_answer.get());
2653
2654 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002655 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002656 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002657 EXPECT_NE(used_pl_type, new_h264_pl_type);
2658 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002659 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002660 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2661 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2662}
2663
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002664// Create an updated offer with RTX after creating an answer to an offer
2665// without RTX, and with different default payload types.
2666// Verify that the added RTX codec references the correct payload type.
2667TEST_F(MediaSessionDescriptionFactoryTest,
2668 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2669 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002670 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002671
2672 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2673 // This creates rtx for H264 with the payload type |f2_| uses.
2674 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2675 f2_.set_video_codecs(f2_codecs);
2676
Steve Anton6fe1fba2018-12-11 10:15:23 -08002677 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002678 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002679 std::unique_ptr<SessionDescription> answer =
2680 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002681
2682 const VideoContentDescription* vcd =
2683 GetFirstVideoContentDescription(answer.get());
2684
2685 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2686 EXPECT_EQ(expected_codecs, vcd->codecs());
2687
2688 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2689 // updated offer, even though the default payload types are different from
2690 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002691 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002692 f2_.CreateOffer(opts, answer.get()));
2693 ASSERT_TRUE(updated_offer);
2694
2695 const VideoContentDescription* updated_vcd =
2696 GetFirstVideoContentDescription(updated_offer.get());
2697
2698 // New offer should attempt to add H263, and RTX for H264.
2699 expected_codecs.push_back(kVideoCodecs2[1]);
2700 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2701 &expected_codecs);
2702 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2703}
2704
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002705// Test that RTX is ignored when there is no associated payload type parameter.
2706TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2707 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002708 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2709 RtpTransceiverDirection::kRecvOnly, kActive,
2710 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002712 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002713 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714 f1_.set_video_codecs(f1_codecs);
2715
2716 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002717 // This creates RTX for H264 with the payload type |f2_| uses.
2718 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002719 f2_.set_video_codecs(f2_codecs);
2720
Steve Anton6fe1fba2018-12-11 10:15:23 -08002721 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002722 ASSERT_TRUE(offer.get() != NULL);
2723 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2724 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2725 // is possible to test that that RTX is dropped when
2726 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002727 MediaContentDescription* media_desc =
2728 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2729 ASSERT_TRUE(media_desc);
2730 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002731 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002732 for (VideoCodec& codec : codecs) {
2733 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2734 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002735 }
2736 }
2737 desc->set_codecs(codecs);
2738
Steve Anton6fe1fba2018-12-11 10:15:23 -08002739 std::unique_ptr<SessionDescription> answer =
2740 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002741
Steve Anton64b626b2019-01-28 17:25:26 -08002742 EXPECT_THAT(
2743 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2744 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002745}
2746
2747// Test that RTX will be filtered out in the answer if its associated payload
2748// type doesn't match the local value.
2749TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2750 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002751 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2752 RtpTransceiverDirection::kRecvOnly, kActive,
2753 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002754 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2755 // This creates RTX for H264 in sender.
2756 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2757 f1_.set_video_codecs(f1_codecs);
2758
2759 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2760 // This creates RTX for H263 in receiver.
2761 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2762 f2_.set_video_codecs(f2_codecs);
2763
Steve Anton6fe1fba2018-12-11 10:15:23 -08002764 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002765 ASSERT_TRUE(offer.get() != NULL);
2766 // Associated payload type doesn't match, therefore, RTX codec is removed in
2767 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002768 std::unique_ptr<SessionDescription> answer =
2769 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002770
Steve Anton64b626b2019-01-28 17:25:26 -08002771 EXPECT_THAT(
2772 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2773 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002774}
2775
2776// Test that when multiple RTX codecs are offered, only the matched RTX codec
2777// is added in the answer, and the unsupported RTX codec is filtered out.
2778TEST_F(MediaSessionDescriptionFactoryTest,
2779 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2780 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002781 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2782 RtpTransceiverDirection::kRecvOnly, kActive,
2783 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002784 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2785 // This creates RTX for H264-SVC in sender.
2786 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2787 f1_.set_video_codecs(f1_codecs);
2788
2789 // This creates RTX for H264 in sender.
2790 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2791 f1_.set_video_codecs(f1_codecs);
2792
2793 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2794 // This creates RTX for H264 in receiver.
2795 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2796 f2_.set_video_codecs(f2_codecs);
2797
2798 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2799 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002800 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002801 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002802 std::unique_ptr<SessionDescription> answer =
2803 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002804 const VideoContentDescription* vcd =
2805 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002806 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2807 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2808 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002809
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002810 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002811}
2812
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002813// Test that after one RTX codec has been negotiated, a new offer can attempt
2814// to add another.
2815TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2816 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002817 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2818 RtpTransceiverDirection::kRecvOnly, kActive,
2819 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002820 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2821 // This creates RTX for H264 for the offerer.
2822 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2823 f1_.set_video_codecs(f1_codecs);
2824
Steve Anton6fe1fba2018-12-11 10:15:23 -08002825 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002826 ASSERT_TRUE(offer);
2827 const VideoContentDescription* vcd =
2828 GetFirstVideoContentDescription(offer.get());
2829
2830 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2831 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2832 &expected_codecs);
2833 EXPECT_EQ(expected_codecs, vcd->codecs());
2834
2835 // Now, attempt to add RTX for H264-SVC.
2836 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2837 f1_.set_video_codecs(f1_codecs);
2838
kwiberg31022942016-03-11 14:18:21 -08002839 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002840 f1_.CreateOffer(opts, offer.get()));
2841 ASSERT_TRUE(updated_offer);
2842 vcd = GetFirstVideoContentDescription(updated_offer.get());
2843
2844 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2845 &expected_codecs);
2846 EXPECT_EQ(expected_codecs, vcd->codecs());
2847}
2848
Noah Richards2e7a0982015-05-18 14:02:54 -07002849// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2850// generated for each simulcast ssrc and correctly grouped.
2851TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2852 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002853 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2854 RtpTransceiverDirection::kSendRecv, kActive,
2855 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002856 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002857 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2858 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002859
2860 // Use a single real codec, and then add RTX for it.
2861 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002862 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002863 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2864 f1_.set_video_codecs(f1_codecs);
2865
2866 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2867 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002868 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002869 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002870 MediaContentDescription* media_desc =
2871 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2872 ASSERT_TRUE(media_desc);
2873 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002874 const StreamParamsVec& streams = desc->streams();
2875 // Single stream.
2876 ASSERT_EQ(1u, streams.size());
2877 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2878 EXPECT_EQ(6u, streams[0].ssrcs.size());
2879 // And should have a SIM group for the simulcast.
2880 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2881 // And a FID group for RTX.
2882 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002883 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002884 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2885 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002886 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002887 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2888 EXPECT_EQ(3u, fid_ssrcs.size());
2889}
2890
brandtr03d5fb12016-11-22 03:37:59 -08002891// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2892// together with a FEC-FR grouping.
2893TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2894 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002895 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2896 RtpTransceiverDirection::kSendRecv, kActive,
2897 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002898 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002899 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2900 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002901
2902 // Use a single real codec, and then add FlexFEC for it.
2903 std::vector<VideoCodec> f1_codecs;
2904 f1_codecs.push_back(VideoCodec(97, "H264"));
2905 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2906 f1_.set_video_codecs(f1_codecs);
2907
2908 // Ensure that the offer has a single FlexFEC ssrc and that
2909 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002910 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002911 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002912 MediaContentDescription* media_desc =
2913 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2914 ASSERT_TRUE(media_desc);
2915 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002916 const StreamParamsVec& streams = desc->streams();
2917 // Single stream.
2918 ASSERT_EQ(1u, streams.size());
2919 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2920 EXPECT_EQ(2u, streams[0].ssrcs.size());
2921 // And should have a FEC-FR group for FlexFEC.
2922 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2923 std::vector<uint32_t> primary_ssrcs;
2924 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2925 ASSERT_EQ(1u, primary_ssrcs.size());
2926 uint32_t flexfec_ssrc;
2927 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2928 EXPECT_NE(flexfec_ssrc, 0u);
2929}
2930
2931// Test that FlexFEC is disabled for simulcast.
2932// TODO(brandtr): Remove this test when we support simulcast, either through
2933// multiple FlexfecSenders, or through multistream protection.
2934TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2935 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002936 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2937 RtpTransceiverDirection::kSendRecv, kActive,
2938 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002939 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002940 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2941 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002942
2943 // Use a single real codec, and then add FlexFEC for it.
2944 std::vector<VideoCodec> f1_codecs;
2945 f1_codecs.push_back(VideoCodec(97, "H264"));
2946 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2947 f1_.set_video_codecs(f1_codecs);
2948
2949 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2950 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002951 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002952 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002953 MediaContentDescription* media_desc =
2954 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2955 ASSERT_TRUE(media_desc);
2956 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002957 const StreamParamsVec& streams = desc->streams();
2958 // Single stream.
2959 ASSERT_EQ(1u, streams.size());
2960 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2961 EXPECT_EQ(3u, streams[0].ssrcs.size());
2962 // And should have a SIM group for the simulcast.
2963 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2964 // And not a FEC-FR group for FlexFEC.
2965 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2966 std::vector<uint32_t> primary_ssrcs;
2967 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2968 EXPECT_EQ(3u, primary_ssrcs.size());
2969 for (uint32_t primary_ssrc : primary_ssrcs) {
2970 uint32_t flexfec_ssrc;
2971 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2972 }
2973}
2974
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002975// Create an updated offer after creating an answer to the original offer and
2976// verify that the RTP header extensions that were part of the original answer
2977// are not changed in the updated offer.
2978TEST_F(MediaSessionDescriptionFactoryTest,
2979 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2980 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002981 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002982
2983 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2984 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2985 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2986 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2987
Steve Anton6fe1fba2018-12-11 10:15:23 -08002988 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2989 std::unique_ptr<SessionDescription> answer =
2990 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002991
Yves Gerey665174f2018-06-19 15:03:05 +02002992 EXPECT_EQ(
2993 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2994 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2995 EXPECT_EQ(
2996 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2997 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002998
kwiberg31022942016-03-11 14:18:21 -08002999 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003000 f2_.CreateOffer(opts, answer.get()));
3001
3002 // The expected RTP header extensions in the new offer are the resulting
3003 // extensions from the first offer/answer exchange plus the extensions only
3004 // |f2_| offer.
3005 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003006 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003007 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3008 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3009 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003010 };
3011
3012 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003013 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003014 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3015 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3016 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003017 };
3018
3019 const AudioContentDescription* updated_acd =
3020 GetFirstAudioContentDescription(updated_offer.get());
3021 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3022 updated_acd->rtp_header_extensions());
3023
3024 const VideoContentDescription* updated_vcd =
3025 GetFirstVideoContentDescription(updated_offer.get());
3026 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3027 updated_vcd->rtp_header_extensions());
3028}
3029
deadbeefa5b273a2015-08-20 17:30:13 -07003030// Verify that if the same RTP extension URI is used for audio and video, the
3031// same ID is used. Also verify that the ID isn't changed when creating an
3032// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003033TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003034 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003035 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003036
3037 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3038 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3039
Steve Anton6fe1fba2018-12-11 10:15:23 -08003040 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003041
3042 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3043 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003044 const RtpExtension kExpectedVideoRtpExtension[] = {
3045 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003046 };
3047
Yves Gerey665174f2018-06-19 15:03:05 +02003048 EXPECT_EQ(
3049 MAKE_VECTOR(kAudioRtpExtension3),
3050 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3051 EXPECT_EQ(
3052 MAKE_VECTOR(kExpectedVideoRtpExtension),
3053 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003054
3055 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003056 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003057 f1_.CreateOffer(opts, offer.get()));
3058
3059 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003060 GetFirstAudioContentDescription(updated_offer.get())
3061 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003062 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003063 GetFirstVideoContentDescription(updated_offer.get())
3064 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003065}
3066
jbauch5869f502017-06-29 12:31:36 -07003067// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3068TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3069 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003070 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003071
3072 f1_.set_enable_encrypted_rtp_header_extensions(true);
3073 f2_.set_enable_encrypted_rtp_header_extensions(true);
3074
3075 f1_.set_audio_rtp_header_extensions(
3076 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3077 f1_.set_video_rtp_header_extensions(
3078 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3079
Steve Anton6fe1fba2018-12-11 10:15:23 -08003080 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003081
3082 // The extensions that are shared between audio and video should use the same
3083 // id.
3084 const RtpExtension kExpectedVideoRtpExtension[] = {
3085 kVideoRtpExtension3ForEncryption[0],
3086 kAudioRtpExtension3ForEncryptionOffer[1],
3087 kAudioRtpExtension3ForEncryptionOffer[2],
3088 };
3089
Yves Gerey665174f2018-06-19 15:03:05 +02003090 EXPECT_EQ(
3091 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3092 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3093 EXPECT_EQ(
3094 MAKE_VECTOR(kExpectedVideoRtpExtension),
3095 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003096
3097 // Nothing should change when creating a new offer
3098 std::unique_ptr<SessionDescription> updated_offer(
3099 f1_.CreateOffer(opts, offer.get()));
3100
3101 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003102 GetFirstAudioContentDescription(updated_offer.get())
3103 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003104 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003105 GetFirstVideoContentDescription(updated_offer.get())
3106 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003107}
3108
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003109TEST(MediaSessionDescription, CopySessionDescription) {
3110 SessionDescription source;
3111 cricket::ContentGroup group(cricket::CN_AUDIO);
3112 source.AddGroup(group);
3113 AudioContentDescription* acd(new AudioContentDescription());
3114 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3115 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003116 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003117 VideoContentDescription* vcd(new VideoContentDescription());
3118 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3119 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003120 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003121
kwiberg31022942016-03-11 14:18:21 -08003122 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003123 ASSERT_TRUE(copy.get() != NULL);
3124 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3125 const ContentInfo* ac = copy->GetContentByName("audio");
3126 const ContentInfo* vc = copy->GetContentByName("video");
3127 ASSERT_TRUE(ac != NULL);
3128 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003129 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003130 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003131 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3132 EXPECT_EQ(1u, acd->first_ssrc());
3133
Steve Anton5adfafd2017-12-20 16:34:00 -08003134 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003135 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003136 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3137 EXPECT_EQ(2u, vcd->first_ssrc());
3138}
3139
3140// The below TestTransportInfoXXX tests create different offers/answers, and
3141// ensure the TransportInfo in the SessionDescription matches what we expect.
3142TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3143 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003144 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3145 RtpTransceiverDirection::kRecvOnly, kActive,
3146 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003147 TestTransportInfo(true, options, false);
3148}
3149
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003150TEST_F(MediaSessionDescriptionFactoryTest,
3151 TestTransportInfoOfferIceRenomination) {
3152 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003153 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3154 RtpTransceiverDirection::kRecvOnly, kActive,
3155 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003156 options.media_description_options[0]
3157 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003158 TestTransportInfo(true, options, false);
3159}
3160
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003161TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3162 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003163 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3164 RtpTransceiverDirection::kRecvOnly, kActive,
3165 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003166 TestTransportInfo(true, options, true);
3167}
3168
3169TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3170 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003171 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3172 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3173 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003174 TestTransportInfo(true, options, false);
3175}
3176
3177TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003178 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003179 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003180 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3181 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3182 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003183 TestTransportInfo(true, options, true);
3184}
3185
3186TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3187 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003188 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3189 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3190 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003191 options.bundle_enabled = true;
3192 TestTransportInfo(true, options, false);
3193}
3194
3195TEST_F(MediaSessionDescriptionFactoryTest,
3196 TestTransportInfoOfferBundleCurrent) {
3197 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003198 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3199 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3200 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003201 options.bundle_enabled = true;
3202 TestTransportInfo(true, options, true);
3203}
3204
3205TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3206 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003207 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3208 RtpTransceiverDirection::kRecvOnly, kActive,
3209 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003210 TestTransportInfo(false, options, false);
3211}
3212
3213TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003214 TestTransportInfoAnswerIceRenomination) {
3215 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003216 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3217 RtpTransceiverDirection::kRecvOnly, kActive,
3218 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003219 options.media_description_options[0]
3220 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003221 TestTransportInfo(false, options, false);
3222}
3223
3224TEST_F(MediaSessionDescriptionFactoryTest,
3225 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003226 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003227 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3228 RtpTransceiverDirection::kRecvOnly, kActive,
3229 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003230 TestTransportInfo(false, options, true);
3231}
3232
3233TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3234 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003235 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3236 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3237 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003238 TestTransportInfo(false, options, false);
3239}
3240
3241TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003242 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003243 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003244 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3245 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3246 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003247 TestTransportInfo(false, options, true);
3248}
3249
3250TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3251 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003252 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3253 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3254 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003255 options.bundle_enabled = true;
3256 TestTransportInfo(false, options, false);
3257}
3258
3259TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003260 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003261 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003262 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3263 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3264 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003265 options.bundle_enabled = true;
3266 TestTransportInfo(false, options, true);
3267}
3268
3269// Create an offer with bundle enabled and verify the crypto parameters are
3270// the common set of the available cryptos.
3271TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3272 TestCryptoWithBundle(true);
3273}
3274
3275// Create an answer with bundle enabled and verify the crypto parameters are
3276// the common set of the available cryptos.
3277TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3278 TestCryptoWithBundle(false);
3279}
3280
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003281// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3282// DTLS is not enabled locally.
3283TEST_F(MediaSessionDescriptionFactoryTest,
3284 TestOfferDtlsSavpfWithoutDtlsFailed) {
3285 f1_.set_secure(SEC_ENABLED);
3286 f2_.set_secure(SEC_ENABLED);
3287 tdf1_.set_secure(SEC_DISABLED);
3288 tdf2_.set_secure(SEC_DISABLED);
3289
Steve Anton6fe1fba2018-12-11 10:15:23 -08003290 std::unique_ptr<SessionDescription> offer =
3291 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003292 ASSERT_TRUE(offer.get() != NULL);
3293 ContentInfo* offer_content = offer->GetContentByName("audio");
3294 ASSERT_TRUE(offer_content != NULL);
3295 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003296 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003297 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3298
Steve Anton6fe1fba2018-12-11 10:15:23 -08003299 std::unique_ptr<SessionDescription> answer =
3300 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003301 ASSERT_TRUE(answer != NULL);
3302 ContentInfo* answer_content = answer->GetContentByName("audio");
3303 ASSERT_TRUE(answer_content != NULL);
3304
3305 ASSERT_TRUE(answer_content->rejected);
3306}
3307
3308// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3309// UDP/TLS/RTP/SAVPF.
3310TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3311 f1_.set_secure(SEC_ENABLED);
3312 f2_.set_secure(SEC_ENABLED);
3313 tdf1_.set_secure(SEC_ENABLED);
3314 tdf2_.set_secure(SEC_ENABLED);
3315
Steve Anton6fe1fba2018-12-11 10:15:23 -08003316 std::unique_ptr<SessionDescription> offer =
3317 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003318 ASSERT_TRUE(offer.get() != NULL);
3319 ContentInfo* offer_content = offer->GetContentByName("audio");
3320 ASSERT_TRUE(offer_content != NULL);
3321 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003322 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003323 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3324
Steve Anton6fe1fba2018-12-11 10:15:23 -08003325 std::unique_ptr<SessionDescription> answer =
3326 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003327 ASSERT_TRUE(answer != NULL);
3328
3329 const ContentInfo* answer_content = answer->GetContentByName("audio");
3330 ASSERT_TRUE(answer_content != NULL);
3331 ASSERT_FALSE(answer_content->rejected);
3332
3333 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003334 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003335 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003336}
3337
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003338// Test that we include both SDES and DTLS in the offer, but only include SDES
3339// in the answer if DTLS isn't negotiated.
3340TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3341 f1_.set_secure(SEC_ENABLED);
3342 f2_.set_secure(SEC_ENABLED);
3343 tdf1_.set_secure(SEC_ENABLED);
3344 tdf2_.set_secure(SEC_DISABLED);
3345 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003346 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003347 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003348 const cricket::MediaContentDescription* audio_media_desc;
3349 const cricket::MediaContentDescription* video_media_desc;
3350 const cricket::TransportDescription* audio_trans_desc;
3351 const cricket::TransportDescription* video_trans_desc;
3352
3353 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003354 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003355 ASSERT_TRUE(offer.get() != NULL);
3356
Steve Antonb1c1de12017-12-21 15:14:30 -08003357 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003358 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003359 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003360 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003361 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003362 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3363
3364 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3365 ASSERT_TRUE(audio_trans_desc != NULL);
3366 video_trans_desc = offer->GetTransportDescriptionByName("video");
3367 ASSERT_TRUE(video_trans_desc != NULL);
3368 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3369 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3370
3371 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003372 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003373 ASSERT_TRUE(answer.get() != NULL);
3374
Steve Antonb1c1de12017-12-21 15:14:30 -08003375 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003376 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003377 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003378 ASSERT_TRUE(video_media_desc != NULL);
3379 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3380 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3381
3382 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3383 ASSERT_TRUE(audio_trans_desc != NULL);
3384 video_trans_desc = answer->GetTransportDescriptionByName("video");
3385 ASSERT_TRUE(video_trans_desc != NULL);
3386 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3387 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3388
3389 // Enable DTLS; the answer should now only have DTLS support.
3390 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003391 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003392 ASSERT_TRUE(answer.get() != NULL);
3393
Steve Antonb1c1de12017-12-21 15:14:30 -08003394 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003395 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003396 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003397 ASSERT_TRUE(video_media_desc != NULL);
3398 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3399 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003400 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3401 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003402
3403 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3404 ASSERT_TRUE(audio_trans_desc != NULL);
3405 video_trans_desc = answer->GetTransportDescriptionByName("video");
3406 ASSERT_TRUE(video_trans_desc != NULL);
3407 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3408 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003409
3410 // Try creating offer again. DTLS enabled now, crypto's should be empty
3411 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003412 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003413 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003414 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003415 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003416 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003417 ASSERT_TRUE(video_media_desc != NULL);
3418 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3419 EXPECT_TRUE(video_media_desc->cryptos().empty());
3420
3421 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3422 ASSERT_TRUE(audio_trans_desc != NULL);
3423 video_trans_desc = offer->GetTransportDescriptionByName("video");
3424 ASSERT_TRUE(video_trans_desc != NULL);
3425 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3426 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003427}
3428
3429// Test that an answer can't be created if cryptos are required but the offer is
3430// unsecure.
3431TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003432 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003433 f1_.set_secure(SEC_DISABLED);
3434 tdf1_.set_secure(SEC_DISABLED);
3435 f2_.set_secure(SEC_REQUIRED);
3436 tdf1_.set_secure(SEC_ENABLED);
3437
Steve Anton6fe1fba2018-12-11 10:15:23 -08003438 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003439 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003440 std::unique_ptr<SessionDescription> answer =
3441 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003442 EXPECT_TRUE(answer.get() == NULL);
3443}
3444
3445// Test that we accept a DTLS offer without SDES and create an appropriate
3446// answer.
3447TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3448 f1_.set_secure(SEC_DISABLED);
3449 f2_.set_secure(SEC_ENABLED);
3450 tdf1_.set_secure(SEC_ENABLED);
3451 tdf2_.set_secure(SEC_ENABLED);
3452 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003453 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3454 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3455 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003456
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003457 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003458 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003459 ASSERT_TRUE(offer.get() != NULL);
3460
3461 const AudioContentDescription* audio_offer =
3462 GetFirstAudioContentDescription(offer.get());
3463 ASSERT_TRUE(audio_offer->cryptos().empty());
3464 const VideoContentDescription* video_offer =
3465 GetFirstVideoContentDescription(offer.get());
3466 ASSERT_TRUE(video_offer->cryptos().empty());
3467 const DataContentDescription* data_offer =
3468 GetFirstDataContentDescription(offer.get());
3469 ASSERT_TRUE(data_offer->cryptos().empty());
3470
3471 const cricket::TransportDescription* audio_offer_trans_desc =
3472 offer->GetTransportDescriptionByName("audio");
3473 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3474 const cricket::TransportDescription* video_offer_trans_desc =
3475 offer->GetTransportDescriptionByName("video");
3476 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3477 const cricket::TransportDescription* data_offer_trans_desc =
3478 offer->GetTransportDescriptionByName("data");
3479 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3480
3481 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003482 std::unique_ptr<SessionDescription> answer =
3483 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003484 ASSERT_TRUE(answer.get() != NULL);
3485
3486 const cricket::TransportDescription* audio_answer_trans_desc =
3487 answer->GetTransportDescriptionByName("audio");
3488 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3489 const cricket::TransportDescription* video_answer_trans_desc =
3490 answer->GetTransportDescriptionByName("video");
3491 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3492 const cricket::TransportDescription* data_answer_trans_desc =
3493 answer->GetTransportDescriptionByName("data");
3494 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3495}
3496
3497// Verifies if vad_enabled option is set to false, CN codecs are not present in
3498// offer or answer.
3499TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3500 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003501 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003502 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003503 ASSERT_TRUE(offer.get() != NULL);
3504 const ContentInfo* audio_content = offer->GetContentByName("audio");
3505 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3506
3507 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003508 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003509 ASSERT_TRUE(offer.get() != NULL);
3510 audio_content = offer->GetContentByName("audio");
3511 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003512 std::unique_ptr<SessionDescription> answer =
3513 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003514 ASSERT_TRUE(answer.get() != NULL);
3515 audio_content = answer->GetContentByName("audio");
3516 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3517}
deadbeef44f08192015-12-15 16:20:09 -08003518
zhihuang1c378ed2017-08-17 14:10:50 -07003519// Test that the generated MIDs match the existing offer.
3520TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003521 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003522 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3523 RtpTransceiverDirection::kRecvOnly, kActive,
3524 &opts);
3525 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3526 RtpTransceiverDirection::kRecvOnly, kActive,
3527 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003528 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003529 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3530 RtpTransceiverDirection::kSendRecv, kActive,
3531 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003532 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003533 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003534 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003535 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003536
deadbeef44f08192015-12-15 16:20:09 -08003537 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3538 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3539 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3540 ASSERT_TRUE(audio_content != nullptr);
3541 ASSERT_TRUE(video_content != nullptr);
3542 ASSERT_TRUE(data_content != nullptr);
3543 EXPECT_EQ("audio_modified", audio_content->name);
3544 EXPECT_EQ("video_modified", video_content->name);
3545 EXPECT_EQ("data_modified", data_content->name);
3546}
zhihuangcf5b37c2016-05-05 11:44:35 -07003547
zhihuang1c378ed2017-08-17 14:10:50 -07003548// The following tests verify that the unified plan SDP is supported.
3549// Test that we can create an offer with multiple media sections of same media
3550// type.
3551TEST_F(MediaSessionDescriptionFactoryTest,
3552 CreateOfferWithMultipleAVMediaSections) {
3553 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003554 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3555 RtpTransceiverDirection::kSendRecv, kActive,
3556 &opts);
3557 AttachSenderToMediaDescriptionOptions(
3558 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003559
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003560 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3561 RtpTransceiverDirection::kSendRecv, kActive,
3562 &opts);
3563 AttachSenderToMediaDescriptionOptions(
3564 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003565
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003566 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3567 RtpTransceiverDirection::kSendRecv, kActive,
3568 &opts);
3569 AttachSenderToMediaDescriptionOptions(
3570 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003571
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003572 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3573 RtpTransceiverDirection::kSendRecv, kActive,
3574 &opts);
3575 AttachSenderToMediaDescriptionOptions(
3576 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003577 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003578 ASSERT_TRUE(offer);
3579
3580 ASSERT_EQ(4u, offer->contents().size());
3581 EXPECT_FALSE(offer->contents()[0].rejected);
3582 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003583 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003584 ASSERT_EQ(1u, acd->streams().size());
3585 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003586 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003587
3588 EXPECT_FALSE(offer->contents()[1].rejected);
3589 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003590 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003591 ASSERT_EQ(1u, vcd->streams().size());
3592 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003593 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003594
3595 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003596 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003597 ASSERT_EQ(1u, acd->streams().size());
3598 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003599 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003600
3601 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003602 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003603 ASSERT_EQ(1u, vcd->streams().size());
3604 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003605 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003606}
3607
3608// Test that we can create an answer with multiple media sections of same media
3609// type.
3610TEST_F(MediaSessionDescriptionFactoryTest,
3611 CreateAnswerWithMultipleAVMediaSections) {
3612 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003613 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3614 RtpTransceiverDirection::kSendRecv, kActive,
3615 &opts);
3616 AttachSenderToMediaDescriptionOptions(
3617 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003618
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003619 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3620 RtpTransceiverDirection::kSendRecv, kActive,
3621 &opts);
3622 AttachSenderToMediaDescriptionOptions(
3623 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003624
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003625 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3626 RtpTransceiverDirection::kSendRecv, kActive,
3627 &opts);
3628 AttachSenderToMediaDescriptionOptions(
3629 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003630
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003631 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3632 RtpTransceiverDirection::kSendRecv, kActive,
3633 &opts);
3634 AttachSenderToMediaDescriptionOptions(
3635 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003636
Steve Anton6fe1fba2018-12-11 10:15:23 -08003637 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003638 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003639 std::unique_ptr<SessionDescription> answer =
3640 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003641
3642 ASSERT_EQ(4u, answer->contents().size());
3643 EXPECT_FALSE(answer->contents()[0].rejected);
3644 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003645 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003646 ASSERT_EQ(1u, acd->streams().size());
3647 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003648 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003649
3650 EXPECT_FALSE(answer->contents()[1].rejected);
3651 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003652 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003653 ASSERT_EQ(1u, vcd->streams().size());
3654 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003655 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003656
3657 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003658 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003659 ASSERT_EQ(1u, acd->streams().size());
3660 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003661 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003662
3663 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003664 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003665 ASSERT_EQ(1u, vcd->streams().size());
3666 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003667 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003668}
3669
3670// Test that the media section will be rejected in offer if the corresponding
3671// MediaDescriptionOptions is stopped by the offerer.
3672TEST_F(MediaSessionDescriptionFactoryTest,
3673 CreateOfferWithMediaSectionStoppedByOfferer) {
3674 // Create an offer with two audio sections and one of them is stopped.
3675 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003676 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3677 RtpTransceiverDirection::kSendRecv, kActive,
3678 &offer_opts);
3679 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3680 RtpTransceiverDirection::kInactive, kStopped,
3681 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003682 std::unique_ptr<SessionDescription> offer =
3683 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003684 ASSERT_TRUE(offer);
3685 ASSERT_EQ(2u, offer->contents().size());
3686 EXPECT_FALSE(offer->contents()[0].rejected);
3687 EXPECT_TRUE(offer->contents()[1].rejected);
3688}
3689
3690// Test that the media section will be rejected in answer if the corresponding
3691// MediaDescriptionOptions is stopped by the offerer.
3692TEST_F(MediaSessionDescriptionFactoryTest,
3693 CreateAnswerWithMediaSectionStoppedByOfferer) {
3694 // Create an offer with two audio sections and one of them is stopped.
3695 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003696 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3697 RtpTransceiverDirection::kSendRecv, kActive,
3698 &offer_opts);
3699 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3700 RtpTransceiverDirection::kInactive, kStopped,
3701 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003702 std::unique_ptr<SessionDescription> offer =
3703 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003704 ASSERT_TRUE(offer);
3705 ASSERT_EQ(2u, offer->contents().size());
3706 EXPECT_FALSE(offer->contents()[0].rejected);
3707 EXPECT_TRUE(offer->contents()[1].rejected);
3708
3709 // Create an answer based on the offer.
3710 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003711 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3712 RtpTransceiverDirection::kSendRecv, kActive,
3713 &answer_opts);
3714 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3715 RtpTransceiverDirection::kSendRecv, kActive,
3716 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003717 std::unique_ptr<SessionDescription> answer =
3718 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003719 ASSERT_EQ(2u, answer->contents().size());
3720 EXPECT_FALSE(answer->contents()[0].rejected);
3721 EXPECT_TRUE(answer->contents()[1].rejected);
3722}
3723
3724// Test that the media section will be rejected in answer if the corresponding
3725// MediaDescriptionOptions is stopped by the answerer.
3726TEST_F(MediaSessionDescriptionFactoryTest,
3727 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3728 // Create an offer with two audio sections.
3729 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003730 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3731 RtpTransceiverDirection::kSendRecv, kActive,
3732 &offer_opts);
3733 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3734 RtpTransceiverDirection::kSendRecv, kActive,
3735 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003736 std::unique_ptr<SessionDescription> offer =
3737 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003738 ASSERT_TRUE(offer);
3739 ASSERT_EQ(2u, offer->contents().size());
3740 ASSERT_FALSE(offer->contents()[0].rejected);
3741 ASSERT_FALSE(offer->contents()[1].rejected);
3742
3743 // The answerer rejects one of the audio sections.
3744 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003745 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3746 RtpTransceiverDirection::kSendRecv, kActive,
3747 &answer_opts);
3748 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3749 RtpTransceiverDirection::kInactive, kStopped,
3750 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003751 std::unique_ptr<SessionDescription> answer =
3752 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003753 ASSERT_EQ(2u, answer->contents().size());
3754 EXPECT_FALSE(answer->contents()[0].rejected);
3755 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003756
3757 // The TransportInfo of the rejected m= section is expected to be added in the
3758 // answer.
3759 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003760}
3761
3762// Test the generated media sections has the same order of the
3763// corresponding MediaDescriptionOptions.
3764TEST_F(MediaSessionDescriptionFactoryTest,
3765 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3766 MediaSessionOptions opts;
3767 // This tests put video section first because normally audio comes first by
3768 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003769 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3770 RtpTransceiverDirection::kSendRecv, kActive,
3771 &opts);
3772 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3773 RtpTransceiverDirection::kSendRecv, kActive,
3774 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003776
3777 ASSERT_TRUE(offer);
3778 ASSERT_EQ(2u, offer->contents().size());
3779 EXPECT_EQ("video", offer->contents()[0].name);
3780 EXPECT_EQ("audio", offer->contents()[1].name);
3781}
3782
3783// Test that different media sections using the same codec have same payload
3784// type.
3785TEST_F(MediaSessionDescriptionFactoryTest,
3786 PayloadTypesSharedByMediaSectionsOfSameType) {
3787 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003788 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3789 RtpTransceiverDirection::kSendRecv, kActive,
3790 &opts);
3791 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3792 RtpTransceiverDirection::kSendRecv, kActive,
3793 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003794 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003795 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003796 ASSERT_TRUE(offer);
3797 ASSERT_EQ(2u, offer->contents().size());
3798 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003799 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003800 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003801 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003802 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3803 ASSERT_EQ(2u, vcd1->codecs().size());
3804 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3805 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3806 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3807 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3808
3809 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003810 std::unique_ptr<SessionDescription> answer =
3811 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003812 ASSERT_TRUE(answer);
3813 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003814 vcd1 = answer->contents()[0].media_description()->as_video();
3815 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003816 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3817 ASSERT_EQ(1u, vcd1->codecs().size());
3818 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3819 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3820}
3821
3822// Test that the codec preference order per media section is respected in
3823// subsequent offer.
3824TEST_F(MediaSessionDescriptionFactoryTest,
3825 CreateOfferRespectsCodecPreferenceOrder) {
3826 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003827 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3828 RtpTransceiverDirection::kSendRecv, kActive,
3829 &opts);
3830 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3831 RtpTransceiverDirection::kSendRecv, kActive,
3832 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003833 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003834 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003835 ASSERT_TRUE(offer);
3836 ASSERT_EQ(2u, offer->contents().size());
3837 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003838 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003839 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003840 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003841 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3842 EXPECT_EQ(video_codecs, vcd1->codecs());
3843 EXPECT_EQ(video_codecs, vcd2->codecs());
3844
3845 // Change the codec preference of the first video section and create a
3846 // follow-up offer.
3847 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3848 vcd1->set_codecs(video_codecs_reverse);
3849 std::unique_ptr<SessionDescription> updated_offer(
3850 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003851 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3852 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003853 // The video codec preference order should be respected.
3854 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3855 EXPECT_EQ(video_codecs, vcd2->codecs());
3856}
3857
3858// Test that the codec preference order per media section is respected in
3859// the answer.
3860TEST_F(MediaSessionDescriptionFactoryTest,
3861 CreateAnswerRespectsCodecPreferenceOrder) {
3862 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003863 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3864 RtpTransceiverDirection::kSendRecv, kActive,
3865 &opts);
3866 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3867 RtpTransceiverDirection::kSendRecv, kActive,
3868 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003869 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003870 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003871 ASSERT_TRUE(offer);
3872 ASSERT_EQ(2u, offer->contents().size());
3873 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003874 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003875 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003876 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003877 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3878 EXPECT_EQ(video_codecs, vcd1->codecs());
3879 EXPECT_EQ(video_codecs, vcd2->codecs());
3880
3881 // Change the codec preference of the first video section and create an
3882 // answer.
3883 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3884 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003885 std::unique_ptr<SessionDescription> answer =
3886 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003887 vcd1 = answer->contents()[0].media_description()->as_video();
3888 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003889 // The video codec preference order should be respected.
3890 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3891 EXPECT_EQ(video_codecs, vcd2->codecs());
3892}
3893
Zhi Huang6f367472017-11-22 13:20:02 -08003894// Test that when creating an answer, the codecs use local parameters instead of
3895// the remote ones.
3896TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3897 const std::string audio_param_name = "audio_param";
3898 const std::string audio_value1 = "audio_v1";
3899 const std::string audio_value2 = "audio_v2";
3900 const std::string video_param_name = "video_param";
3901 const std::string video_value1 = "video_v1";
3902 const std::string video_value2 = "video_v2";
3903
3904 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3905 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3906 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3907 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3908
3909 // Set the parameters for codecs.
3910 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3911 video_codecs1[0].SetParam(video_param_name, video_value1);
3912 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3913 video_codecs2[0].SetParam(video_param_name, video_value2);
3914
3915 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3916 f1_.set_video_codecs(video_codecs1);
3917 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3918 f2_.set_video_codecs(video_codecs2);
3919
3920 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003921 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3922 RtpTransceiverDirection::kSendRecv, kActive,
3923 &opts);
3924 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3925 RtpTransceiverDirection::kSendRecv, kActive,
3926 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003927
Steve Anton6fe1fba2018-12-11 10:15:23 -08003928 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003929 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003930 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3931 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003932 std::string value;
3933 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3934 EXPECT_EQ(audio_value1, value);
3935 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3936 EXPECT_EQ(video_value1, value);
3937
Steve Anton6fe1fba2018-12-11 10:15:23 -08003938 std::unique_ptr<SessionDescription> answer =
3939 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003940 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003941 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3942 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003943 // Use the parameters from the local codecs.
3944 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3945 EXPECT_EQ(audio_value2, value);
3946 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3947 EXPECT_EQ(video_value2, value);
3948}
3949
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003950// Test that matching packetization-mode is part of the criteria for matching
3951// H264 codecs (in addition to profile-level-id). Previously, this was not the
3952// case, so the first H264 codec with the same profile-level-id would match and
3953// the payload type in the answer would be incorrect.
3954// This is a regression test for bugs.webrtc.org/8808
3955TEST_F(MediaSessionDescriptionFactoryTest,
3956 H264MatchCriteriaIncludesPacketizationMode) {
3957 // Create two H264 codecs with the same profile level ID and different
3958 // packetization modes.
3959 VideoCodec h264_pm0(96, "H264");
3960 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3961 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3962 VideoCodec h264_pm1(97, "H264");
3963 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3964 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3965
3966 // Offerer will send both codecs, answerer should choose the one with matching
3967 // packetization mode (and not the first one it sees).
3968 f1_.set_video_codecs({h264_pm0, h264_pm1});
3969 f2_.set_video_codecs({h264_pm1});
3970
3971 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003972 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3973 RtpTransceiverDirection::kSendRecv, kActive,
3974 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003975
Steve Anton6fe1fba2018-12-11 10:15:23 -08003976 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003977 ASSERT_TRUE(offer);
3978
Steve Anton6fe1fba2018-12-11 10:15:23 -08003979 std::unique_ptr<SessionDescription> answer =
3980 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003981 ASSERT_TRUE(answer);
3982
3983 // Answer should have one negotiated codec with packetization-mode=1 using the
3984 // offered payload type.
3985 ASSERT_EQ(1u, answer->contents().size());
3986 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3987 ASSERT_EQ(1u, answer_vcd->codecs().size());
3988 auto answer_codec = answer_vcd->codecs()[0];
3989 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3990}
3991
zhihuangcf5b37c2016-05-05 11:44:35 -07003992class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3993 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08003994 MediaProtocolTest()
3995 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07003996 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3997 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003998 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3999 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004000 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4001 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004002 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
4003 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
4004 f1_.set_secure(SEC_ENABLED);
4005 f2_.set_secure(SEC_ENABLED);
4006 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004007 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004008 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004009 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004010 tdf1_.set_secure(SEC_ENABLED);
4011 tdf2_.set_secure(SEC_ENABLED);
4012 }
4013
4014 protected:
4015 MediaSessionDescriptionFactory f1_;
4016 MediaSessionDescriptionFactory f2_;
4017 TransportDescriptionFactory tdf1_;
4018 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004019 UniqueRandomIdGenerator ssrc_generator1;
4020 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004021};
4022
4023TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4024 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004025 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004026 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004027 ASSERT_TRUE(offer.get() != nullptr);
4028 // Set the protocol for all the contents.
4029 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004030 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004031 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004032 std::unique_ptr<SessionDescription> answer =
4033 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004034 const ContentInfo* ac = answer->GetContentByName("audio");
4035 const ContentInfo* vc = answer->GetContentByName("video");
4036 ASSERT_TRUE(ac != nullptr);
4037 ASSERT_TRUE(vc != nullptr);
4038 EXPECT_FALSE(ac->rejected); // the offer is accepted
4039 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004040 const AudioContentDescription* acd = ac->media_description()->as_audio();
4041 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004042 EXPECT_EQ(GetParam(), acd->protocol());
4043 EXPECT_EQ(GetParam(), vcd->protocol());
4044}
4045
4046INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
4047 MediaProtocolTest,
4048 ::testing::ValuesIn(kMediaProtocols));
4049INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
4050 MediaProtocolTest,
4051 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004052
4053TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4054 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004055 UniqueRandomIdGenerator ssrc_generator;
4056 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004057 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4058 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4059
4060 // The merged list of codecs should contain any send codecs that are also
4061 // nominally in the recieve codecs list. Payload types should be picked from
4062 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4063 // (set to 1). This equals what happens when the send codecs are used in an
4064 // offer and the receive codecs are used in the following answer.
4065 const std::vector<AudioCodec> sendrecv_codecs =
4066 MAKE_VECTOR(kAudioCodecsAnswer);
4067 const std::vector<AudioCodec> no_codecs;
4068
4069 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4070 << "Please don't change shared test data!";
4071 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4072 << "Please don't change shared test data!";
4073 // Alter iLBC send codec to have zero channels, to test that that is handled
4074 // properly.
4075 send_codecs[1].channels = 0;
4076
4077 // Alther iLBC receive codec to be lowercase, to test that case conversions
4078 // are handled properly.
4079 recv_codecs[2].name = "ilbc";
4080
4081 // Test proper merge
4082 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004083 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4084 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4085 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004086
4087 // Test empty send codecs list
4088 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004089 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4090 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4091 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004092
4093 // Test empty recv codecs list
4094 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004095 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4096 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4097 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004098
4099 // Test all empty codec lists
4100 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004101 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4102 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4103 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004104}
4105
Amit Hilbuch77938e62018-12-21 09:23:38 -08004106// Checks that the RID extensions are added to the video RTP header extensions.
4107// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4108// not very well defined, as calling set() and immediately get() will yield
4109// an object that is not semantically equivalent to the set object.
4110TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4111 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004112 UniqueRandomIdGenerator ssrc_generator;
4113 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004114 sf.set_is_unified_plan(true);
4115 cricket::RtpHeaderExtensions extensions;
4116 sf.set_video_rtp_header_extensions(extensions);
4117 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4118 // Check to see that RID extensions were added to the extension list
4119 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004120 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4121 RtpExtension::kRidUri)));
4122 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4123 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004124}
4125
4126// Checks that the RID extensions are added to the audio RTP header extensions.
4127// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4128// not very well defined, as calling set() and immediately get() will yield
4129// an object that is not semantically equivalent to the set object.
4130TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4131 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004132 UniqueRandomIdGenerator ssrc_generator;
4133 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004134 sf.set_is_unified_plan(true);
4135 cricket::RtpHeaderExtensions extensions;
4136 sf.set_audio_rtp_header_extensions(extensions);
4137 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4138 // Check to see that RID extensions were added to the extension list
4139 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004140 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4141 RtpExtension::kRidUri)));
4142 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4143 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004144}
4145
ossu075af922016-06-14 03:29:38 -07004146namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004147// Compare the two vectors of codecs ignoring the payload type.
4148template <class Codec>
4149bool CodecsMatch(const std::vector<Codec>& codecs1,
4150 const std::vector<Codec>& codecs2) {
4151 if (codecs1.size() != codecs2.size()) {
4152 return false;
4153 }
4154
4155 for (size_t i = 0; i < codecs1.size(); ++i) {
4156 if (!codecs1[i].Matches(codecs2[i])) {
4157 return false;
4158 }
4159 }
4160 return true;
4161}
4162
Steve Anton4e70a722017-11-28 14:57:10 -08004163void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004164 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004165 UniqueRandomIdGenerator ssrc_generator;
4166 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004167 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4168 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4169 const std::vector<AudioCodec> sendrecv_codecs =
4170 MAKE_VECTOR(kAudioCodecsAnswer);
4171 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004172
4173 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004174 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4175 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004176
Steve Anton4e70a722017-11-28 14:57:10 -08004177 if (direction == RtpTransceiverDirection::kSendRecv ||
4178 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004179 AttachSenderToMediaDescriptionOptions(
4180 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004181 }
ossu075af922016-06-14 03:29:38 -07004182
Steve Anton6fe1fba2018-12-11 10:15:23 -08004183 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004184 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004185 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004186
4187 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004188 // that the codecs put in are right. This happens when we neither want to
4189 // send nor receive audio. The checks are still in place if at some point
4190 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004191 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004192 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004193 // sendrecv and inactive should both present lists as if the channel was
4194 // to be used for sending and receiving. Inactive essentially means it
4195 // might eventually be used anything, but we don't know more at this
4196 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004197 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004198 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004199 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004200 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004201 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004202 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004203 }
4204 }
4205}
4206
4207static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004208 AudioCodec(0, "codec0", 16000, -1, 1),
4209 AudioCodec(1, "codec1", 8000, 13300, 1),
4210 AudioCodec(2, "codec2", 8000, 64000, 1),
4211 AudioCodec(3, "codec3", 8000, 64000, 1),
4212 AudioCodec(4, "codec4", 8000, 0, 2),
4213 AudioCodec(5, "codec5", 32000, 0, 1),
4214 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004215
zhihuang1c378ed2017-08-17 14:10:50 -07004216/* The codecs groups below are chosen as per the matrix below. The objective
4217 * is to have different sets of codecs in the inputs, to get unique sets of
4218 * codecs after negotiation, depending on offer and answer communication
4219 * directions. One-way directions in the offer should either result in the
4220 * opposite direction in the answer, or an inactive answer. Regardless, the
4221 * choice of codecs should be as if the answer contained the opposite
4222 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004223 *
4224 * | Offer | Answer | Result
4225 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4226 * 0 | x - - | - x - | x - - - -
4227 * 1 | x x x | - x - | x - - x -
4228 * 2 | - x - | x - - | - x - - -
4229 * 3 | x x x | x - - | - x x - -
4230 * 4 | - x - | x x x | - x - - -
4231 * 5 | x - - | x x x | x - - - -
4232 * 6 | x x x | x x x | x x x x x
4233 */
4234// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004235static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4236static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004237// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4238// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004239static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4240static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004241// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004242static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4243static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4244static const int kResultSendrecv_SendCodecs[] = {3, 6};
4245static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4246static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004247
4248template <typename T, int IDXS>
4249std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4250 std::vector<T> out;
4251 out.reserve(IDXS);
4252 for (int idx : indices)
4253 out.push_back(array[idx]);
4254
4255 return out;
4256}
4257
Steve Anton4e70a722017-11-28 14:57:10 -08004258void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4259 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004260 bool add_legacy_stream) {
4261 TransportDescriptionFactory offer_tdf;
4262 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004263 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4264 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4265 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004266 offer_factory.set_audio_codecs(
4267 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4268 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4269 answer_factory.set_audio_codecs(
4270 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4271 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4272
ossu075af922016-06-14 03:29:38 -07004273 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004274 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4275 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004276
Steve Anton4e70a722017-11-28 14:57:10 -08004277 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004278 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4279 kAudioTrack1, {kMediaStream1}, 1,
4280 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004281 }
4282
Steve Anton6fe1fba2018-12-11 10:15:23 -08004283 std::unique_ptr<SessionDescription> offer =
4284 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004285 ASSERT_TRUE(offer.get() != NULL);
4286
4287 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004288 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4289 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004290
Steve Anton4e70a722017-11-28 14:57:10 -08004291 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004292 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4293 kAudioTrack1, {kMediaStream1}, 1,
4294 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004295 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004296 std::unique_ptr<SessionDescription> answer =
4297 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004298 const ContentInfo* ac = answer->GetContentByName("audio");
4299
zhihuang1c378ed2017-08-17 14:10:50 -07004300 // If the factory didn't add any audio content to the answer, we cannot
4301 // check that the codecs put in are right. This happens when we neither want
4302 // to send nor receive audio. The checks are still in place if at some point
4303 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004304 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004305 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4306 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004307
ossu075af922016-06-14 03:29:38 -07004308 std::vector<AudioCodec> target_codecs;
4309 // For offers with sendrecv or inactive, we should never reply with more
4310 // codecs than offered, with these codec sets.
4311 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004312 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004313 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4314 kResultSendrecv_SendrecvCodecs);
4315 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004316 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004317 target_codecs =
4318 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004319 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004320 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004321 target_codecs =
4322 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004323 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004324 case RtpTransceiverDirection::kSendRecv:
4325 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004326 target_codecs =
4327 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004328 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004329 target_codecs =
4330 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004331 } else {
4332 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4333 kResultSendrecv_SendrecvCodecs);
4334 }
4335 break;
4336 }
4337
zhihuang1c378ed2017-08-17 14:10:50 -07004338 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004339 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004340 bool first = true;
4341 os << "{";
4342 for (const auto& c : codecs) {
4343 os << (first ? " " : ", ") << c.id;
4344 first = false;
4345 }
4346 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004347 return os.Release();
ossu075af922016-06-14 03:29:38 -07004348 };
4349
4350 EXPECT_TRUE(acd->codecs() == target_codecs)
4351 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004352 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4353 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004354 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004355 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4356 << "; got: "
4357 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004358 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004359 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004360 << "Only inactive offers are allowed to not generate any audio "
4361 "content";
ossu075af922016-06-14 03:29:38 -07004362 }
4363}
brandtr03d5fb12016-11-22 03:37:59 -08004364
4365} // namespace
ossu075af922016-06-14 03:29:38 -07004366
4367class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004368 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004369
4370TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004371 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004372}
4373
4374INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
4375 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004376 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4377 RtpTransceiverDirection::kRecvOnly,
4378 RtpTransceiverDirection::kSendRecv,
4379 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004380
4381class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004382 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4383 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004384 bool>> {};
ossu075af922016-06-14 03:29:38 -07004385
4386TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004387 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4388 ::testing::get<1>(GetParam()),
4389 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004390}
4391
zhihuang1c378ed2017-08-17 14:10:50 -07004392INSTANTIATE_TEST_CASE_P(
4393 MediaSessionDescriptionFactoryTest,
4394 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004395 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4396 RtpTransceiverDirection::kRecvOnly,
4397 RtpTransceiverDirection::kSendRecv,
4398 RtpTransceiverDirection::kInactive),
4399 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4400 RtpTransceiverDirection::kRecvOnly,
4401 RtpTransceiverDirection::kSendRecv,
4402 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004403 ::testing::Bool()));