blob: 16be74f6641e104c5ff5ef6a3c9cc477a550ba5d [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 Anton6fe1fba2018-12-11 10:15:23 -080016#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "media/base/codec.h"
18#include "media/base/testutils.h"
19#include "p2p/base/p2pconstants.h"
20#include "p2p/base/transportdescription.h"
21#include "p2p/base/transportinfo.h"
22#include "pc/mediasession.h"
Steve Anton1d03a752017-11-27 14:30:09 -080023#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "pc/srtpfilter.h"
25#include "rtc_base/checks.h"
26#include "rtc_base/fakesslidentity.h"
27#include "rtc_base/gunit.h"
28#include "rtc_base/messagedigest.h"
29#include "rtc_base/ssladapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020030#include "rtc_base/strings/string_builder.h"
Steve Antone38a5a12018-11-21 16:05:15 -080031#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032
Yves Gerey665174f2018-06-19 15:03:05 +020033#define ASSERT_CRYPTO(cd, s, cs) \
34 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080035 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036
37typedef std::vector<cricket::Candidate> Candidates;
38
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080039using cricket::AudioCodec;
40using cricket::AudioContentDescription;
41using cricket::ContentInfo;
42using cricket::CryptoParamsVec;
43using cricket::DataCodec;
44using cricket::DataContentDescription;
45using cricket::GetFirstAudioContent;
46using cricket::GetFirstAudioContentDescription;
47using cricket::GetFirstDataContent;
48using cricket::GetFirstDataContentDescription;
49using cricket::GetFirstVideoContent;
50using cricket::GetFirstVideoContentDescription;
51using cricket::kAutoBandwidth;
52using cricket::MEDIA_TYPE_AUDIO;
53using cricket::MEDIA_TYPE_DATA;
54using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070056using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080057using cricket::MediaProtocolType;
58using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059using cricket::MediaSessionOptions;
60using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080061using cricket::RidDescription;
62using cricket::RidDirection;
63using cricket::SEC_DISABLED;
64using cricket::SEC_ENABLED;
65using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080067using cricket::SimulcastDescription;
68using cricket::SimulcastLayer;
69using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070using cricket::SsrcGroup;
71using cricket::StreamParams;
72using cricket::StreamParamsVec;
73using cricket::TransportDescription;
74using cricket::TransportDescriptionFactory;
75using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080077using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070078using rtc::CS_AEAD_AES_128_GCM;
79using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080080using rtc::CS_AES_CM_128_HMAC_SHA1_32;
81using rtc::CS_AES_CM_128_HMAC_SHA1_80;
82using testing::Each;
Steve Antone38a5a12018-11-21 16:05:15 -080083using testing::ElementsAreArray;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080084using testing::Eq;
85using testing::Field;
86using testing::IsEmpty;
87using testing::IsFalse;
88using testing::Ne;
89using testing::Pointwise;
90using testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070091using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080092using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093
94static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070095 AudioCodec(103, "ISAC", 16000, -1, 1),
96 AudioCodec(102, "iLBC", 8000, 13300, 1),
97 AudioCodec(0, "PCMU", 8000, 64000, 1),
98 AudioCodec(8, "PCMA", 8000, 64000, 1),
99 AudioCodec(117, "red", 8000, 0, 1),
100 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101
102static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200103 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700104 AudioCodec(0, "PCMU", 8000, 64000, 1),
105 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106};
107
108static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700109 AudioCodec(102, "iLBC", 8000, 13300, 1),
110 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111};
112
perkj26752742016-10-24 01:21:16 -0700113static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
114 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115
zhihuang1c378ed2017-08-17 14:10:50 -0700116static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
117 VideoCodec(96, "H264-SVC")};
118
perkj26752742016-10-24 01:21:16 -0700119static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
120 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121
perkj26752742016-10-24 01:21:16 -0700122static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123
deadbeef67cf2c12016-04-13 10:07:16 -0700124static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
125 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126
deadbeef67cf2c12016-04-13 10:07:16 -0700127static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
128 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000129
deadbeef67cf2c12016-04-13 10:07:16 -0700130static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
131 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132
isheriff6f8d6862016-05-26 11:24:55 -0700133static const RtpExtension kAudioRtpExtension1[] = {
134 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
135 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136};
137
jbauch5869f502017-06-29 12:31:36 -0700138static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
139 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
140 RtpExtension("http://google.com/testing/audio_something", 10),
141 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
142};
143
isheriff6f8d6862016-05-26 11:24:55 -0700144static const RtpExtension kAudioRtpExtension2[] = {
145 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
146 RtpExtension("http://google.com/testing/audio_something_else", 8),
147 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148};
149
isheriff6f8d6862016-05-26 11:24:55 -0700150static const RtpExtension kAudioRtpExtension3[] = {
151 RtpExtension("http://google.com/testing/audio_something", 2),
152 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700153};
154
jbauch5869f502017-06-29 12:31:36 -0700155static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
156 RtpExtension("http://google.com/testing/audio_something", 2),
157 // Use RTP extension that supports encryption.
158 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
159};
160
161static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
164 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
165};
166
isheriff6f8d6862016-05-26 11:24:55 -0700167static const RtpExtension kAudioRtpExtensionAnswer[] = {
168 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000169};
170
jbauch5869f502017-06-29 12:31:36 -0700171static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
172 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
173};
174
isheriff6f8d6862016-05-26 11:24:55 -0700175static const RtpExtension kVideoRtpExtension1[] = {
176 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
177 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000178};
179
jbauch5869f502017-06-29 12:31:36 -0700180static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
181 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
182 RtpExtension("http://google.com/testing/video_something", 13),
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
184};
185
isheriff6f8d6862016-05-26 11:24:55 -0700186static const RtpExtension kVideoRtpExtension2[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
188 RtpExtension("http://google.com/testing/video_something_else", 14),
189 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190};
191
isheriff6f8d6862016-05-26 11:24:55 -0700192static const RtpExtension kVideoRtpExtension3[] = {
193 RtpExtension("http://google.com/testing/video_something", 4),
194 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700195};
196
jbauch5869f502017-06-29 12:31:36 -0700197static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
198 RtpExtension("http://google.com/testing/video_something", 4),
199 // Use RTP extension that supports encryption.
200 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
201};
202
isheriff6f8d6862016-05-26 11:24:55 -0700203static const RtpExtension kVideoRtpExtensionAnswer[] = {
204 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000205};
206
jbauch5869f502017-06-29 12:31:36 -0700207static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
208 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
209};
210
Peter Boström0c4e06b2015-10-07 12:23:21 +0200211static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
212static const uint32_t kSimSsrc[] = {10, 20, 30};
213static const uint32_t kFec1Ssrc[] = {10, 11};
214static const uint32_t kFec2Ssrc[] = {20, 21};
215static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216
217static const char kMediaStream1[] = "stream_1";
218static const char kMediaStream2[] = "stream_2";
219static const char kVideoTrack1[] = "video_1";
220static const char kVideoTrack2[] = "video_2";
221static const char kAudioTrack1[] = "audio_1";
222static const char kAudioTrack2[] = "audio_2";
223static const char kAudioTrack3[] = "audio_3";
224static const char kDataTrack1[] = "data_1";
225static const char kDataTrack2[] = "data_2";
226static const char kDataTrack3[] = "data_3";
227
zhihuangcf5b37c2016-05-05 11:44:35 -0700228static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
229 "RTP/SAVPF"};
230static const char* kMediaProtocolsDtls[] = {
231 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
232 "UDP/TLS/RTP/SAVP"};
233
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700234// SRTP cipher name negotiated by the tests. This must be updated if the
235// default changes.
236static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
237static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
238
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800239// These constants are used to make the code using "AddMediaDescriptionOptions"
240// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700241static constexpr bool kStopped = true;
242static constexpr bool kActive = false;
243
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000244static bool IsMediaContentOfType(const ContentInfo* content,
245 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800246 RTC_DCHECK(content);
247 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000248}
249
Steve Anton4e70a722017-11-28 14:57:10 -0800250static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800251 RTC_DCHECK(content);
252 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000253}
254
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000255static void AddRtxCodec(const VideoCodec& rtx_codec,
256 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800257 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000258 codecs->push_back(rtx_codec);
259}
260
261template <class T>
262static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
263 std::vector<std::string> codec_names;
264 for (const auto& codec : codecs) {
265 codec_names.push_back(codec.name);
266 }
267 return codec_names;
268}
269
zhihuang1c378ed2017-08-17 14:10:50 -0700270// This is used for test only. MIDs are not the identification of the
271// MediaDescriptionOptions since some end points may not support MID and the SDP
272// may not contain 'mid'.
273std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
274 const std::string& mid,
275 MediaSessionOptions* opts) {
276 return std::find_if(
277 opts->media_description_options.begin(),
278 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700279 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
280}
281
282std::vector<MediaDescriptionOptions>::const_iterator
283FindFirstMediaDescriptionByMid(const std::string& mid,
284 const MediaSessionOptions& opts) {
285 return std::find_if(
286 opts.media_description_options.begin(),
287 opts.media_description_options.end(),
288 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700289}
290
291// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800292static void AddMediaDescriptionOptions(MediaType type,
293 const std::string& mid,
294 RtpTransceiverDirection direction,
295 bool stopped,
296 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800297 opts->media_description_options.push_back(
298 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700299}
300
Steve Anton4e70a722017-11-28 14:57:10 -0800301static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700302 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800303 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
304 opts);
305 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
306 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700307}
308
309static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800310 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700311 MediaSessionOptions* opts) {
312 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800313 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700314}
315
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800316static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700317 const std::string& mid,
318 MediaType type,
319 const std::string& track_id,
320 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800321 const std::vector<RidDescription>& rids,
322 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700323 int num_sim_layer,
324 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700325 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
326 switch (type) {
327 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700328 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700329 break;
330 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800331 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
332 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700333 break;
334 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700335 RTC_CHECK(stream_ids.size() == 1U);
336 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700337 break;
338 default:
339 RTC_NOTREACHED();
340 }
341}
342
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800343static void AttachSenderToMediaDescriptionOptions(
344 const std::string& mid,
345 MediaType type,
346 const std::string& track_id,
347 const std::vector<std::string>& stream_ids,
348 int num_sim_layer,
349 MediaSessionOptions* session_options) {
350 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
351 SimulcastLayerList(), num_sim_layer,
352 session_options);
353}
354
zhihuang1c378ed2017-08-17 14:10:50 -0700355static void DetachSenderFromMediaSection(const std::string& mid,
356 const std::string& track_id,
357 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700358 std::vector<cricket::SenderOptions>& sender_options_list =
359 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
360 auto sender_it =
361 std::find_if(sender_options_list.begin(), sender_options_list.end(),
362 [track_id](const cricket::SenderOptions& sender_options) {
363 return sender_options.track_id == track_id;
364 });
365 RTC_DCHECK(sender_it != sender_options_list.end());
366 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700367}
368
369// Helper function used to create a default MediaSessionOptions for Plan B SDP.
370// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
371static MediaSessionOptions CreatePlanBMediaSessionOptions() {
372 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800373 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
374 RtpTransceiverDirection::kRecvOnly, kActive,
375 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700376 return session_options;
377}
378
379// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
380// was designed for Plan B SDP, where only one audio "m=" section and one video
381// "m=" section could be generated, and ordering couldn't be controlled. Many of
382// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000383class MediaSessionDescriptionFactoryTest : public testing::Test {
384 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700385 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700386 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
387 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000388 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
389 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700390 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
391 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000392 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
393 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200394 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700395 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200396 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700397 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000398 }
399
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000400 // Create a video StreamParamsVec object with:
401 // - one video stream with 3 simulcast streams and FEC,
402 StreamParamsVec CreateComplexVideoStreamParamsVec() {
403 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
404 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
405 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
406 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
407
408 std::vector<SsrcGroup> ssrc_groups;
409 ssrc_groups.push_back(sim_group);
410 ssrc_groups.push_back(fec_group1);
411 ssrc_groups.push_back(fec_group2);
412 ssrc_groups.push_back(fec_group3);
413
414 StreamParams simulcast_params;
415 simulcast_params.id = kVideoTrack1;
416 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
417 simulcast_params.ssrc_groups = ssrc_groups;
418 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800419 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000420
421 StreamParamsVec video_streams;
422 video_streams.push_back(simulcast_params);
423
424 return video_streams;
425 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426
427 bool CompareCryptoParams(const CryptoParamsVec& c1,
428 const CryptoParamsVec& c2) {
429 if (c1.size() != c2.size())
430 return false;
431 for (size_t i = 0; i < c1.size(); ++i)
432 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
433 c1[i].key_params != c2[i].key_params ||
434 c1[i].session_params != c2[i].session_params)
435 return false;
436 return true;
437 }
438
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700439 // Returns true if the transport info contains "renomination" as an
440 // ICE option.
441 bool GetIceRenomination(const TransportInfo* transport_info) {
442 const std::vector<std::string>& ice_options =
443 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700444 auto iter =
445 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700446 return iter != ice_options.end();
447 }
448
zhihuang1c378ed2017-08-17 14:10:50 -0700449 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700450 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000451 bool has_current_desc) {
452 const std::string current_audio_ufrag = "current_audio_ufrag";
453 const std::string current_audio_pwd = "current_audio_pwd";
454 const std::string current_video_ufrag = "current_video_ufrag";
455 const std::string current_video_pwd = "current_video_pwd";
456 const std::string current_data_ufrag = "current_data_ufrag";
457 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800458 std::unique_ptr<SessionDescription> current_desc;
459 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800461 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800462 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200463 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800464 TransportDescription(current_audio_ufrag, current_audio_pwd)));
465 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200466 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800467 TransportDescription(current_video_ufrag, current_video_pwd)));
468 current_desc->AddTransportInfo(TransportInfo(
469 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000470 }
471 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800472 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 } else {
kwiberg31022942016-03-11 14:18:21 -0800474 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800475 offer = f1_.CreateOffer(options, NULL);
476 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000477 }
478 ASSERT_TRUE(desc.get() != NULL);
479 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000480 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481 EXPECT_TRUE(ti_audio != NULL);
482 if (has_current_desc) {
483 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
484 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
485 } else {
486 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
487 ti_audio->description.ice_ufrag.size());
488 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
489 ti_audio->description.ice_pwd.size());
490 }
zhihuang1c378ed2017-08-17 14:10:50 -0700491 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700492 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700493 EXPECT_EQ(
494 media_desc_options_it->transport_options.enable_ice_renomination,
495 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496
497 } else {
498 EXPECT_TRUE(ti_audio == NULL);
499 }
500 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000501 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 EXPECT_TRUE(ti_video != NULL);
503 if (options.bundle_enabled) {
504 EXPECT_EQ(ti_audio->description.ice_ufrag,
505 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200506 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 } else {
508 if (has_current_desc) {
509 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
510 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
511 } else {
512 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
513 ti_video->description.ice_ufrag.size());
514 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
515 ti_video->description.ice_pwd.size());
516 }
517 }
zhihuang1c378ed2017-08-17 14:10:50 -0700518 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700519 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700520 EXPECT_EQ(
521 media_desc_options_it->transport_options.enable_ice_renomination,
522 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000523 } else {
524 EXPECT_TRUE(ti_video == NULL);
525 }
526 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
527 if (options.has_data()) {
528 EXPECT_TRUE(ti_data != NULL);
529 if (options.bundle_enabled) {
530 EXPECT_EQ(ti_audio->description.ice_ufrag,
531 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200532 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 } else {
534 if (has_current_desc) {
535 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
536 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
537 } else {
538 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
539 ti_data->description.ice_ufrag.size());
540 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
541 ti_data->description.ice_pwd.size());
542 }
543 }
zhihuang1c378ed2017-08-17 14:10:50 -0700544 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700545 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700546 EXPECT_EQ(
547 media_desc_options_it->transport_options.enable_ice_renomination,
548 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700549
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 } else {
551 EXPECT_TRUE(ti_video == NULL);
552 }
553 }
554
555 void TestCryptoWithBundle(bool offer) {
556 f1_.set_secure(SEC_ENABLED);
557 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800558 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
559 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
560 &options);
kwiberg31022942016-03-11 14:18:21 -0800561 std::unique_ptr<SessionDescription> ref_desc;
562 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 if (offer) {
564 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800565 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800567 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 } else {
569 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800570 ref_desc = f1_.CreateOffer(options, NULL);
571 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800573 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800575 desc->GetContentDescriptionByName("audio");
576 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800578 desc->GetContentDescriptionByName("video");
579 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
581 video_media_desc->cryptos()));
582 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800583 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 audio_media_desc->cryptos()[0].cipher_suite);
585
586 // Verify the selected crypto is one from the reference audio
587 // media content.
588 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800589 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 bool found = false;
591 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
592 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200593 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 found = true;
595 break;
596 }
597 }
598 EXPECT_TRUE(found);
599 }
600
601 // This test that the audio and video media direction is set to
602 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700603 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800605 RtpTransceiverDirection direction_in_offer,
606 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700607 MediaSessionOptions offer_opts;
608 AddAudioVideoSections(direction_in_offer, &offer_opts);
609
Steve Anton6fe1fba2018-12-11 10:15:23 -0800610 std::unique_ptr<SessionDescription> offer =
611 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700613 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700615 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617
zhihuang1c378ed2017-08-17 14:10:50 -0700618 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800619 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800620 std::unique_ptr<SessionDescription> answer =
621 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 const AudioContentDescription* acd_answer =
623 GetFirstAudioContentDescription(answer.get());
624 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
625 const VideoContentDescription* vcd_answer =
626 GetFirstVideoContentDescription(answer.get());
627 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
628 }
629
630 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800631 RTC_DCHECK(content);
632 RTC_CHECK(content->media_description());
633 const cricket::AudioContentDescription* audio_desc =
634 content->media_description()->as_audio();
635 RTC_CHECK(audio_desc);
636 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
637 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800639 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 }
641 return true;
642 }
643
jbauchcb560652016-08-04 05:20:32 -0700644 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
645 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800646 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700647 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700648
jbauchcb560652016-08-04 05:20:32 -0700649 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800650 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700651 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700652
jbauchcb560652016-08-04 05:20:32 -0700653 f1_.set_secure(SEC_ENABLED);
654 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800655 std::unique_ptr<SessionDescription> offer =
656 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700657 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800658 std::unique_ptr<SessionDescription> answer =
659 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700660 const ContentInfo* ac = answer->GetContentByName("audio");
661 const ContentInfo* vc = answer->GetContentByName("video");
662 ASSERT_TRUE(ac != NULL);
663 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800664 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
665 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800666 const AudioContentDescription* acd = ac->media_description()->as_audio();
667 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700668 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800669 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700670 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700671 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700672 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
673 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700674 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700675 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700676 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700677 }
678 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800679 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200680 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
681 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700682 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700683 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700684 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700685 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700686 }
Steve Antone38a5a12018-11-21 16:05:15 -0800687 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700688 }
689
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000690 protected:
691 MediaSessionDescriptionFactory f1_;
692 MediaSessionDescriptionFactory f2_;
693 TransportDescriptionFactory tdf1_;
694 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000695};
696
697// Create a typical audio offer, and ensure it matches what we expect.
698TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
699 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800700 std::unique_ptr<SessionDescription> offer =
701 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000702 ASSERT_TRUE(offer.get() != NULL);
703 const ContentInfo* ac = offer->GetContentByName("audio");
704 const ContentInfo* vc = offer->GetContentByName("video");
705 ASSERT_TRUE(ac != NULL);
706 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800707 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800708 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700710 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700711 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000712 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
713 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700714 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800715 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000716}
717
718// Create a typical video offer, and ensure it matches what we expect.
719TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
720 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800721 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800723 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 ASSERT_TRUE(offer.get() != NULL);
725 const ContentInfo* ac = offer->GetContentByName("audio");
726 const ContentInfo* vc = offer->GetContentByName("video");
727 ASSERT_TRUE(ac != NULL);
728 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800729 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
730 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800731 const AudioContentDescription* acd = ac->media_description()->as_audio();
732 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700734 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700735 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
737 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700738 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800739 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000740 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
741 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700742 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000743 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
744 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700745 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800746 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747}
748
749// Test creating an offer with bundle where the Codecs have the same dynamic
750// RTP playlod type. The test verifies that the offer don't contain the
751// duplicate RTP payload types.
752TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
753 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700754 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000755 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
756 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
757 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
758
759 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800760 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
761 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000762 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800763 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764 const VideoContentDescription* vcd =
765 GetFirstVideoContentDescription(offer.get());
766 const AudioContentDescription* acd =
767 GetFirstAudioContentDescription(offer.get());
768 const DataContentDescription* dcd =
769 GetFirstDataContentDescription(offer.get());
770 ASSERT_TRUE(NULL != vcd);
771 ASSERT_TRUE(NULL != acd);
772 ASSERT_TRUE(NULL != dcd);
773 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
774 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
775 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
776 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
777 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
778 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
779}
780
zhihuang1c378ed2017-08-17 14:10:50 -0700781// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782// after an audio only session has been negotiated.
783TEST_F(MediaSessionDescriptionFactoryTest,
784 TestCreateUpdatedVideoOfferWithBundle) {
785 f1_.set_secure(SEC_ENABLED);
786 f2_.set_secure(SEC_ENABLED);
787 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800788 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
789 RtpTransceiverDirection::kRecvOnly, kActive,
790 &opts);
791 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
792 RtpTransceiverDirection::kInactive, kStopped,
793 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 opts.data_channel_type = cricket::DCT_NONE;
795 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800796 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
797 std::unique_ptr<SessionDescription> answer =
798 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799
800 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800801 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
802 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
803 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800805 std::unique_ptr<SessionDescription> updated_offer(
806 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807
808 const AudioContentDescription* acd =
809 GetFirstAudioContentDescription(updated_offer.get());
810 const VideoContentDescription* vcd =
811 GetFirstVideoContentDescription(updated_offer.get());
812 const DataContentDescription* dcd =
813 GetFirstDataContentDescription(updated_offer.get());
814 EXPECT_TRUE(NULL != vcd);
815 EXPECT_TRUE(NULL != acd);
816 EXPECT_TRUE(NULL != dcd);
817
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700818 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800819 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700820 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800821 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700822 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800823 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000824}
deadbeef44f08192015-12-15 16:20:09 -0800825
wu@webrtc.org78187522013-10-07 23:32:02 +0000826// Create a RTP data offer, and ensure it matches what we expect.
827TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800829 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
830 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800832 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 ASSERT_TRUE(offer.get() != NULL);
834 const ContentInfo* ac = offer->GetContentByName("audio");
835 const ContentInfo* dc = offer->GetContentByName("data");
836 ASSERT_TRUE(ac != NULL);
837 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800838 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
839 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800840 const AudioContentDescription* acd = ac->media_description()->as_audio();
841 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700843 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700844 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
846 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700847 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800848 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
850 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700851 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200853 dcd->bandwidth()); // default bandwidth (auto)
854 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700855 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800856 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857}
858
wu@webrtc.org78187522013-10-07 23:32:02 +0000859// Create an SCTP data offer with bundle without error.
860TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
861 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000862 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800863 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000864 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800865 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000866 EXPECT_TRUE(offer.get() != NULL);
867 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
868}
869
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000870// Test creating an sctp data channel from an already generated offer.
871TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
872 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000873 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800874 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000875 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800876 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000877 ASSERT_TRUE(offer1.get() != NULL);
878 const ContentInfo* data = offer1->GetContentByName("data");
879 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800880 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000881
882 // Now set data_channel_type to 'none' (default) and make sure that the
883 // datachannel type that gets generated from the previous offer, is of the
884 // same type.
885 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800886 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000887 f1_.CreateOffer(opts, offer1.get()));
888 data = offer2->GetContentByName("data");
889 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800890 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000891}
892
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893// Create an audio, video offer without legacy StreamParams.
894TEST_F(MediaSessionDescriptionFactoryTest,
895 TestCreateOfferWithoutLegacyStreams) {
896 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800897 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800898 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 ASSERT_TRUE(offer.get() != NULL);
900 const ContentInfo* ac = offer->GetContentByName("audio");
901 const ContentInfo* vc = offer->GetContentByName("video");
902 ASSERT_TRUE(ac != NULL);
903 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800904 const AudioContentDescription* acd = ac->media_description()->as_audio();
905 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000906
Yves Gerey665174f2018-06-19 15:03:05 +0200907 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
908 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909}
910
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000911// Creates an audio+video sendonly offer.
912TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700913 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800914 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800915 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
916 {kMediaStream1}, 1, &opts);
917 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
918 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000919
Steve Anton6fe1fba2018-12-11 10:15:23 -0800920 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000921 ASSERT_TRUE(offer.get() != NULL);
922 EXPECT_EQ(2u, offer->contents().size());
923 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
924 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
925
Steve Anton4e70a722017-11-28 14:57:10 -0800926 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
927 GetMediaDirection(&offer->contents()[0]));
928 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
929 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000930}
931
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000932// Verifies that the order of the media contents in the current
933// SessionDescription is preserved in the new SessionDescription.
934TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
935 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800936 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000937
kwiberg31022942016-03-11 14:18:21 -0800938 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000939 ASSERT_TRUE(offer1.get() != NULL);
940 EXPECT_EQ(1u, offer1->contents().size());
941 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
942
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800943 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
944 RtpTransceiverDirection::kRecvOnly, kActive,
945 &opts);
kwiberg31022942016-03-11 14:18:21 -0800946 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000947 f1_.CreateOffer(opts, offer1.get()));
948 ASSERT_TRUE(offer2.get() != NULL);
949 EXPECT_EQ(2u, offer2->contents().size());
950 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
951 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
952
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800953 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
954 RtpTransceiverDirection::kRecvOnly, kActive,
955 &opts);
kwiberg31022942016-03-11 14:18:21 -0800956 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000957 f1_.CreateOffer(opts, offer2.get()));
958 ASSERT_TRUE(offer3.get() != NULL);
959 EXPECT_EQ(3u, offer3->contents().size());
960 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
961 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
962 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000963}
964
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965// Create a typical audio answer, and ensure it matches what we expect.
966TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
967 f1_.set_secure(SEC_ENABLED);
968 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800969 std::unique_ptr<SessionDescription> offer =
970 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000971 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800972 std::unique_ptr<SessionDescription> answer =
973 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000974 const ContentInfo* ac = answer->GetContentByName("audio");
975 const ContentInfo* vc = answer->GetContentByName("video");
976 ASSERT_TRUE(ac != NULL);
977 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800978 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800979 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800981 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -0700982 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
984 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700985 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800986 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987}
988
jbauchcb560652016-08-04 05:20:32 -0700989// Create a typical audio answer with GCM ciphers enabled, and ensure it
990// matches what we expect.
991TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
992 f1_.set_secure(SEC_ENABLED);
993 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700994 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700995 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800996 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700997 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800998 std::unique_ptr<SessionDescription> answer =
999 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001000 const ContentInfo* ac = answer->GetContentByName("audio");
1001 const ContentInfo* vc = answer->GetContentByName("video");
1002 ASSERT_TRUE(ac != NULL);
1003 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001004 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001005 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001006 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001007 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001008 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001009 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1010 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001011 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001012 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001013}
1014
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001015// Create a typical video answer, and ensure it matches what we expect.
1016TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1017 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001018 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001019 f1_.set_secure(SEC_ENABLED);
1020 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001021 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001022 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001023 std::unique_ptr<SessionDescription> answer =
1024 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001025 const ContentInfo* ac = answer->GetContentByName("audio");
1026 const ContentInfo* vc = answer->GetContentByName("video");
1027 ASSERT_TRUE(ac != NULL);
1028 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001029 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1030 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001031 const AudioContentDescription* acd = ac->media_description()->as_audio();
1032 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001033 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001034 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001035 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001036 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001038 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001040 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001041 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1042 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001043 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001044 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045}
1046
jbauchcb560652016-08-04 05:20:32 -07001047// Create a typical video answer with GCM ciphers enabled, and ensure it
1048// matches what we expect.
1049TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1050 TestVideoGcmCipher(true, true);
1051}
1052
1053// Create a typical video answer with GCM ciphers enabled for the offer only,
1054// and ensure it matches what we expect.
1055TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1056 TestVideoGcmCipher(true, false);
1057}
1058
1059// Create a typical video answer with GCM ciphers enabled for the answer only,
1060// and ensure it matches what we expect.
1061TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1062 TestVideoGcmCipher(false, true);
1063}
1064
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001065TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001066 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001067 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068 f1_.set_secure(SEC_ENABLED);
1069 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001070 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001071 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001072 std::unique_ptr<SessionDescription> answer =
1073 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001074 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001075 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001076 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001077 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001078 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1079 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001080 const AudioContentDescription* acd = ac->media_description()->as_audio();
1081 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001082 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001083 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001084 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001085 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001086 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001087 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001088 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001089 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001090 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001091 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001092 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001093 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001094}
1095
jbauchcb560652016-08-04 05:20:32 -07001096TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001097 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001098 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001099 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001100 f1_.set_secure(SEC_ENABLED);
1101 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001102 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001103 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001104 std::unique_ptr<SessionDescription> answer =
1105 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001106 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001107 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001108 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001109 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001110 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1111 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001112 const AudioContentDescription* acd = ac->media_description()->as_audio();
1113 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001114 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001115 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001116 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001117 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001118 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001119 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001120 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001121 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001122 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001123 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001124 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001125 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001126}
1127
1128// The use_sctpmap flag should be set in a DataContentDescription by default.
1129// The answer's use_sctpmap flag should match the offer's.
1130TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1131 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001132 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001133 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001134 ASSERT_TRUE(offer.get() != NULL);
1135 ContentInfo* dc_offer = offer->GetContentByName("data");
1136 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001137 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001138 EXPECT_TRUE(dcd_offer->use_sctpmap());
1139
Steve Anton6fe1fba2018-12-11 10:15:23 -08001140 std::unique_ptr<SessionDescription> answer =
1141 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001142 const ContentInfo* dc_answer = answer->GetContentByName("data");
1143 ASSERT_TRUE(dc_answer != NULL);
1144 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001145 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001146 EXPECT_TRUE(dcd_answer->use_sctpmap());
1147}
1148
1149// The answer's use_sctpmap flag should match the offer's.
1150TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1151 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001152 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001153 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001154 ASSERT_TRUE(offer.get() != NULL);
1155 ContentInfo* dc_offer = offer->GetContentByName("data");
1156 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001157 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001158 dcd_offer->set_use_sctpmap(false);
1159
Steve Anton6fe1fba2018-12-11 10:15:23 -08001160 std::unique_ptr<SessionDescription> answer =
1161 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001162 const ContentInfo* dc_answer = answer->GetContentByName("data");
1163 ASSERT_TRUE(dc_answer != NULL);
1164 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001165 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001166 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001167}
1168
deadbeef8b7e9ad2017-05-25 09:38:55 -07001169// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1170// and "TCP/DTLS/SCTP" offers.
1171TEST_F(MediaSessionDescriptionFactoryTest,
1172 TestCreateDataAnswerToDifferentOfferedProtos) {
1173 // Need to enable DTLS offer/answer generation (disabled by default in this
1174 // test).
1175 f1_.set_secure(SEC_ENABLED);
1176 f2_.set_secure(SEC_ENABLED);
1177 tdf1_.set_secure(SEC_ENABLED);
1178 tdf2_.set_secure(SEC_ENABLED);
1179
1180 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001181 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001182 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001183 ASSERT_TRUE(offer.get() != nullptr);
1184 ContentInfo* dc_offer = offer->GetContentByName("data");
1185 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001186 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001187
1188 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1189 "TCP/DTLS/SCTP"};
1190 for (const std::string& proto : protos) {
1191 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001192 std::unique_ptr<SessionDescription> answer =
1193 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001194 const ContentInfo* dc_answer = answer->GetContentByName("data");
1195 ASSERT_TRUE(dc_answer != nullptr);
1196 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001197 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001198 EXPECT_FALSE(dc_answer->rejected);
1199 EXPECT_EQ(proto, dcd_answer->protocol());
1200 }
1201}
1202
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001203// Verifies that the order of the media contents in the offer is preserved in
1204// the answer.
1205TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1206 MediaSessionOptions opts;
1207
1208 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001209 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001210 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001211 ASSERT_TRUE(offer1.get() != NULL);
1212
1213 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001214 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1215 RtpTransceiverDirection::kRecvOnly, kActive,
1216 &opts);
kwiberg31022942016-03-11 14:18:21 -08001217 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001218 f1_.CreateOffer(opts, offer1.get()));
1219 ASSERT_TRUE(offer2.get() != NULL);
1220
1221 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001222 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1223 RtpTransceiverDirection::kRecvOnly, kActive,
1224 &opts);
kwiberg31022942016-03-11 14:18:21 -08001225 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001226 f1_.CreateOffer(opts, offer2.get()));
1227 ASSERT_TRUE(offer3.get() != NULL);
1228
Steve Anton6fe1fba2018-12-11 10:15:23 -08001229 std::unique_ptr<SessionDescription> answer =
1230 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001231 ASSERT_TRUE(answer.get() != NULL);
1232 EXPECT_EQ(3u, answer->contents().size());
1233 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1234 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1235 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1236}
1237
ossu075af922016-06-14 03:29:38 -07001238// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1239// answerer settings.
1240
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001241// This test that the media direction is set to send/receive in an answer if
1242// the offer is send receive.
1243TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001244 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1245 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246}
1247
1248// This test that the media direction is set to receive only in an answer if
1249// the offer is send only.
1250TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001251 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1252 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253}
1254
1255// This test that the media direction is set to send only in an answer if
1256// the offer is recv only.
1257TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001258 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1259 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260}
1261
1262// This test that the media direction is set to inactive in an answer if
1263// the offer is inactive.
1264TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001265 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1266 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267}
1268
1269// Test that a data content with an unknown protocol is rejected in an answer.
1270TEST_F(MediaSessionDescriptionFactoryTest,
1271 CreateDataAnswerToOfferWithUnknownProtocol) {
1272 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001273 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 f1_.set_secure(SEC_ENABLED);
1275 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001276 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001277 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001279 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 ASSERT_TRUE(dcd_offer != NULL);
1281 std::string protocol = "a weird unknown protocol";
1282 dcd_offer->set_protocol(protocol);
1283
Steve Anton6fe1fba2018-12-11 10:15:23 -08001284 std::unique_ptr<SessionDescription> answer =
1285 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286
1287 const ContentInfo* dc_answer = answer->GetContentByName("data");
1288 ASSERT_TRUE(dc_answer != NULL);
1289 EXPECT_TRUE(dc_answer->rejected);
1290 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001291 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292 ASSERT_TRUE(dcd_answer != NULL);
1293 EXPECT_EQ(protocol, dcd_answer->protocol());
1294}
1295
1296// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1297TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001298 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001299 f1_.set_secure(SEC_DISABLED);
1300 f2_.set_secure(SEC_DISABLED);
1301 tdf1_.set_secure(SEC_DISABLED);
1302 tdf2_.set_secure(SEC_DISABLED);
1303
Steve Anton6fe1fba2018-12-11 10:15:23 -08001304 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 const AudioContentDescription* offer_acd =
1306 GetFirstAudioContentDescription(offer.get());
1307 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001308 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309
Steve Anton6fe1fba2018-12-11 10:15:23 -08001310 std::unique_ptr<SessionDescription> answer =
1311 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312
1313 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1314 ASSERT_TRUE(ac_answer != NULL);
1315 EXPECT_FALSE(ac_answer->rejected);
1316
1317 const AudioContentDescription* answer_acd =
1318 GetFirstAudioContentDescription(answer.get());
1319 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001320 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001321}
1322
1323// Create a video offer and answer and ensure the RTP header extensions
1324// matches what we expect.
1325TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1326 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001327 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1329 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1330 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1331 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1332
Steve Anton6fe1fba2018-12-11 10:15:23 -08001333 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001334 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001335 std::unique_ptr<SessionDescription> answer =
1336 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001337
Yves Gerey665174f2018-06-19 15:03:05 +02001338 EXPECT_EQ(
1339 MAKE_VECTOR(kAudioRtpExtension1),
1340 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1341 EXPECT_EQ(
1342 MAKE_VECTOR(kVideoRtpExtension1),
1343 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1344 EXPECT_EQ(
1345 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1346 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1347 EXPECT_EQ(
1348 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1349 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001350}
1351
jbauch5869f502017-06-29 12:31:36 -07001352TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001353 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001354 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001355 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001356
1357 f1_.set_enable_encrypted_rtp_header_extensions(true);
1358 f2_.set_enable_encrypted_rtp_header_extensions(true);
1359
Yves Gerey665174f2018-06-19 15:03:05 +02001360 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1361 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1362 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1363 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001364
Steve Anton6fe1fba2018-12-11 10:15:23 -08001365 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001366 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001367 std::unique_ptr<SessionDescription> answer =
1368 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001369
Yves Gerey665174f2018-06-19 15:03:05 +02001370 EXPECT_EQ(
1371 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1372 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1373 EXPECT_EQ(
1374 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1375 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1376 EXPECT_EQ(
1377 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1378 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1379 EXPECT_EQ(
1380 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1381 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001382}
1383
1384TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001385 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001386 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001387 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001388
1389 f1_.set_enable_encrypted_rtp_header_extensions(true);
1390
Yves Gerey665174f2018-06-19 15:03:05 +02001391 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1392 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1393 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1394 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001395
Steve Anton6fe1fba2018-12-11 10:15:23 -08001396 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001397 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001398 std::unique_ptr<SessionDescription> answer =
1399 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001400
Yves Gerey665174f2018-06-19 15:03:05 +02001401 EXPECT_EQ(
1402 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1403 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1404 EXPECT_EQ(
1405 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1406 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1407 EXPECT_EQ(
1408 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1409 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1410 EXPECT_EQ(
1411 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1412 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001413}
1414
1415TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001416 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001417 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001418 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001419
1420 f2_.set_enable_encrypted_rtp_header_extensions(true);
1421
Yves Gerey665174f2018-06-19 15:03:05 +02001422 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1423 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1424 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1425 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001426
Steve Anton6fe1fba2018-12-11 10:15:23 -08001427 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001428 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001429 std::unique_ptr<SessionDescription> answer =
1430 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001431
Yves Gerey665174f2018-06-19 15:03:05 +02001432 EXPECT_EQ(
1433 MAKE_VECTOR(kAudioRtpExtension1),
1434 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1435 EXPECT_EQ(
1436 MAKE_VECTOR(kVideoRtpExtension1),
1437 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1438 EXPECT_EQ(
1439 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1440 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1441 EXPECT_EQ(
1442 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1443 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001444}
1445
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001446// Create an audio, video, data answer without legacy StreamParams.
1447TEST_F(MediaSessionDescriptionFactoryTest,
1448 TestCreateAnswerWithoutLegacyStreams) {
1449 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001450 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1451 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001452 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001453 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001454 std::unique_ptr<SessionDescription> answer =
1455 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001456 const ContentInfo* ac = answer->GetContentByName("audio");
1457 const ContentInfo* vc = answer->GetContentByName("video");
1458 const ContentInfo* dc = answer->GetContentByName("data");
1459 ASSERT_TRUE(ac != NULL);
1460 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001461 const AudioContentDescription* acd = ac->media_description()->as_audio();
1462 const VideoContentDescription* vcd = vc->media_description()->as_video();
1463 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001464
1465 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1466 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1467 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1468}
1469
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001470// Create a typical video answer, and ensure it matches what we expect.
1471TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1472 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001473 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1474 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1475 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001476
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001477 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001478 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1479 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1480 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001481
kwiberg31022942016-03-11 14:18:21 -08001482 std::unique_ptr<SessionDescription> offer;
1483 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001484
1485 offer_opts.rtcp_mux_enabled = true;
1486 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001487 offer = f1_.CreateOffer(offer_opts, NULL);
1488 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001489 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1490 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1491 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1492 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1493 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1494 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1495 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1496 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1497 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1498 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1499 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1500 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1501
1502 offer_opts.rtcp_mux_enabled = true;
1503 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001504 offer = f1_.CreateOffer(offer_opts, NULL);
1505 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001506 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1507 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1508 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1509 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1510 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1511 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1512 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1513 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1514 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1515 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1516 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1517 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1518
1519 offer_opts.rtcp_mux_enabled = false;
1520 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001521 offer = f1_.CreateOffer(offer_opts, NULL);
1522 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001523 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1524 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1525 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1526 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1527 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1528 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1529 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1530 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1531 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1532 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1533 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1534 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1535
1536 offer_opts.rtcp_mux_enabled = false;
1537 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001538 offer = f1_.CreateOffer(offer_opts, NULL);
1539 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001540 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1541 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1542 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1543 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1544 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1545 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1546 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1547 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1548 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1549 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1550 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1551 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1552}
1553
1554// Create an audio-only answer to a video offer.
1555TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1556 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001557 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1558 RtpTransceiverDirection::kRecvOnly, kActive,
1559 &opts);
1560 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1561 RtpTransceiverDirection::kRecvOnly, kActive,
1562 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001563 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001564 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001565
1566 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001567 std::unique_ptr<SessionDescription> answer =
1568 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001569 const ContentInfo* ac = answer->GetContentByName("audio");
1570 const ContentInfo* vc = answer->GetContentByName("video");
1571 ASSERT_TRUE(ac != NULL);
1572 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001573 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574 EXPECT_TRUE(vc->rejected);
1575}
1576
1577// Create an audio-only answer to an offer with data.
1578TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001579 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001580 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001581 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1582 RtpTransceiverDirection::kRecvOnly, kActive,
1583 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001584 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001585 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001586
1587 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001588 std::unique_ptr<SessionDescription> answer =
1589 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001590 const ContentInfo* ac = answer->GetContentByName("audio");
1591 const ContentInfo* dc = answer->GetContentByName("data");
1592 ASSERT_TRUE(ac != NULL);
1593 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001594 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001595 EXPECT_TRUE(dc->rejected);
1596}
1597
1598// Create an answer that rejects the contents which are rejected in the offer.
1599TEST_F(MediaSessionDescriptionFactoryTest,
1600 CreateAnswerToOfferWithRejectedMedia) {
1601 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001602 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1603 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001604 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605 ASSERT_TRUE(offer.get() != NULL);
1606 ContentInfo* ac = offer->GetContentByName("audio");
1607 ContentInfo* vc = offer->GetContentByName("video");
1608 ContentInfo* dc = offer->GetContentByName("data");
1609 ASSERT_TRUE(ac != NULL);
1610 ASSERT_TRUE(vc != NULL);
1611 ASSERT_TRUE(dc != NULL);
1612 ac->rejected = true;
1613 vc->rejected = true;
1614 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001615 std::unique_ptr<SessionDescription> answer =
1616 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001617 ac = answer->GetContentByName("audio");
1618 vc = answer->GetContentByName("video");
1619 dc = answer->GetContentByName("data");
1620 ASSERT_TRUE(ac != NULL);
1621 ASSERT_TRUE(vc != NULL);
1622 ASSERT_TRUE(dc != NULL);
1623 EXPECT_TRUE(ac->rejected);
1624 EXPECT_TRUE(vc->rejected);
1625 EXPECT_TRUE(dc->rejected);
1626}
1627
Johannes Kron0854eb62018-10-10 22:33:20 +02001628TEST_F(MediaSessionDescriptionFactoryTest,
1629 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1630 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001631 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001632 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001633 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001634 ASSERT_TRUE(offer.get() != NULL);
1635 std::unique_ptr<SessionDescription> answer_no_support(
1636 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001637 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001638
1639 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001640 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001641 ASSERT_TRUE(offer.get() != NULL);
1642 std::unique_ptr<SessionDescription> answer_support(
1643 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001644 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001645}
1646
1647TEST_F(MediaSessionDescriptionFactoryTest,
1648 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1649 MediaSessionOptions opts;
1650 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001651 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001652 MediaContentDescription* video_offer =
1653 offer->GetContentDescriptionByName("video");
1654 ASSERT_TRUE(video_offer);
1655 MediaContentDescription* audio_offer =
1656 offer->GetContentDescriptionByName("audio");
1657 ASSERT_TRUE(audio_offer);
1658
1659 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001660 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1661 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001662
1663 ASSERT_TRUE(offer.get() != NULL);
1664 std::unique_ptr<SessionDescription> answer_no_support(
1665 f2_.CreateAnswer(offer.get(), opts, NULL));
1666 MediaContentDescription* video_answer =
1667 answer_no_support->GetContentDescriptionByName("video");
1668 MediaContentDescription* audio_answer =
1669 answer_no_support->GetContentDescriptionByName("audio");
1670 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001671 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001672 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001673 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001674
1675 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001676 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1677 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001678 ASSERT_TRUE(offer.get() != NULL);
1679 std::unique_ptr<SessionDescription> answer_support(
1680 f2_.CreateAnswer(offer.get(), opts, NULL));
1681 video_answer = answer_support->GetContentDescriptionByName("video");
1682 audio_answer = answer_support->GetContentDescriptionByName("audio");
1683 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001684 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001685 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001686 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001687}
1688
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001689// Create an audio and video offer with:
1690// - one video track
1691// - two audio tracks
1692// - two data tracks
1693// and ensure it matches what we expect. Also updates the initial offer by
1694// adding a new video track and replaces one of the audio tracks.
1695TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1696 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001697 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001698 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1699 {kMediaStream1}, 1, &opts);
1700 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1701 {kMediaStream1}, 1, &opts);
1702 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1703 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001704
Steve Anton4e70a722017-11-28 14:57:10 -08001705 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001706 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1707 {kMediaStream1}, 1, &opts);
1708 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1709 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001710
1711 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001712 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001713
1714 ASSERT_TRUE(offer.get() != NULL);
1715 const ContentInfo* ac = offer->GetContentByName("audio");
1716 const ContentInfo* vc = offer->GetContentByName("video");
1717 const ContentInfo* dc = offer->GetContentByName("data");
1718 ASSERT_TRUE(ac != NULL);
1719 ASSERT_TRUE(vc != NULL);
1720 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001721 const AudioContentDescription* acd = ac->media_description()->as_audio();
1722 const VideoContentDescription* vcd = vc->media_description()->as_video();
1723 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001724 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001725 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001726
1727 const StreamParamsVec& audio_streams = acd->streams();
1728 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001729 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1731 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1732 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1733 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1734 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1735 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1736
1737 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1738 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001739 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001740
1741 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1742 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001743 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744
1745 const StreamParamsVec& video_streams = vcd->streams();
1746 ASSERT_EQ(1U, video_streams.size());
1747 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1748 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1749 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1750 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1751
1752 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1753 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001754 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001755
1756 const StreamParamsVec& data_streams = dcd->streams();
1757 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001758 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001759 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1760 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1761 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1762 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1763 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1764 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1765
1766 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001767 dcd->bandwidth()); // default bandwidth (auto)
1768 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001769 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001770
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001771 // Update the offer. Add a new video track that is not synched to the
1772 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001773 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
1774 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001775 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001776 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
1777 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001778 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001779 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
1780 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001781 std::unique_ptr<SessionDescription> updated_offer(
1782 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001783
1784 ASSERT_TRUE(updated_offer.get() != NULL);
1785 ac = updated_offer->GetContentByName("audio");
1786 vc = updated_offer->GetContentByName("video");
1787 dc = updated_offer->GetContentByName("data");
1788 ASSERT_TRUE(ac != NULL);
1789 ASSERT_TRUE(vc != NULL);
1790 ASSERT_TRUE(dc != NULL);
1791 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001792 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001793 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001794 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001796 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001797
1798 EXPECT_EQ(acd->type(), updated_acd->type());
1799 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1800 EXPECT_EQ(vcd->type(), updated_vcd->type());
1801 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1802 EXPECT_EQ(dcd->type(), updated_dcd->type());
1803 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001804 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001805 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001806 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001807 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001808 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1810
1811 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1812 ASSERT_EQ(2U, updated_audio_streams.size());
1813 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1814 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1815 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1816 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1817 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1818
1819 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1820 ASSERT_EQ(2U, updated_video_streams.size());
1821 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1822 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001823 // All the media streams in one PeerConnection share one RTCP CNAME.
1824 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825
1826 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1827 ASSERT_EQ(2U, updated_data_streams.size());
1828 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1829 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1830 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1831 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1832 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001833 // The stream correctly got the CNAME from the MediaSessionOptions.
1834 // The Expected RTCP CNAME is the default one as we are using the default
1835 // MediaSessionOptions.
1836 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001837}
1838
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001839// Create an offer with simulcast video stream.
1840TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1841 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001842 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1843 RtpTransceiverDirection::kRecvOnly, kActive,
1844 &opts);
1845 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1846 RtpTransceiverDirection::kSendRecv, kActive,
1847 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001848 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001849 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1850 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001851 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001852
1853 ASSERT_TRUE(offer.get() != NULL);
1854 const ContentInfo* vc = offer->GetContentByName("video");
1855 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001856 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001857
1858 const StreamParamsVec& video_streams = vcd->streams();
1859 ASSERT_EQ(1U, video_streams.size());
1860 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1861 const SsrcGroup* sim_ssrc_group =
1862 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1863 ASSERT_TRUE(sim_ssrc_group != NULL);
1864 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1865}
1866
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001867MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
1868 const RidDescription& rid1 = ::testing::get<0>(arg);
1869 const RidDescription& rid2 = ::testing::get<1>(arg);
1870 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
1871}
1872
1873static void CheckSimulcastInSessionDescription(
1874 const SessionDescription* description,
1875 const std::string& content_name,
1876 const std::vector<RidDescription>& send_rids,
1877 const SimulcastLayerList& send_layers,
1878 const RidDescription& receive_rid,
1879 const SimulcastLayer& receive_layer) {
1880 ASSERT_NE(description, nullptr);
1881 const ContentInfo* content = description->GetContentByName(content_name);
1882 ASSERT_NE(content, nullptr);
1883 const MediaContentDescription* cd = content->media_description();
1884 ASSERT_NE(cd, nullptr);
1885 const StreamParamsVec& streams = cd->streams();
1886 ASSERT_THAT(streams, SizeIs(1));
1887 const StreamParams& stream = streams[0];
1888 ASSERT_THAT(stream.ssrcs, IsEmpty());
1889 EXPECT_TRUE(stream.has_rids());
1890 const std::vector<RidDescription> rids = stream.rids();
1891
1892 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
1893
1894 ASSERT_TRUE(cd->has_receive_stream());
1895 const StreamParams& receive_stream = cd->receive_stream();
1896 EXPECT_THAT(receive_stream.ssrcs, IsEmpty());
1897 EXPECT_TRUE(receive_stream.has_rids());
1898 ASSERT_THAT(receive_stream.rids(), SizeIs(1));
1899
1900 EXPECT_EQ(receive_rid.rid, receive_stream.rids()[0].rid);
1901 EXPECT_EQ(receive_rid.direction, receive_stream.rids()[0].direction);
1902
1903 EXPECT_TRUE(cd->HasSimulcast());
1904 const SimulcastDescription& simulcast = cd->simulcast_description();
1905 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
1906 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
1907
1908 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(1));
1909 EXPECT_EQ(receive_layer, simulcast.receive_layers().GetAllLayers()[0]);
1910}
1911
1912// Create an offer with spec-compliant simulcast video stream.
1913TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
1914 MediaSessionOptions opts;
1915 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1916 RtpTransceiverDirection::kSendRecv, kActive,
1917 &opts);
1918 RidDescription receive_rid("1", RidDirection::kReceive);
1919 SimulcastLayer receive_layer(receive_rid.rid, false);
1920 opts.media_description_options[0].receive_rids = {receive_rid};
1921 opts.media_description_options[0].receive_simulcast_layers.AddLayer(
1922 receive_layer);
1923 std::vector<RidDescription> send_rids;
1924 send_rids.push_back(RidDescription("f", RidDirection::kSend));
1925 send_rids.push_back(RidDescription("h", RidDirection::kSend));
1926 send_rids.push_back(RidDescription("q", RidDirection::kSend));
1927 SimulcastLayerList simulcast_layers;
1928 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
1929 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
1930 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
1931 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1932 {kMediaStream1}, send_rids,
1933 simulcast_layers, 0, &opts);
1934 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1935
1936 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
1937 simulcast_layers, receive_rid,
1938 receive_layer);
1939}
1940
1941// Create an offer that signals RIDs (not SSRCs) without Simulcast.
1942// In this scenario, RIDs do not need to be negotiated (there is only one).
1943TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
1944 MediaSessionOptions opts;
1945 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1946 RtpTransceiverDirection::kSendRecv, kActive,
1947 &opts);
1948 RidDescription rid("f", RidDirection::kSend);
1949 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1950 {kMediaStream1}, {rid},
1951 SimulcastLayerList(), 0, &opts);
1952 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1953
1954 ASSERT_NE(offer.get(), nullptr);
1955 const ContentInfo* content = offer->GetContentByName("video");
1956 ASSERT_NE(content, nullptr);
1957 const MediaContentDescription* cd = content->media_description();
1958 ASSERT_NE(cd, nullptr);
1959 EXPECT_FALSE(cd->has_receive_stream());
1960 const StreamParamsVec& streams = cd->streams();
1961 ASSERT_THAT(streams, SizeIs(1));
1962 const StreamParams& stream = streams[0];
1963 ASSERT_THAT(stream.ssrcs, IsEmpty());
1964 EXPECT_FALSE(stream.has_rids());
1965 EXPECT_FALSE(cd->HasSimulcast());
1966}
1967
1968// Create an answer with spec-compliant simulcast video stream.
1969// In this scenario, the SFU is the caller requesting that we send Simulcast.
1970TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
1971 MediaSessionOptions offer_opts;
1972 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1973 RtpTransceiverDirection::kSendRecv, kActive,
1974 &offer_opts);
1975 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1976 {kMediaStream1}, 1, &offer_opts);
1977 std::unique_ptr<SessionDescription> offer =
1978 f1_.CreateOffer(offer_opts, nullptr);
1979
1980 MediaSessionOptions answer_opts;
1981 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1982 RtpTransceiverDirection::kSendRecv, kActive,
1983 &answer_opts);
1984
1985 RidDescription receive_rid("1", RidDirection::kReceive);
1986 SimulcastLayer receive_layer(receive_rid.rid, false);
1987 answer_opts.media_description_options[0].receive_rids = {receive_rid};
1988 answer_opts.media_description_options[0].receive_simulcast_layers.AddLayer(
1989 receive_layer);
1990 std::vector<RidDescription> rid_descriptions{
1991 RidDescription("f", RidDirection::kSend),
1992 RidDescription("h", RidDirection::kSend),
1993 RidDescription("q", RidDirection::kSend),
1994 };
1995 SimulcastLayerList simulcast_layers;
1996 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
1997 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
1998 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
1999 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2000 {kMediaStream1}, rid_descriptions,
2001 simulcast_layers, 0, &answer_opts);
2002 std::unique_ptr<SessionDescription> answer =
2003 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2004
2005 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
2006 simulcast_layers, receive_rid,
2007 receive_layer);
2008}
2009
2010// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2011// In this scenario, RIDs do not need to be negotiated (there is only one).
2012// Note that RID Direction is not the same as the transceiver direction.
2013TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2014 MediaSessionOptions offer_opts;
2015 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2016 RtpTransceiverDirection::kSendRecv, kActive,
2017 &offer_opts);
2018 RidDescription rid_offer("f", RidDirection::kSend);
2019 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2020 {kMediaStream1}, {rid_offer},
2021 SimulcastLayerList(), 0, &offer_opts);
2022 std::unique_ptr<SessionDescription> offer =
2023 f1_.CreateOffer(offer_opts, nullptr);
2024
2025 MediaSessionOptions answer_opts;
2026 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2027 RtpTransceiverDirection::kSendRecv, kActive,
2028 &answer_opts);
2029
2030 RidDescription rid_answer("f", RidDirection::kReceive);
2031 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2032 {kMediaStream1}, {rid_answer},
2033 SimulcastLayerList(), 0, &answer_opts);
2034 std::unique_ptr<SessionDescription> answer =
2035 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2036
2037 ASSERT_NE(answer.get(), nullptr);
2038 const ContentInfo* content = offer->GetContentByName("video");
2039 ASSERT_NE(content, nullptr);
2040 const MediaContentDescription* cd = content->media_description();
2041 ASSERT_NE(cd, nullptr);
2042 EXPECT_FALSE(cd->has_receive_stream());
2043 const StreamParamsVec& streams = cd->streams();
2044 ASSERT_THAT(streams, SizeIs(1));
2045 const StreamParams& stream = streams[0];
2046 ASSERT_THAT(stream.ssrcs, IsEmpty());
2047 EXPECT_FALSE(stream.has_rids());
2048 EXPECT_FALSE(cd->HasSimulcast());
2049}
2050
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002051// Create an audio and video answer to a standard video offer with:
2052// - one video track
2053// - two audio tracks
2054// - two data tracks
2055// and ensure it matches what we expect. Also updates the initial answer by
2056// adding a new video track and removes one of the audio tracks.
2057TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2058 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002059 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2060 RtpTransceiverDirection::kRecvOnly, kActive,
2061 &offer_opts);
2062 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2063 RtpTransceiverDirection::kRecvOnly, kActive,
2064 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002066 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2067 RtpTransceiverDirection::kRecvOnly, kActive,
2068 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002069 f1_.set_secure(SEC_ENABLED);
2070 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002071 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072
zhihuang1c378ed2017-08-17 14:10:50 -07002073 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002074 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2075 RtpTransceiverDirection::kSendRecv, kActive,
2076 &answer_opts);
2077 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2078 RtpTransceiverDirection::kSendRecv, kActive,
2079 &answer_opts);
2080 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2081 {kMediaStream1}, 1, &answer_opts);
2082 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2083 {kMediaStream1}, 1, &answer_opts);
2084 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2085 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002086
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002087 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2088 RtpTransceiverDirection::kSendRecv, kActive,
2089 &answer_opts);
2090 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2091 {kMediaStream1}, 1, &answer_opts);
2092 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2093 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002094 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002095
Steve Anton6fe1fba2018-12-11 10:15:23 -08002096 std::unique_ptr<SessionDescription> answer =
2097 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002098
2099 ASSERT_TRUE(answer.get() != NULL);
2100 const ContentInfo* ac = answer->GetContentByName("audio");
2101 const ContentInfo* vc = answer->GetContentByName("video");
2102 const ContentInfo* dc = answer->GetContentByName("data");
2103 ASSERT_TRUE(ac != NULL);
2104 ASSERT_TRUE(vc != NULL);
2105 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002106 const AudioContentDescription* acd = ac->media_description()->as_audio();
2107 const VideoContentDescription* vcd = vc->media_description()->as_video();
2108 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002109 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2110 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2111 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002112
2113 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002114 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002115
2116 const StreamParamsVec& audio_streams = acd->streams();
2117 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002118 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002119 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2120 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2121 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2122 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2123 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2124 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2125
2126 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2127 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2128
2129 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002130 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131
2132 const StreamParamsVec& video_streams = vcd->streams();
2133 ASSERT_EQ(1U, video_streams.size());
2134 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2135 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2136 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2137 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2138
2139 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002140 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002141
2142 const StreamParamsVec& data_streams = dcd->streams();
2143 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002144 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002145 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2146 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2147 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2148 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2149 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2150 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2151
2152 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002153 dcd->bandwidth()); // default bandwidth (auto)
2154 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155
2156 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002157 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002158 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2159 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002160 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2161 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002162 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002163 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164
2165 ASSERT_TRUE(updated_answer.get() != NULL);
2166 ac = updated_answer->GetContentByName("audio");
2167 vc = updated_answer->GetContentByName("video");
2168 dc = updated_answer->GetContentByName("data");
2169 ASSERT_TRUE(ac != NULL);
2170 ASSERT_TRUE(vc != NULL);
2171 ASSERT_TRUE(dc != NULL);
2172 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002173 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002175 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002176 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002177 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002179 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002180 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002181 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002182 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002183 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002184 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2185
2186 EXPECT_EQ(acd->type(), updated_acd->type());
2187 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2188 EXPECT_EQ(vcd->type(), updated_vcd->type());
2189 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2190 EXPECT_EQ(dcd->type(), updated_dcd->type());
2191 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2192
2193 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2194 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002195 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002196
2197 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2198 ASSERT_EQ(2U, updated_video_streams.size());
2199 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2200 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002201 // All media streams in one PeerConnection share one CNAME.
2202 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002203
2204 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2205 ASSERT_EQ(1U, updated_data_streams.size());
2206 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2207}
2208
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209// Create an updated offer after creating an answer to the original offer and
2210// verify that the codecs that were part of the original answer are not changed
2211// in the updated offer.
2212TEST_F(MediaSessionDescriptionFactoryTest,
2213 RespondentCreatesOfferAfterCreatingAnswer) {
2214 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002215 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002216
Steve Anton6fe1fba2018-12-11 10:15:23 -08002217 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2218 std::unique_ptr<SessionDescription> answer =
2219 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002220
2221 const AudioContentDescription* acd =
2222 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002223 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002224
2225 const VideoContentDescription* vcd =
2226 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002227 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002228
kwiberg31022942016-03-11 14:18:21 -08002229 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002230 f2_.CreateOffer(opts, answer.get()));
2231
2232 // The expected audio codecs are the common audio codecs from the first
2233 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2234 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002235 // TODO(wu): |updated_offer| should not include the codec
2236 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002237 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002238 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239 };
2240
2241 // The expected video codecs are the common video codecs from the first
2242 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2243 // preference order.
2244 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002245 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002246 };
2247
2248 const AudioContentDescription* updated_acd =
2249 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002250 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002251
2252 const VideoContentDescription* updated_vcd =
2253 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002254 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002255}
2256
Steve Anton5c72e712018-12-10 14:25:30 -08002257// Test that a reoffer does not reuse audio codecs from a previous media section
2258// that is being recycled.
2259TEST_F(MediaSessionDescriptionFactoryTest,
2260 ReOfferDoesNotReUseRecycledAudioCodecs) {
2261 f1_.set_video_codecs({});
2262 f2_.set_video_codecs({});
2263
2264 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002265 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2266 RtpTransceiverDirection::kSendRecv, kActive,
2267 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002268 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2269 std::unique_ptr<SessionDescription> answer =
2270 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002271
2272 // Recycle the media section by changing its mid.
2273 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002274 std::unique_ptr<SessionDescription> reoffer =
2275 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002276
2277 // Expect that the results of the first negotiation are ignored. If the m=
2278 // section was not recycled the payload types would match the initial offerer.
2279 const AudioContentDescription* acd =
2280 GetFirstAudioContentDescription(reoffer.get());
2281 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2282}
2283
2284// Test that a reoffer does not reuse video codecs from a previous media section
2285// that is being recycled.
2286TEST_F(MediaSessionDescriptionFactoryTest,
2287 ReOfferDoesNotReUseRecycledVideoCodecs) {
2288 f1_.set_audio_codecs({}, {});
2289 f2_.set_audio_codecs({}, {});
2290
2291 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002292 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2293 RtpTransceiverDirection::kSendRecv, kActive,
2294 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002295 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2296 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002297
2298 // Recycle the media section by changing its mid.
2299 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002300 std::unique_ptr<SessionDescription> reoffer =
2301 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002302
2303 // Expect that the results of the first negotiation are ignored. If the m=
2304 // section was not recycled the payload types would match the initial offerer.
2305 const VideoContentDescription* vcd =
2306 GetFirstVideoContentDescription(reoffer.get());
2307 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2308}
2309
2310// Test that a reanswer does not reuse audio codecs from a previous media
2311// section that is being recycled.
2312TEST_F(MediaSessionDescriptionFactoryTest,
2313 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2314 f1_.set_video_codecs({});
2315 f2_.set_video_codecs({});
2316
2317 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2318 // second offer/answer is forward (|f1_| as offerer).
2319 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002320 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2321 RtpTransceiverDirection::kSendRecv, kActive,
2322 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002323 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2324 std::unique_ptr<SessionDescription> answer =
2325 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002326
2327 // Recycle the media section by changing its mid.
2328 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002329 std::unique_ptr<SessionDescription> reoffer =
2330 f1_.CreateOffer(opts, answer.get());
2331 std::unique_ptr<SessionDescription> reanswer =
2332 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002333
2334 // Expect that the results of the first negotiation are ignored. If the m=
2335 // section was not recycled the payload types would match the initial offerer.
2336 const AudioContentDescription* acd =
2337 GetFirstAudioContentDescription(reanswer.get());
2338 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2339}
2340
2341// Test that a reanswer does not reuse video codecs from a previous media
2342// section that is being recycled.
2343TEST_F(MediaSessionDescriptionFactoryTest,
2344 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2345 f1_.set_audio_codecs({}, {});
2346 f2_.set_audio_codecs({}, {});
2347
2348 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2349 // second offer/answer is forward (|f1_| as offerer).
2350 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002351 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2352 RtpTransceiverDirection::kSendRecv, kActive,
2353 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002354 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2355 std::unique_ptr<SessionDescription> answer =
2356 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002357
2358 // Recycle the media section by changing its mid.
2359 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002360 std::unique_ptr<SessionDescription> reoffer =
2361 f1_.CreateOffer(opts, answer.get());
2362 std::unique_ptr<SessionDescription> reanswer =
2363 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002364
2365 // Expect that the results of the first negotiation are ignored. If the m=
2366 // section was not recycled the payload types would match the initial offerer.
2367 const VideoContentDescription* vcd =
2368 GetFirstVideoContentDescription(reanswer.get());
2369 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2370}
2371
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002372// Create an updated offer after creating an answer to the original offer and
2373// verify that the codecs that were part of the original answer are not changed
2374// in the updated offer. In this test Rtx is enabled.
2375TEST_F(MediaSessionDescriptionFactoryTest,
2376 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2377 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002378 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2379 RtpTransceiverDirection::kRecvOnly, kActive,
2380 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002381 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002383 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002384 f1_.set_video_codecs(f1_codecs);
2385
2386 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002388 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002389 f2_.set_video_codecs(f2_codecs);
2390
Steve Anton6fe1fba2018-12-11 10:15:23 -08002391 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002392 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002393 std::unique_ptr<SessionDescription> answer =
2394 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002395
2396 const VideoContentDescription* vcd =
2397 GetFirstVideoContentDescription(answer.get());
2398
2399 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002400 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2401 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002402
2403 EXPECT_EQ(expected_codecs, vcd->codecs());
2404
deadbeef67cf2c12016-04-13 10:07:16 -07002405 // Now, make sure we get same result (except for the order) if |f2_| creates
2406 // an updated offer even though the default payload types between |f1_| and
2407 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002408 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002409 f2_.CreateOffer(opts, answer.get()));
2410 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002411 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002412 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2413
2414 const VideoContentDescription* updated_vcd =
2415 GetFirstVideoContentDescription(updated_answer.get());
2416
2417 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2418}
2419
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002420// Regression test for:
2421// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2422// Existing codecs should always appear before new codecs in re-offers. But
2423// under a specific set of circumstances, the existing RTX codec was ending up
2424// added to the end of the list.
2425TEST_F(MediaSessionDescriptionFactoryTest,
2426 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2427 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002428 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2429 RtpTransceiverDirection::kRecvOnly, kActive,
2430 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002431 // We specifically choose different preferred payload types for VP8 to
2432 // trigger the issue.
2433 cricket::VideoCodec vp8_offerer(100, "VP8");
2434 cricket::VideoCodec vp8_offerer_rtx =
2435 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2436 cricket::VideoCodec vp8_answerer(110, "VP8");
2437 cricket::VideoCodec vp8_answerer_rtx =
2438 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2439 cricket::VideoCodec vp9(120, "VP9");
2440 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2441
2442 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2443 // We also specifically cause the answerer to prefer VP9, such that if it
2444 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2445 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2446 vp8_answerer_rtx};
2447
2448 f1_.set_video_codecs(f1_codecs);
2449 f2_.set_video_codecs(f2_codecs);
2450 std::vector<AudioCodec> audio_codecs;
2451 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2452 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2453
2454 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002455 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002456 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002457 std::unique_ptr<SessionDescription> answer =
2458 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002459
2460 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2461 // But if the bug is triggered, RTX for VP8 ends up last.
2462 std::unique_ptr<SessionDescription> updated_offer(
2463 f2_.CreateOffer(opts, answer.get()));
2464
2465 const VideoContentDescription* vcd =
2466 GetFirstVideoContentDescription(updated_offer.get());
2467 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2468 ASSERT_EQ(4u, codecs.size());
2469 EXPECT_EQ(vp8_offerer, codecs[0]);
2470 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2471 EXPECT_EQ(vp9, codecs[2]);
2472 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002473}
2474
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002475// Create an updated offer that adds video after creating an audio only answer
2476// to the original offer. This test verifies that if a video codec and the RTX
2477// codec have the same default payload type as an audio codec that is already in
2478// use, the added codecs payload types are changed.
2479TEST_F(MediaSessionDescriptionFactoryTest,
2480 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2481 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002482 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002483 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002484 f1_.set_video_codecs(f1_codecs);
2485
2486 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002487 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2488 RtpTransceiverDirection::kRecvOnly, kActive,
2489 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002490
Steve Anton6fe1fba2018-12-11 10:15:23 -08002491 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2492 std::unique_ptr<SessionDescription> answer =
2493 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002494
2495 const AudioContentDescription* acd =
2496 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002497 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002498
2499 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2500 // reference be the same as an audio codec that was negotiated in the
2501 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002502 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002503 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002504
2505 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2506 int used_pl_type = acd->codecs()[0].id;
2507 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002508 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002509 f2_.set_video_codecs(f2_codecs);
2510
kwiberg31022942016-03-11 14:18:21 -08002511 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002512 f2_.CreateOffer(opts, answer.get()));
2513 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002514 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002515 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2516
2517 const AudioContentDescription* updated_acd =
2518 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002519 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002520
2521 const VideoContentDescription* updated_vcd =
2522 GetFirstVideoContentDescription(updated_answer.get());
2523
2524 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002525 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002526 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002527 EXPECT_NE(used_pl_type, new_h264_pl_type);
2528 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002529 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2531 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2532}
2533
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002534// Create an updated offer with RTX after creating an answer to an offer
2535// without RTX, and with different default payload types.
2536// Verify that the added RTX codec references the correct payload type.
2537TEST_F(MediaSessionDescriptionFactoryTest,
2538 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2539 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002540 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002541
2542 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2543 // This creates rtx for H264 with the payload type |f2_| uses.
2544 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2545 f2_.set_video_codecs(f2_codecs);
2546
Steve Anton6fe1fba2018-12-11 10:15:23 -08002547 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002548 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002549 std::unique_ptr<SessionDescription> answer =
2550 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002551
2552 const VideoContentDescription* vcd =
2553 GetFirstVideoContentDescription(answer.get());
2554
2555 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2556 EXPECT_EQ(expected_codecs, vcd->codecs());
2557
2558 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2559 // updated offer, even though the default payload types are different from
2560 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002561 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002562 f2_.CreateOffer(opts, answer.get()));
2563 ASSERT_TRUE(updated_offer);
2564
2565 const VideoContentDescription* updated_vcd =
2566 GetFirstVideoContentDescription(updated_offer.get());
2567
2568 // New offer should attempt to add H263, and RTX for H264.
2569 expected_codecs.push_back(kVideoCodecs2[1]);
2570 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2571 &expected_codecs);
2572 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2573}
2574
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002575// Test that RTX is ignored when there is no associated payload type parameter.
2576TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2577 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002578 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2579 RtpTransceiverDirection::kRecvOnly, kActive,
2580 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002581 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002582 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002583 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002584 f1_.set_video_codecs(f1_codecs);
2585
2586 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002587 // This creates RTX for H264 with the payload type |f2_| uses.
2588 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002589 f2_.set_video_codecs(f2_codecs);
2590
Steve Anton6fe1fba2018-12-11 10:15:23 -08002591 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002592 ASSERT_TRUE(offer.get() != NULL);
2593 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2594 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2595 // is possible to test that that RTX is dropped when
2596 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002597 MediaContentDescription* media_desc =
2598 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2599 ASSERT_TRUE(media_desc);
2600 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002601 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002602 for (VideoCodec& codec : codecs) {
2603 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2604 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002605 }
2606 }
2607 desc->set_codecs(codecs);
2608
Steve Anton6fe1fba2018-12-11 10:15:23 -08002609 std::unique_ptr<SessionDescription> answer =
2610 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002611
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002612 std::vector<std::string> codec_names =
2613 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2614 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2615 cricket::kRtxCodecName));
2616}
2617
2618// Test that RTX will be filtered out in the answer if its associated payload
2619// type doesn't match the local value.
2620TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2621 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002622 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2623 RtpTransceiverDirection::kRecvOnly, kActive,
2624 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002625 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2626 // This creates RTX for H264 in sender.
2627 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2628 f1_.set_video_codecs(f1_codecs);
2629
2630 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2631 // This creates RTX for H263 in receiver.
2632 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2633 f2_.set_video_codecs(f2_codecs);
2634
Steve Anton6fe1fba2018-12-11 10:15:23 -08002635 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002636 ASSERT_TRUE(offer.get() != NULL);
2637 // Associated payload type doesn't match, therefore, RTX codec is removed in
2638 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002639 std::unique_ptr<SessionDescription> answer =
2640 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002641
2642 std::vector<std::string> codec_names =
2643 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2644 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2645 cricket::kRtxCodecName));
2646}
2647
2648// Test that when multiple RTX codecs are offered, only the matched RTX codec
2649// is added in the answer, and the unsupported RTX codec is filtered out.
2650TEST_F(MediaSessionDescriptionFactoryTest,
2651 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2652 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002653 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2654 RtpTransceiverDirection::kRecvOnly, kActive,
2655 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002656 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2657 // This creates RTX for H264-SVC in sender.
2658 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2659 f1_.set_video_codecs(f1_codecs);
2660
2661 // This creates RTX for H264 in sender.
2662 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2663 f1_.set_video_codecs(f1_codecs);
2664
2665 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2666 // This creates RTX for H264 in receiver.
2667 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2668 f2_.set_video_codecs(f2_codecs);
2669
2670 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2671 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002672 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002673 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002674 std::unique_ptr<SessionDescription> answer =
2675 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002676 const VideoContentDescription* vcd =
2677 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002678 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2679 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2680 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002681
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002682 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002683}
2684
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002685// Test that after one RTX codec has been negotiated, a new offer can attempt
2686// to add another.
2687TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2688 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002689 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2690 RtpTransceiverDirection::kRecvOnly, kActive,
2691 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002692 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2693 // This creates RTX for H264 for the offerer.
2694 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2695 f1_.set_video_codecs(f1_codecs);
2696
Steve Anton6fe1fba2018-12-11 10:15:23 -08002697 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002698 ASSERT_TRUE(offer);
2699 const VideoContentDescription* vcd =
2700 GetFirstVideoContentDescription(offer.get());
2701
2702 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2703 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2704 &expected_codecs);
2705 EXPECT_EQ(expected_codecs, vcd->codecs());
2706
2707 // Now, attempt to add RTX for H264-SVC.
2708 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2709 f1_.set_video_codecs(f1_codecs);
2710
kwiberg31022942016-03-11 14:18:21 -08002711 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002712 f1_.CreateOffer(opts, offer.get()));
2713 ASSERT_TRUE(updated_offer);
2714 vcd = GetFirstVideoContentDescription(updated_offer.get());
2715
2716 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2717 &expected_codecs);
2718 EXPECT_EQ(expected_codecs, vcd->codecs());
2719}
2720
Noah Richards2e7a0982015-05-18 14:02:54 -07002721// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2722// generated for each simulcast ssrc and correctly grouped.
2723TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2724 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002725 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2726 RtpTransceiverDirection::kSendRecv, kActive,
2727 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002728 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002729 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2730 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002731
2732 // Use a single real codec, and then add RTX for it.
2733 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002734 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002735 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2736 f1_.set_video_codecs(f1_codecs);
2737
2738 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2739 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002740 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002741 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002742 MediaContentDescription* media_desc =
2743 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2744 ASSERT_TRUE(media_desc);
2745 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002746 const StreamParamsVec& streams = desc->streams();
2747 // Single stream.
2748 ASSERT_EQ(1u, streams.size());
2749 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2750 EXPECT_EQ(6u, streams[0].ssrcs.size());
2751 // And should have a SIM group for the simulcast.
2752 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2753 // And a FID group for RTX.
2754 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002755 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002756 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2757 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002758 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002759 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2760 EXPECT_EQ(3u, fid_ssrcs.size());
2761}
2762
brandtr03d5fb12016-11-22 03:37:59 -08002763// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2764// together with a FEC-FR grouping.
2765TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2766 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002767 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2768 RtpTransceiverDirection::kSendRecv, kActive,
2769 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002770 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002771 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2772 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002773
2774 // Use a single real codec, and then add FlexFEC for it.
2775 std::vector<VideoCodec> f1_codecs;
2776 f1_codecs.push_back(VideoCodec(97, "H264"));
2777 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2778 f1_.set_video_codecs(f1_codecs);
2779
2780 // Ensure that the offer has a single FlexFEC ssrc and that
2781 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002782 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002783 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002784 MediaContentDescription* media_desc =
2785 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2786 ASSERT_TRUE(media_desc);
2787 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002788 const StreamParamsVec& streams = desc->streams();
2789 // Single stream.
2790 ASSERT_EQ(1u, streams.size());
2791 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2792 EXPECT_EQ(2u, streams[0].ssrcs.size());
2793 // And should have a FEC-FR group for FlexFEC.
2794 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2795 std::vector<uint32_t> primary_ssrcs;
2796 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2797 ASSERT_EQ(1u, primary_ssrcs.size());
2798 uint32_t flexfec_ssrc;
2799 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2800 EXPECT_NE(flexfec_ssrc, 0u);
2801}
2802
2803// Test that FlexFEC is disabled for simulcast.
2804// TODO(brandtr): Remove this test when we support simulcast, either through
2805// multiple FlexfecSenders, or through multistream protection.
2806TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2807 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002808 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2809 RtpTransceiverDirection::kSendRecv, kActive,
2810 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002811 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002812 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2813 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002814
2815 // Use a single real codec, and then add FlexFEC for it.
2816 std::vector<VideoCodec> f1_codecs;
2817 f1_codecs.push_back(VideoCodec(97, "H264"));
2818 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2819 f1_.set_video_codecs(f1_codecs);
2820
2821 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2822 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002823 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002824 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002825 MediaContentDescription* media_desc =
2826 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2827 ASSERT_TRUE(media_desc);
2828 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002829 const StreamParamsVec& streams = desc->streams();
2830 // Single stream.
2831 ASSERT_EQ(1u, streams.size());
2832 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2833 EXPECT_EQ(3u, streams[0].ssrcs.size());
2834 // And should have a SIM group for the simulcast.
2835 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2836 // And not a FEC-FR group for FlexFEC.
2837 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2838 std::vector<uint32_t> primary_ssrcs;
2839 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2840 EXPECT_EQ(3u, primary_ssrcs.size());
2841 for (uint32_t primary_ssrc : primary_ssrcs) {
2842 uint32_t flexfec_ssrc;
2843 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2844 }
2845}
2846
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002847// Create an updated offer after creating an answer to the original offer and
2848// verify that the RTP header extensions that were part of the original answer
2849// are not changed in the updated offer.
2850TEST_F(MediaSessionDescriptionFactoryTest,
2851 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2852 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002853 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002854
2855 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2856 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2857 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2858 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2859
Steve Anton6fe1fba2018-12-11 10:15:23 -08002860 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2861 std::unique_ptr<SessionDescription> answer =
2862 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002863
Yves Gerey665174f2018-06-19 15:03:05 +02002864 EXPECT_EQ(
2865 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2866 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2867 EXPECT_EQ(
2868 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2869 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002870
kwiberg31022942016-03-11 14:18:21 -08002871 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002872 f2_.CreateOffer(opts, answer.get()));
2873
2874 // The expected RTP header extensions in the new offer are the resulting
2875 // extensions from the first offer/answer exchange plus the extensions only
2876 // |f2_| offer.
2877 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002878 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002879 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2880 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2881 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002882 };
2883
2884 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002885 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002886 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2887 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2888 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002889 };
2890
2891 const AudioContentDescription* updated_acd =
2892 GetFirstAudioContentDescription(updated_offer.get());
2893 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2894 updated_acd->rtp_header_extensions());
2895
2896 const VideoContentDescription* updated_vcd =
2897 GetFirstVideoContentDescription(updated_offer.get());
2898 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2899 updated_vcd->rtp_header_extensions());
2900}
2901
deadbeefa5b273a2015-08-20 17:30:13 -07002902// Verify that if the same RTP extension URI is used for audio and video, the
2903// same ID is used. Also verify that the ID isn't changed when creating an
2904// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002905TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002906 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002907 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002908
2909 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2910 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2911
Steve Anton6fe1fba2018-12-11 10:15:23 -08002912 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07002913
2914 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2915 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002916 const RtpExtension kExpectedVideoRtpExtension[] = {
2917 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002918 };
2919
Yves Gerey665174f2018-06-19 15:03:05 +02002920 EXPECT_EQ(
2921 MAKE_VECTOR(kAudioRtpExtension3),
2922 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2923 EXPECT_EQ(
2924 MAKE_VECTOR(kExpectedVideoRtpExtension),
2925 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002926
2927 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002928 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002929 f1_.CreateOffer(opts, offer.get()));
2930
2931 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02002932 GetFirstAudioContentDescription(updated_offer.get())
2933 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002934 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002935 GetFirstVideoContentDescription(updated_offer.get())
2936 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002937}
2938
jbauch5869f502017-06-29 12:31:36 -07002939// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2940TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2941 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002942 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002943
2944 f1_.set_enable_encrypted_rtp_header_extensions(true);
2945 f2_.set_enable_encrypted_rtp_header_extensions(true);
2946
2947 f1_.set_audio_rtp_header_extensions(
2948 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2949 f1_.set_video_rtp_header_extensions(
2950 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2951
Steve Anton6fe1fba2018-12-11 10:15:23 -08002952 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07002953
2954 // The extensions that are shared between audio and video should use the same
2955 // id.
2956 const RtpExtension kExpectedVideoRtpExtension[] = {
2957 kVideoRtpExtension3ForEncryption[0],
2958 kAudioRtpExtension3ForEncryptionOffer[1],
2959 kAudioRtpExtension3ForEncryptionOffer[2],
2960 };
2961
Yves Gerey665174f2018-06-19 15:03:05 +02002962 EXPECT_EQ(
2963 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2964 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2965 EXPECT_EQ(
2966 MAKE_VECTOR(kExpectedVideoRtpExtension),
2967 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002968
2969 // Nothing should change when creating a new offer
2970 std::unique_ptr<SessionDescription> updated_offer(
2971 f1_.CreateOffer(opts, offer.get()));
2972
2973 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02002974 GetFirstAudioContentDescription(updated_offer.get())
2975 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002976 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002977 GetFirstVideoContentDescription(updated_offer.get())
2978 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002979}
2980
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002981TEST(MediaSessionDescription, CopySessionDescription) {
2982 SessionDescription source;
2983 cricket::ContentGroup group(cricket::CN_AUDIO);
2984 source.AddGroup(group);
2985 AudioContentDescription* acd(new AudioContentDescription());
2986 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2987 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08002988 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002989 VideoContentDescription* vcd(new VideoContentDescription());
2990 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2991 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08002992 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002993
kwiberg31022942016-03-11 14:18:21 -08002994 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002995 ASSERT_TRUE(copy.get() != NULL);
2996 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2997 const ContentInfo* ac = copy->GetContentByName("audio");
2998 const ContentInfo* vc = copy->GetContentByName("video");
2999 ASSERT_TRUE(ac != NULL);
3000 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003001 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003002 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003003 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3004 EXPECT_EQ(1u, acd->first_ssrc());
3005
Steve Anton5adfafd2017-12-20 16:34:00 -08003006 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003007 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003008 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3009 EXPECT_EQ(2u, vcd->first_ssrc());
3010}
3011
3012// The below TestTransportInfoXXX tests create different offers/answers, and
3013// ensure the TransportInfo in the SessionDescription matches what we expect.
3014TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3015 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003016 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3017 RtpTransceiverDirection::kRecvOnly, kActive,
3018 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003019 TestTransportInfo(true, options, false);
3020}
3021
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003022TEST_F(MediaSessionDescriptionFactoryTest,
3023 TestTransportInfoOfferIceRenomination) {
3024 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003025 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3026 RtpTransceiverDirection::kRecvOnly, kActive,
3027 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003028 options.media_description_options[0]
3029 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003030 TestTransportInfo(true, options, false);
3031}
3032
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003033TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3034 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003035 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3036 RtpTransceiverDirection::kRecvOnly, kActive,
3037 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003038 TestTransportInfo(true, options, true);
3039}
3040
3041TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3042 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003043 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3044 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3045 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003046 TestTransportInfo(true, options, false);
3047}
3048
3049TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003050 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003051 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003052 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3053 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3054 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003055 TestTransportInfo(true, options, true);
3056}
3057
3058TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3059 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003060 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3061 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3062 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003063 options.bundle_enabled = true;
3064 TestTransportInfo(true, options, false);
3065}
3066
3067TEST_F(MediaSessionDescriptionFactoryTest,
3068 TestTransportInfoOfferBundleCurrent) {
3069 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003070 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3071 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3072 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003073 options.bundle_enabled = true;
3074 TestTransportInfo(true, options, true);
3075}
3076
3077TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3078 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003079 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3080 RtpTransceiverDirection::kRecvOnly, kActive,
3081 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003082 TestTransportInfo(false, options, false);
3083}
3084
3085TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003086 TestTransportInfoAnswerIceRenomination) {
3087 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003088 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3089 RtpTransceiverDirection::kRecvOnly, kActive,
3090 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003091 options.media_description_options[0]
3092 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003093 TestTransportInfo(false, options, false);
3094}
3095
3096TEST_F(MediaSessionDescriptionFactoryTest,
3097 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003098 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003099 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3100 RtpTransceiverDirection::kRecvOnly, kActive,
3101 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003102 TestTransportInfo(false, options, true);
3103}
3104
3105TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3106 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003107 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3108 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3109 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003110 TestTransportInfo(false, options, false);
3111}
3112
3113TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003114 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003115 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003116 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3117 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3118 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003119 TestTransportInfo(false, options, true);
3120}
3121
3122TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3123 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003124 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3125 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3126 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003127 options.bundle_enabled = true;
3128 TestTransportInfo(false, options, false);
3129}
3130
3131TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003132 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003133 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003134 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3135 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3136 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003137 options.bundle_enabled = true;
3138 TestTransportInfo(false, options, true);
3139}
3140
3141// Create an offer with bundle enabled and verify the crypto parameters are
3142// the common set of the available cryptos.
3143TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3144 TestCryptoWithBundle(true);
3145}
3146
3147// Create an answer with bundle enabled and verify the crypto parameters are
3148// the common set of the available cryptos.
3149TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3150 TestCryptoWithBundle(false);
3151}
3152
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003153// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3154// DTLS is not enabled locally.
3155TEST_F(MediaSessionDescriptionFactoryTest,
3156 TestOfferDtlsSavpfWithoutDtlsFailed) {
3157 f1_.set_secure(SEC_ENABLED);
3158 f2_.set_secure(SEC_ENABLED);
3159 tdf1_.set_secure(SEC_DISABLED);
3160 tdf2_.set_secure(SEC_DISABLED);
3161
Steve Anton6fe1fba2018-12-11 10:15:23 -08003162 std::unique_ptr<SessionDescription> offer =
3163 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003164 ASSERT_TRUE(offer.get() != NULL);
3165 ContentInfo* offer_content = offer->GetContentByName("audio");
3166 ASSERT_TRUE(offer_content != NULL);
3167 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003168 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003169 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3170
Steve Anton6fe1fba2018-12-11 10:15:23 -08003171 std::unique_ptr<SessionDescription> answer =
3172 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003173 ASSERT_TRUE(answer != NULL);
3174 ContentInfo* answer_content = answer->GetContentByName("audio");
3175 ASSERT_TRUE(answer_content != NULL);
3176
3177 ASSERT_TRUE(answer_content->rejected);
3178}
3179
3180// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3181// UDP/TLS/RTP/SAVPF.
3182TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3183 f1_.set_secure(SEC_ENABLED);
3184 f2_.set_secure(SEC_ENABLED);
3185 tdf1_.set_secure(SEC_ENABLED);
3186 tdf2_.set_secure(SEC_ENABLED);
3187
Steve Anton6fe1fba2018-12-11 10:15:23 -08003188 std::unique_ptr<SessionDescription> offer =
3189 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003190 ASSERT_TRUE(offer.get() != NULL);
3191 ContentInfo* offer_content = offer->GetContentByName("audio");
3192 ASSERT_TRUE(offer_content != NULL);
3193 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003194 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003195 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3196
Steve Anton6fe1fba2018-12-11 10:15:23 -08003197 std::unique_ptr<SessionDescription> answer =
3198 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003199 ASSERT_TRUE(answer != NULL);
3200
3201 const ContentInfo* answer_content = answer->GetContentByName("audio");
3202 ASSERT_TRUE(answer_content != NULL);
3203 ASSERT_FALSE(answer_content->rejected);
3204
3205 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003206 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003207 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003208}
3209
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003210// Test that we include both SDES and DTLS in the offer, but only include SDES
3211// in the answer if DTLS isn't negotiated.
3212TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3213 f1_.set_secure(SEC_ENABLED);
3214 f2_.set_secure(SEC_ENABLED);
3215 tdf1_.set_secure(SEC_ENABLED);
3216 tdf2_.set_secure(SEC_DISABLED);
3217 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003218 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003219 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003220 const cricket::MediaContentDescription* audio_media_desc;
3221 const cricket::MediaContentDescription* video_media_desc;
3222 const cricket::TransportDescription* audio_trans_desc;
3223 const cricket::TransportDescription* video_trans_desc;
3224
3225 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003226 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003227 ASSERT_TRUE(offer.get() != NULL);
3228
Steve Antonb1c1de12017-12-21 15:14:30 -08003229 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003230 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003231 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003232 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003233 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003234 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3235
3236 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3237 ASSERT_TRUE(audio_trans_desc != NULL);
3238 video_trans_desc = offer->GetTransportDescriptionByName("video");
3239 ASSERT_TRUE(video_trans_desc != NULL);
3240 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3241 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3242
3243 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003244 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003245 ASSERT_TRUE(answer.get() != NULL);
3246
Steve Antonb1c1de12017-12-21 15:14:30 -08003247 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003248 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003249 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003250 ASSERT_TRUE(video_media_desc != NULL);
3251 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3252 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3253
3254 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3255 ASSERT_TRUE(audio_trans_desc != NULL);
3256 video_trans_desc = answer->GetTransportDescriptionByName("video");
3257 ASSERT_TRUE(video_trans_desc != NULL);
3258 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3259 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3260
3261 // Enable DTLS; the answer should now only have DTLS support.
3262 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003263 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003264 ASSERT_TRUE(answer.get() != NULL);
3265
Steve Antonb1c1de12017-12-21 15:14:30 -08003266 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003267 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003268 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003269 ASSERT_TRUE(video_media_desc != NULL);
3270 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3271 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003272 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3273 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003274
3275 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3276 ASSERT_TRUE(audio_trans_desc != NULL);
3277 video_trans_desc = answer->GetTransportDescriptionByName("video");
3278 ASSERT_TRUE(video_trans_desc != NULL);
3279 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3280 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003281
3282 // Try creating offer again. DTLS enabled now, crypto's should be empty
3283 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003284 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003285 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003286 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003287 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003288 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003289 ASSERT_TRUE(video_media_desc != NULL);
3290 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3291 EXPECT_TRUE(video_media_desc->cryptos().empty());
3292
3293 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3294 ASSERT_TRUE(audio_trans_desc != NULL);
3295 video_trans_desc = offer->GetTransportDescriptionByName("video");
3296 ASSERT_TRUE(video_trans_desc != NULL);
3297 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3298 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003299}
3300
3301// Test that an answer can't be created if cryptos are required but the offer is
3302// unsecure.
3303TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003304 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003305 f1_.set_secure(SEC_DISABLED);
3306 tdf1_.set_secure(SEC_DISABLED);
3307 f2_.set_secure(SEC_REQUIRED);
3308 tdf1_.set_secure(SEC_ENABLED);
3309
Steve Anton6fe1fba2018-12-11 10:15:23 -08003310 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003311 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003312 std::unique_ptr<SessionDescription> answer =
3313 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003314 EXPECT_TRUE(answer.get() == NULL);
3315}
3316
3317// Test that we accept a DTLS offer without SDES and create an appropriate
3318// answer.
3319TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3320 f1_.set_secure(SEC_DISABLED);
3321 f2_.set_secure(SEC_ENABLED);
3322 tdf1_.set_secure(SEC_ENABLED);
3323 tdf2_.set_secure(SEC_ENABLED);
3324 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003325 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3326 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3327 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003328
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003329 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003330 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003331 ASSERT_TRUE(offer.get() != NULL);
3332
3333 const AudioContentDescription* audio_offer =
3334 GetFirstAudioContentDescription(offer.get());
3335 ASSERT_TRUE(audio_offer->cryptos().empty());
3336 const VideoContentDescription* video_offer =
3337 GetFirstVideoContentDescription(offer.get());
3338 ASSERT_TRUE(video_offer->cryptos().empty());
3339 const DataContentDescription* data_offer =
3340 GetFirstDataContentDescription(offer.get());
3341 ASSERT_TRUE(data_offer->cryptos().empty());
3342
3343 const cricket::TransportDescription* audio_offer_trans_desc =
3344 offer->GetTransportDescriptionByName("audio");
3345 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3346 const cricket::TransportDescription* video_offer_trans_desc =
3347 offer->GetTransportDescriptionByName("video");
3348 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3349 const cricket::TransportDescription* data_offer_trans_desc =
3350 offer->GetTransportDescriptionByName("data");
3351 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3352
3353 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003354 std::unique_ptr<SessionDescription> answer =
3355 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003356 ASSERT_TRUE(answer.get() != NULL);
3357
3358 const cricket::TransportDescription* audio_answer_trans_desc =
3359 answer->GetTransportDescriptionByName("audio");
3360 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3361 const cricket::TransportDescription* video_answer_trans_desc =
3362 answer->GetTransportDescriptionByName("video");
3363 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3364 const cricket::TransportDescription* data_answer_trans_desc =
3365 answer->GetTransportDescriptionByName("data");
3366 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3367}
3368
3369// Verifies if vad_enabled option is set to false, CN codecs are not present in
3370// offer or answer.
3371TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3372 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003373 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003374 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003375 ASSERT_TRUE(offer.get() != NULL);
3376 const ContentInfo* audio_content = offer->GetContentByName("audio");
3377 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3378
3379 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003380 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003381 ASSERT_TRUE(offer.get() != NULL);
3382 audio_content = offer->GetContentByName("audio");
3383 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003384 std::unique_ptr<SessionDescription> answer =
3385 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003386 ASSERT_TRUE(answer.get() != NULL);
3387 audio_content = answer->GetContentByName("audio");
3388 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3389}
deadbeef44f08192015-12-15 16:20:09 -08003390
zhihuang1c378ed2017-08-17 14:10:50 -07003391// Test that the generated MIDs match the existing offer.
3392TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003393 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003394 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3395 RtpTransceiverDirection::kRecvOnly, kActive,
3396 &opts);
3397 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3398 RtpTransceiverDirection::kRecvOnly, kActive,
3399 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003400 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003401 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3402 RtpTransceiverDirection::kSendRecv, kActive,
3403 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003404 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003405 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003406 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003407 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003408
deadbeef44f08192015-12-15 16:20:09 -08003409 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3410 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3411 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3412 ASSERT_TRUE(audio_content != nullptr);
3413 ASSERT_TRUE(video_content != nullptr);
3414 ASSERT_TRUE(data_content != nullptr);
3415 EXPECT_EQ("audio_modified", audio_content->name);
3416 EXPECT_EQ("video_modified", video_content->name);
3417 EXPECT_EQ("data_modified", data_content->name);
3418}
zhihuangcf5b37c2016-05-05 11:44:35 -07003419
zhihuang1c378ed2017-08-17 14:10:50 -07003420// The following tests verify that the unified plan SDP is supported.
3421// Test that we can create an offer with multiple media sections of same media
3422// type.
3423TEST_F(MediaSessionDescriptionFactoryTest,
3424 CreateOfferWithMultipleAVMediaSections) {
3425 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003426 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3427 RtpTransceiverDirection::kSendRecv, kActive,
3428 &opts);
3429 AttachSenderToMediaDescriptionOptions(
3430 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003431
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003432 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3433 RtpTransceiverDirection::kSendRecv, kActive,
3434 &opts);
3435 AttachSenderToMediaDescriptionOptions(
3436 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003437
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003438 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3439 RtpTransceiverDirection::kSendRecv, kActive,
3440 &opts);
3441 AttachSenderToMediaDescriptionOptions(
3442 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003443
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003444 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3445 RtpTransceiverDirection::kSendRecv, kActive,
3446 &opts);
3447 AttachSenderToMediaDescriptionOptions(
3448 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003449 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003450 ASSERT_TRUE(offer);
3451
3452 ASSERT_EQ(4u, offer->contents().size());
3453 EXPECT_FALSE(offer->contents()[0].rejected);
3454 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003455 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003456 ASSERT_EQ(1u, acd->streams().size());
3457 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003458 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003459
3460 EXPECT_FALSE(offer->contents()[1].rejected);
3461 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003462 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003463 ASSERT_EQ(1u, vcd->streams().size());
3464 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003465 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003466
3467 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003468 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003469 ASSERT_EQ(1u, acd->streams().size());
3470 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003471 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003472
3473 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003474 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003475 ASSERT_EQ(1u, vcd->streams().size());
3476 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003477 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003478}
3479
3480// Test that we can create an answer with multiple media sections of same media
3481// type.
3482TEST_F(MediaSessionDescriptionFactoryTest,
3483 CreateAnswerWithMultipleAVMediaSections) {
3484 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003485 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3486 RtpTransceiverDirection::kSendRecv, kActive,
3487 &opts);
3488 AttachSenderToMediaDescriptionOptions(
3489 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003490
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003491 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3492 RtpTransceiverDirection::kSendRecv, kActive,
3493 &opts);
3494 AttachSenderToMediaDescriptionOptions(
3495 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003496
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003497 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3498 RtpTransceiverDirection::kSendRecv, kActive,
3499 &opts);
3500 AttachSenderToMediaDescriptionOptions(
3501 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003502
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003503 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3504 RtpTransceiverDirection::kSendRecv, kActive,
3505 &opts);
3506 AttachSenderToMediaDescriptionOptions(
3507 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003508
Steve Anton6fe1fba2018-12-11 10:15:23 -08003509 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003510 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003511 std::unique_ptr<SessionDescription> answer =
3512 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003513
3514 ASSERT_EQ(4u, answer->contents().size());
3515 EXPECT_FALSE(answer->contents()[0].rejected);
3516 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003517 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003518 ASSERT_EQ(1u, acd->streams().size());
3519 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003520 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003521
3522 EXPECT_FALSE(answer->contents()[1].rejected);
3523 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003524 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003525 ASSERT_EQ(1u, vcd->streams().size());
3526 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003527 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003528
3529 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003530 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003531 ASSERT_EQ(1u, acd->streams().size());
3532 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003533 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003534
3535 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003536 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003537 ASSERT_EQ(1u, vcd->streams().size());
3538 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003539 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003540}
3541
3542// Test that the media section will be rejected in offer if the corresponding
3543// MediaDescriptionOptions is stopped by the offerer.
3544TEST_F(MediaSessionDescriptionFactoryTest,
3545 CreateOfferWithMediaSectionStoppedByOfferer) {
3546 // Create an offer with two audio sections and one of them is stopped.
3547 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003548 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3549 RtpTransceiverDirection::kSendRecv, kActive,
3550 &offer_opts);
3551 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3552 RtpTransceiverDirection::kInactive, kStopped,
3553 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003554 std::unique_ptr<SessionDescription> offer =
3555 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003556 ASSERT_TRUE(offer);
3557 ASSERT_EQ(2u, offer->contents().size());
3558 EXPECT_FALSE(offer->contents()[0].rejected);
3559 EXPECT_TRUE(offer->contents()[1].rejected);
3560}
3561
3562// Test that the media section will be rejected in answer if the corresponding
3563// MediaDescriptionOptions is stopped by the offerer.
3564TEST_F(MediaSessionDescriptionFactoryTest,
3565 CreateAnswerWithMediaSectionStoppedByOfferer) {
3566 // Create an offer with two audio sections and one of them is stopped.
3567 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003568 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3569 RtpTransceiverDirection::kSendRecv, kActive,
3570 &offer_opts);
3571 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3572 RtpTransceiverDirection::kInactive, kStopped,
3573 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003574 std::unique_ptr<SessionDescription> offer =
3575 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003576 ASSERT_TRUE(offer);
3577 ASSERT_EQ(2u, offer->contents().size());
3578 EXPECT_FALSE(offer->contents()[0].rejected);
3579 EXPECT_TRUE(offer->contents()[1].rejected);
3580
3581 // Create an answer based on the offer.
3582 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003583 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3584 RtpTransceiverDirection::kSendRecv, kActive,
3585 &answer_opts);
3586 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3587 RtpTransceiverDirection::kSendRecv, kActive,
3588 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003589 std::unique_ptr<SessionDescription> answer =
3590 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003591 ASSERT_EQ(2u, answer->contents().size());
3592 EXPECT_FALSE(answer->contents()[0].rejected);
3593 EXPECT_TRUE(answer->contents()[1].rejected);
3594}
3595
3596// Test that the media section will be rejected in answer if the corresponding
3597// MediaDescriptionOptions is stopped by the answerer.
3598TEST_F(MediaSessionDescriptionFactoryTest,
3599 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3600 // Create an offer with two audio sections.
3601 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003602 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3603 RtpTransceiverDirection::kSendRecv, kActive,
3604 &offer_opts);
3605 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3606 RtpTransceiverDirection::kSendRecv, kActive,
3607 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003608 std::unique_ptr<SessionDescription> offer =
3609 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003610 ASSERT_TRUE(offer);
3611 ASSERT_EQ(2u, offer->contents().size());
3612 ASSERT_FALSE(offer->contents()[0].rejected);
3613 ASSERT_FALSE(offer->contents()[1].rejected);
3614
3615 // The answerer rejects one of the audio sections.
3616 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003617 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3618 RtpTransceiverDirection::kSendRecv, kActive,
3619 &answer_opts);
3620 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3621 RtpTransceiverDirection::kInactive, kStopped,
3622 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003623 std::unique_ptr<SessionDescription> answer =
3624 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003625 ASSERT_EQ(2u, answer->contents().size());
3626 EXPECT_FALSE(answer->contents()[0].rejected);
3627 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003628
3629 // The TransportInfo of the rejected m= section is expected to be added in the
3630 // answer.
3631 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003632}
3633
3634// Test the generated media sections has the same order of the
3635// corresponding MediaDescriptionOptions.
3636TEST_F(MediaSessionDescriptionFactoryTest,
3637 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3638 MediaSessionOptions opts;
3639 // This tests put video section first because normally audio comes first by
3640 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003641 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3642 RtpTransceiverDirection::kSendRecv, kActive,
3643 &opts);
3644 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3645 RtpTransceiverDirection::kSendRecv, kActive,
3646 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003647 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003648
3649 ASSERT_TRUE(offer);
3650 ASSERT_EQ(2u, offer->contents().size());
3651 EXPECT_EQ("video", offer->contents()[0].name);
3652 EXPECT_EQ("audio", offer->contents()[1].name);
3653}
3654
3655// Test that different media sections using the same codec have same payload
3656// type.
3657TEST_F(MediaSessionDescriptionFactoryTest,
3658 PayloadTypesSharedByMediaSectionsOfSameType) {
3659 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003660 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3661 RtpTransceiverDirection::kSendRecv, kActive,
3662 &opts);
3663 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3664 RtpTransceiverDirection::kSendRecv, kActive,
3665 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003666 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003667 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003668 ASSERT_TRUE(offer);
3669 ASSERT_EQ(2u, offer->contents().size());
3670 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003671 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003672 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003673 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003674 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3675 ASSERT_EQ(2u, vcd1->codecs().size());
3676 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3677 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3678 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3679 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3680
3681 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003682 std::unique_ptr<SessionDescription> answer =
3683 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003684 ASSERT_TRUE(answer);
3685 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003686 vcd1 = answer->contents()[0].media_description()->as_video();
3687 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003688 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3689 ASSERT_EQ(1u, vcd1->codecs().size());
3690 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3691 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3692}
3693
3694// Test that the codec preference order per media section is respected in
3695// subsequent offer.
3696TEST_F(MediaSessionDescriptionFactoryTest,
3697 CreateOfferRespectsCodecPreferenceOrder) {
3698 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003699 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3700 RtpTransceiverDirection::kSendRecv, kActive,
3701 &opts);
3702 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3703 RtpTransceiverDirection::kSendRecv, kActive,
3704 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003705 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003706 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003707 ASSERT_TRUE(offer);
3708 ASSERT_EQ(2u, offer->contents().size());
3709 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003710 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003711 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003712 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003713 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3714 EXPECT_EQ(video_codecs, vcd1->codecs());
3715 EXPECT_EQ(video_codecs, vcd2->codecs());
3716
3717 // Change the codec preference of the first video section and create a
3718 // follow-up offer.
3719 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3720 vcd1->set_codecs(video_codecs_reverse);
3721 std::unique_ptr<SessionDescription> updated_offer(
3722 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003723 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3724 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003725 // The video codec preference order should be respected.
3726 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3727 EXPECT_EQ(video_codecs, vcd2->codecs());
3728}
3729
3730// Test that the codec preference order per media section is respected in
3731// the answer.
3732TEST_F(MediaSessionDescriptionFactoryTest,
3733 CreateAnswerRespectsCodecPreferenceOrder) {
3734 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003735 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3736 RtpTransceiverDirection::kSendRecv, kActive,
3737 &opts);
3738 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3739 RtpTransceiverDirection::kSendRecv, kActive,
3740 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003741 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003742 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003743 ASSERT_TRUE(offer);
3744 ASSERT_EQ(2u, offer->contents().size());
3745 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003746 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003747 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003748 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003749 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3750 EXPECT_EQ(video_codecs, vcd1->codecs());
3751 EXPECT_EQ(video_codecs, vcd2->codecs());
3752
3753 // Change the codec preference of the first video section and create an
3754 // answer.
3755 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3756 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003757 std::unique_ptr<SessionDescription> answer =
3758 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003759 vcd1 = answer->contents()[0].media_description()->as_video();
3760 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003761 // The video codec preference order should be respected.
3762 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3763 EXPECT_EQ(video_codecs, vcd2->codecs());
3764}
3765
Zhi Huang6f367472017-11-22 13:20:02 -08003766// Test that when creating an answer, the codecs use local parameters instead of
3767// the remote ones.
3768TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3769 const std::string audio_param_name = "audio_param";
3770 const std::string audio_value1 = "audio_v1";
3771 const std::string audio_value2 = "audio_v2";
3772 const std::string video_param_name = "video_param";
3773 const std::string video_value1 = "video_v1";
3774 const std::string video_value2 = "video_v2";
3775
3776 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3777 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3778 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3779 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3780
3781 // Set the parameters for codecs.
3782 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3783 video_codecs1[0].SetParam(video_param_name, video_value1);
3784 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3785 video_codecs2[0].SetParam(video_param_name, video_value2);
3786
3787 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3788 f1_.set_video_codecs(video_codecs1);
3789 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3790 f2_.set_video_codecs(video_codecs2);
3791
3792 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003793 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3794 RtpTransceiverDirection::kSendRecv, kActive,
3795 &opts);
3796 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3797 RtpTransceiverDirection::kSendRecv, kActive,
3798 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003799
Steve Anton6fe1fba2018-12-11 10:15:23 -08003800 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003801 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003802 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3803 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003804 std::string value;
3805 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3806 EXPECT_EQ(audio_value1, value);
3807 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3808 EXPECT_EQ(video_value1, value);
3809
Steve Anton6fe1fba2018-12-11 10:15:23 -08003810 std::unique_ptr<SessionDescription> answer =
3811 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003812 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003813 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3814 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003815 // Use the parameters from the local codecs.
3816 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3817 EXPECT_EQ(audio_value2, value);
3818 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3819 EXPECT_EQ(video_value2, value);
3820}
3821
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003822// Test that matching packetization-mode is part of the criteria for matching
3823// H264 codecs (in addition to profile-level-id). Previously, this was not the
3824// case, so the first H264 codec with the same profile-level-id would match and
3825// the payload type in the answer would be incorrect.
3826// This is a regression test for bugs.webrtc.org/8808
3827TEST_F(MediaSessionDescriptionFactoryTest,
3828 H264MatchCriteriaIncludesPacketizationMode) {
3829 // Create two H264 codecs with the same profile level ID and different
3830 // packetization modes.
3831 VideoCodec h264_pm0(96, "H264");
3832 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3833 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3834 VideoCodec h264_pm1(97, "H264");
3835 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3836 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3837
3838 // Offerer will send both codecs, answerer should choose the one with matching
3839 // packetization mode (and not the first one it sees).
3840 f1_.set_video_codecs({h264_pm0, h264_pm1});
3841 f2_.set_video_codecs({h264_pm1});
3842
3843 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003844 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3845 RtpTransceiverDirection::kSendRecv, kActive,
3846 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003847
Steve Anton6fe1fba2018-12-11 10:15:23 -08003848 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003849 ASSERT_TRUE(offer);
3850
Steve Anton6fe1fba2018-12-11 10:15:23 -08003851 std::unique_ptr<SessionDescription> answer =
3852 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003853 ASSERT_TRUE(answer);
3854
3855 // Answer should have one negotiated codec with packetization-mode=1 using the
3856 // offered payload type.
3857 ASSERT_EQ(1u, answer->contents().size());
3858 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3859 ASSERT_EQ(1u, answer_vcd->codecs().size());
3860 auto answer_codec = answer_vcd->codecs()[0];
3861 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3862}
3863
zhihuangcf5b37c2016-05-05 11:44:35 -07003864class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3865 public:
3866 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003867 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3868 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003869 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3870 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003871 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3872 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003873 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3874 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3875 f1_.set_secure(SEC_ENABLED);
3876 f2_.set_secure(SEC_ENABLED);
3877 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003878 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003879 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003880 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003881 tdf1_.set_secure(SEC_ENABLED);
3882 tdf2_.set_secure(SEC_ENABLED);
3883 }
3884
3885 protected:
3886 MediaSessionDescriptionFactory f1_;
3887 MediaSessionDescriptionFactory f2_;
3888 TransportDescriptionFactory tdf1_;
3889 TransportDescriptionFactory tdf2_;
3890};
3891
3892TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3893 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003894 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003895 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07003896 ASSERT_TRUE(offer.get() != nullptr);
3897 // Set the protocol for all the contents.
3898 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003899 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07003900 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08003901 std::unique_ptr<SessionDescription> answer =
3902 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07003903 const ContentInfo* ac = answer->GetContentByName("audio");
3904 const ContentInfo* vc = answer->GetContentByName("video");
3905 ASSERT_TRUE(ac != nullptr);
3906 ASSERT_TRUE(vc != nullptr);
3907 EXPECT_FALSE(ac->rejected); // the offer is accepted
3908 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003909 const AudioContentDescription* acd = ac->media_description()->as_audio();
3910 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07003911 EXPECT_EQ(GetParam(), acd->protocol());
3912 EXPECT_EQ(GetParam(), vcd->protocol());
3913}
3914
3915INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3916 MediaProtocolTest,
3917 ::testing::ValuesIn(kMediaProtocols));
3918INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3919 MediaProtocolTest,
3920 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003921
3922TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3923 TransportDescriptionFactory tdf;
3924 MediaSessionDescriptionFactory sf(&tdf);
3925 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3926 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3927
3928 // The merged list of codecs should contain any send codecs that are also
3929 // nominally in the recieve codecs list. Payload types should be picked from
3930 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3931 // (set to 1). This equals what happens when the send codecs are used in an
3932 // offer and the receive codecs are used in the following answer.
3933 const std::vector<AudioCodec> sendrecv_codecs =
3934 MAKE_VECTOR(kAudioCodecsAnswer);
3935 const std::vector<AudioCodec> no_codecs;
3936
3937 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3938 << "Please don't change shared test data!";
3939 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3940 << "Please don't change shared test data!";
3941 // Alter iLBC send codec to have zero channels, to test that that is handled
3942 // properly.
3943 send_codecs[1].channels = 0;
3944
3945 // Alther iLBC receive codec to be lowercase, to test that case conversions
3946 // are handled properly.
3947 recv_codecs[2].name = "ilbc";
3948
3949 // Test proper merge
3950 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003951 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3952 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3953 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003954
3955 // Test empty send codecs list
3956 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003957 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3958 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3959 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003960
3961 // Test empty recv codecs list
3962 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003963 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3964 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3965 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003966
3967 // Test all empty codec lists
3968 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003969 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3970 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3971 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003972}
3973
Amit Hilbuch77938e62018-12-21 09:23:38 -08003974// Checks that the RID extensions are added to the video RTP header extensions.
3975// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
3976// not very well defined, as calling set() and immediately get() will yield
3977// an object that is not semantically equivalent to the set object.
3978TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
3979 TransportDescriptionFactory tdf;
3980 MediaSessionDescriptionFactory sf(&tdf);
3981 sf.set_is_unified_plan(true);
3982 cricket::RtpHeaderExtensions extensions;
3983 sf.set_video_rtp_header_extensions(extensions);
3984 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
3985 // Check to see that RID extensions were added to the extension list
3986 EXPECT_GE(result.size(), 2u);
3987 auto rid_extension = std::find_if(
3988 result.begin(), result.end(), [](const RtpExtension& extension) {
3989 return extension.uri == webrtc::RtpExtension::kRidUri;
3990 });
3991 EXPECT_NE(rid_extension, extensions.end());
3992 auto repaired_rid_extension = std::find_if(
3993 result.begin(), result.end(), [](const RtpExtension& extension) {
3994 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
3995 });
3996 EXPECT_NE(repaired_rid_extension, extensions.end());
3997}
3998
3999// Checks that the RID extensions are added to the audio RTP header extensions.
4000// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4001// not very well defined, as calling set() and immediately get() will yield
4002// an object that is not semantically equivalent to the set object.
4003TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4004 TransportDescriptionFactory tdf;
4005 MediaSessionDescriptionFactory sf(&tdf);
4006 sf.set_is_unified_plan(true);
4007 cricket::RtpHeaderExtensions extensions;
4008 sf.set_audio_rtp_header_extensions(extensions);
4009 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4010 // Check to see that RID extensions were added to the extension list
4011 EXPECT_GE(result.size(), 2u);
4012 auto rid_extension = std::find_if(
4013 result.begin(), result.end(), [](const RtpExtension& extension) {
4014 return extension.uri == webrtc::RtpExtension::kRidUri;
4015 });
4016 EXPECT_NE(rid_extension, extensions.end());
4017 auto repaired_rid_extension = std::find_if(
4018 result.begin(), result.end(), [](const RtpExtension& extension) {
4019 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
4020 });
4021 EXPECT_NE(repaired_rid_extension, extensions.end());
4022}
4023
ossu075af922016-06-14 03:29:38 -07004024namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004025// Compare the two vectors of codecs ignoring the payload type.
4026template <class Codec>
4027bool CodecsMatch(const std::vector<Codec>& codecs1,
4028 const std::vector<Codec>& codecs2) {
4029 if (codecs1.size() != codecs2.size()) {
4030 return false;
4031 }
4032
4033 for (size_t i = 0; i < codecs1.size(); ++i) {
4034 if (!codecs1[i].Matches(codecs2[i])) {
4035 return false;
4036 }
4037 }
4038 return true;
4039}
4040
Steve Anton4e70a722017-11-28 14:57:10 -08004041void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004042 TransportDescriptionFactory tdf;
4043 MediaSessionDescriptionFactory sf(&tdf);
4044 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4045 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4046 const std::vector<AudioCodec> sendrecv_codecs =
4047 MAKE_VECTOR(kAudioCodecsAnswer);
4048 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004049
4050 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004051 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4052 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004053
Steve Anton4e70a722017-11-28 14:57:10 -08004054 if (direction == RtpTransceiverDirection::kSendRecv ||
4055 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004056 AttachSenderToMediaDescriptionOptions(
4057 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004058 }
ossu075af922016-06-14 03:29:38 -07004059
Steve Anton6fe1fba2018-12-11 10:15:23 -08004060 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004061 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004062 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004063
4064 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004065 // that the codecs put in are right. This happens when we neither want to
4066 // send nor receive audio. The checks are still in place if at some point
4067 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004068 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004069 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004070 // sendrecv and inactive should both present lists as if the channel was
4071 // to be used for sending and receiving. Inactive essentially means it
4072 // might eventually be used anything, but we don't know more at this
4073 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004074 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004075 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004076 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004077 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004078 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004079 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004080 }
4081 }
4082}
4083
4084static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004085 AudioCodec(0, "codec0", 16000, -1, 1),
4086 AudioCodec(1, "codec1", 8000, 13300, 1),
4087 AudioCodec(2, "codec2", 8000, 64000, 1),
4088 AudioCodec(3, "codec3", 8000, 64000, 1),
4089 AudioCodec(4, "codec4", 8000, 0, 2),
4090 AudioCodec(5, "codec5", 32000, 0, 1),
4091 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004092
zhihuang1c378ed2017-08-17 14:10:50 -07004093/* The codecs groups below are chosen as per the matrix below. The objective
4094 * is to have different sets of codecs in the inputs, to get unique sets of
4095 * codecs after negotiation, depending on offer and answer communication
4096 * directions. One-way directions in the offer should either result in the
4097 * opposite direction in the answer, or an inactive answer. Regardless, the
4098 * choice of codecs should be as if the answer contained the opposite
4099 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004100 *
4101 * | Offer | Answer | Result
4102 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4103 * 0 | x - - | - x - | x - - - -
4104 * 1 | x x x | - x - | x - - x -
4105 * 2 | - x - | x - - | - x - - -
4106 * 3 | x x x | x - - | - x x - -
4107 * 4 | - x - | x x x | - x - - -
4108 * 5 | x - - | x x x | x - - - -
4109 * 6 | x x x | x x x | x x x x x
4110 */
4111// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004112static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4113static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004114// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4115// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004116static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4117static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004118// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004119static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4120static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4121static const int kResultSendrecv_SendCodecs[] = {3, 6};
4122static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4123static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004124
4125template <typename T, int IDXS>
4126std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4127 std::vector<T> out;
4128 out.reserve(IDXS);
4129 for (int idx : indices)
4130 out.push_back(array[idx]);
4131
4132 return out;
4133}
4134
Steve Anton4e70a722017-11-28 14:57:10 -08004135void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4136 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004137 bool add_legacy_stream) {
4138 TransportDescriptionFactory offer_tdf;
4139 TransportDescriptionFactory answer_tdf;
4140 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
4141 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
4142 offer_factory.set_audio_codecs(
4143 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4144 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4145 answer_factory.set_audio_codecs(
4146 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4147 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4148
ossu075af922016-06-14 03:29:38 -07004149 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004150 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4151 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004152
Steve Anton4e70a722017-11-28 14:57:10 -08004153 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004154 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4155 kAudioTrack1, {kMediaStream1}, 1,
4156 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004157 }
4158
Steve Anton6fe1fba2018-12-11 10:15:23 -08004159 std::unique_ptr<SessionDescription> offer =
4160 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004161 ASSERT_TRUE(offer.get() != NULL);
4162
4163 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004164 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4165 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004166
Steve Anton4e70a722017-11-28 14:57:10 -08004167 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004168 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4169 kAudioTrack1, {kMediaStream1}, 1,
4170 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004171 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004172 std::unique_ptr<SessionDescription> answer =
4173 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004174 const ContentInfo* ac = answer->GetContentByName("audio");
4175
zhihuang1c378ed2017-08-17 14:10:50 -07004176 // If the factory didn't add any audio content to the answer, we cannot
4177 // check that the codecs put in are right. This happens when we neither want
4178 // to send nor receive audio. The checks are still in place if at some point
4179 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004180 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004181 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4182 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004183
ossu075af922016-06-14 03:29:38 -07004184 std::vector<AudioCodec> target_codecs;
4185 // For offers with sendrecv or inactive, we should never reply with more
4186 // codecs than offered, with these codec sets.
4187 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004188 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004189 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4190 kResultSendrecv_SendrecvCodecs);
4191 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004192 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004193 target_codecs =
4194 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004195 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004196 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004197 target_codecs =
4198 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004199 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004200 case RtpTransceiverDirection::kSendRecv:
4201 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004202 target_codecs =
4203 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004204 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004205 target_codecs =
4206 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004207 } else {
4208 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4209 kResultSendrecv_SendrecvCodecs);
4210 }
4211 break;
4212 }
4213
zhihuang1c378ed2017-08-17 14:10:50 -07004214 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004215 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004216 bool first = true;
4217 os << "{";
4218 for (const auto& c : codecs) {
4219 os << (first ? " " : ", ") << c.id;
4220 first = false;
4221 }
4222 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004223 return os.Release();
ossu075af922016-06-14 03:29:38 -07004224 };
4225
4226 EXPECT_TRUE(acd->codecs() == target_codecs)
4227 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004228 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4229 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004230 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004231 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4232 << "; got: "
4233 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004234 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004235 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004236 << "Only inactive offers are allowed to not generate any audio "
4237 "content";
ossu075af922016-06-14 03:29:38 -07004238 }
4239}
brandtr03d5fb12016-11-22 03:37:59 -08004240
4241} // namespace
ossu075af922016-06-14 03:29:38 -07004242
4243class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004244 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004245
4246TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004247 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004248}
4249
4250INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
4251 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004252 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4253 RtpTransceiverDirection::kRecvOnly,
4254 RtpTransceiverDirection::kSendRecv,
4255 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004256
4257class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004258 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4259 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004260 bool>> {};
ossu075af922016-06-14 03:29:38 -07004261
4262TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004263 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4264 ::testing::get<1>(GetParam()),
4265 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004266}
4267
zhihuang1c378ed2017-08-17 14:10:50 -07004268INSTANTIATE_TEST_CASE_P(
4269 MediaSessionDescriptionFactoryTest,
4270 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004271 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4272 RtpTransceiverDirection::kRecvOnly,
4273 RtpTransceiverDirection::kSendRecv,
4274 RtpTransceiverDirection::kInactive),
4275 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4276 RtpTransceiverDirection::kRecvOnly,
4277 RtpTransceiverDirection::kSendRecv,
4278 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004279 ::testing::Bool()));