blob: b6be353c36b5a111c04eafac51864acedd7d2af4 [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"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "media/base/test_utils.h"
19#include "p2p/base/p2p_constants.h"
20#include "p2p/base/transport_description.h"
21#include "p2p/base/transport_info.h"
22#include "pc/media_session.h"
23#include "pc/rtp_media_utils.h"
24#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/message_digest.h"
29#include "rtc_base/ssl_adapter.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
Steve Anton2bed3972019-01-04 17:04:30 -0800893// Test that if BUNDLE is enabled and all media sections are rejected then the
894// BUNDLE group is not present in the re-offer.
895TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
896 MediaSessionOptions opts;
897 opts.bundle_enabled = true;
898 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
899 RtpTransceiverDirection::kSendRecv, kActive,
900 &opts);
901 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
902
903 opts.media_description_options[0].stopped = true;
904 std::unique_ptr<SessionDescription> reoffer =
905 f1_.CreateOffer(opts, offer.get());
906
907 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
908}
909
910// Test that if BUNDLE is enabled and the remote re-offer does not include a
911// BUNDLE group since all media sections are rejected, then the re-answer also
912// does not include a BUNDLE group.
913TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
914 MediaSessionOptions opts;
915 opts.bundle_enabled = true;
916 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
917 RtpTransceiverDirection::kSendRecv, kActive,
918 &opts);
919 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
920 std::unique_ptr<SessionDescription> answer =
921 f2_.CreateAnswer(offer.get(), opts, nullptr);
922
923 opts.media_description_options[0].stopped = true;
924 std::unique_ptr<SessionDescription> reoffer =
925 f1_.CreateOffer(opts, offer.get());
926 std::unique_ptr<SessionDescription> reanswer =
927 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
928
929 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
930}
931
932// Test that if BUNDLE is enabled and the previous offerer-tagged media section
933// was rejected then the new offerer-tagged media section is the non-rejected
934// media section.
935TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
936 MediaSessionOptions opts;
937 opts.bundle_enabled = true;
938 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
939 RtpTransceiverDirection::kSendRecv, kActive,
940 &opts);
941 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
942
943 // Reject the audio m= section and add a video m= section.
944 opts.media_description_options[0].stopped = true;
945 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
946 RtpTransceiverDirection::kSendRecv, kActive,
947 &opts);
948 std::unique_ptr<SessionDescription> reoffer =
949 f1_.CreateOffer(opts, offer.get());
950
951 const cricket::ContentGroup* bundle_group =
952 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
953 ASSERT_TRUE(bundle_group);
954 EXPECT_FALSE(bundle_group->HasContentName("audio"));
955 EXPECT_TRUE(bundle_group->HasContentName("video"));
956}
957
958// Test that if BUNDLE is enabled and the previous offerer-tagged media section
959// was rejected and a new media section is added, then the re-answer BUNDLE
960// group will contain only the non-rejected media section.
961TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
962 MediaSessionOptions opts;
963 opts.bundle_enabled = true;
964 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
965 RtpTransceiverDirection::kSendRecv, kActive,
966 &opts);
967 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
968 std::unique_ptr<SessionDescription> answer =
969 f2_.CreateAnswer(offer.get(), opts, nullptr);
970
971 // Reject the audio m= section and add a video m= section.
972 opts.media_description_options[0].stopped = true;
973 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
974 RtpTransceiverDirection::kSendRecv, kActive,
975 &opts);
976 std::unique_ptr<SessionDescription> reoffer =
977 f1_.CreateOffer(opts, offer.get());
978 std::unique_ptr<SessionDescription> reanswer =
979 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
980
981 const cricket::ContentGroup* bundle_group =
982 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
983 ASSERT_TRUE(bundle_group);
984 EXPECT_FALSE(bundle_group->HasContentName("audio"));
985 EXPECT_TRUE(bundle_group->HasContentName("video"));
986}
987
988// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
989// and there is still a non-rejected media section that was in the initial
990// offer, then the ICE credentials do not change in the reoffer offerer-tagged
991// media section.
992TEST_F(MediaSessionDescriptionFactoryTest,
993 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
994 MediaSessionOptions opts;
995 opts.bundle_enabled = true;
996 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
997 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
998 std::unique_ptr<SessionDescription> answer =
999 f2_.CreateAnswer(offer.get(), opts, nullptr);
1000
1001 // Reject the audio m= section.
1002 opts.media_description_options[0].stopped = true;
1003 std::unique_ptr<SessionDescription> reoffer =
1004 f1_.CreateOffer(opts, offer.get());
1005
1006 const TransportDescription* offer_tagged =
1007 offer->GetTransportDescriptionByName("audio");
1008 ASSERT_TRUE(offer_tagged);
1009 const TransportDescription* reoffer_tagged =
1010 reoffer->GetTransportDescriptionByName("video");
1011 ASSERT_TRUE(reoffer_tagged);
1012 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1013 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1014}
1015
1016// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1017// and there is still a non-rejected media section that was in the initial
1018// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1019// media section.
1020TEST_F(MediaSessionDescriptionFactoryTest,
1021 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1022 MediaSessionOptions opts;
1023 opts.bundle_enabled = true;
1024 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1025 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1026 std::unique_ptr<SessionDescription> answer =
1027 f2_.CreateAnswer(offer.get(), opts, nullptr);
1028
1029 // Reject the audio m= section.
1030 opts.media_description_options[0].stopped = true;
1031 std::unique_ptr<SessionDescription> reoffer =
1032 f1_.CreateOffer(opts, offer.get());
1033 std::unique_ptr<SessionDescription> reanswer =
1034 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1035
1036 const TransportDescription* answer_tagged =
1037 answer->GetTransportDescriptionByName("audio");
1038 ASSERT_TRUE(answer_tagged);
1039 const TransportDescription* reanswer_tagged =
1040 reanswer->GetTransportDescriptionByName("video");
1041 ASSERT_TRUE(reanswer_tagged);
1042 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1043 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1044}
1045
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001046// Create an audio, video offer without legacy StreamParams.
1047TEST_F(MediaSessionDescriptionFactoryTest,
1048 TestCreateOfferWithoutLegacyStreams) {
1049 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001050 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001051 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001052 ASSERT_TRUE(offer.get() != NULL);
1053 const ContentInfo* ac = offer->GetContentByName("audio");
1054 const ContentInfo* vc = offer->GetContentByName("video");
1055 ASSERT_TRUE(ac != NULL);
1056 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001057 const AudioContentDescription* acd = ac->media_description()->as_audio();
1058 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059
Yves Gerey665174f2018-06-19 15:03:05 +02001060 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1061 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062}
1063
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001064// Creates an audio+video sendonly offer.
1065TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001066 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001067 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001068 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1069 {kMediaStream1}, 1, &opts);
1070 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1071 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001072
Steve Anton6fe1fba2018-12-11 10:15:23 -08001073 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001074 ASSERT_TRUE(offer.get() != NULL);
1075 EXPECT_EQ(2u, offer->contents().size());
1076 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1077 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1078
Steve Anton4e70a722017-11-28 14:57:10 -08001079 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1080 GetMediaDirection(&offer->contents()[0]));
1081 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1082 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001083}
1084
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001085// Verifies that the order of the media contents in the current
1086// SessionDescription is preserved in the new SessionDescription.
1087TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1088 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001089 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001090
kwiberg31022942016-03-11 14:18:21 -08001091 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001092 ASSERT_TRUE(offer1.get() != NULL);
1093 EXPECT_EQ(1u, offer1->contents().size());
1094 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1095
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001096 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1097 RtpTransceiverDirection::kRecvOnly, kActive,
1098 &opts);
kwiberg31022942016-03-11 14:18:21 -08001099 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001100 f1_.CreateOffer(opts, offer1.get()));
1101 ASSERT_TRUE(offer2.get() != NULL);
1102 EXPECT_EQ(2u, offer2->contents().size());
1103 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1104 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1105
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001106 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1107 RtpTransceiverDirection::kRecvOnly, kActive,
1108 &opts);
kwiberg31022942016-03-11 14:18:21 -08001109 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001110 f1_.CreateOffer(opts, offer2.get()));
1111 ASSERT_TRUE(offer3.get() != NULL);
1112 EXPECT_EQ(3u, offer3->contents().size());
1113 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1114 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1115 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001116}
1117
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001118// Create a typical audio answer, and ensure it matches what we expect.
1119TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1120 f1_.set_secure(SEC_ENABLED);
1121 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001122 std::unique_ptr<SessionDescription> offer =
1123 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001125 std::unique_ptr<SessionDescription> answer =
1126 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001127 const ContentInfo* ac = answer->GetContentByName("audio");
1128 const ContentInfo* vc = answer->GetContentByName("video");
1129 ASSERT_TRUE(ac != NULL);
1130 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001131 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001132 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001133 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001134 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001135 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001136 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1137 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001138 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001139 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140}
1141
jbauchcb560652016-08-04 05:20:32 -07001142// Create a typical audio answer with GCM ciphers enabled, and ensure it
1143// matches what we expect.
1144TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1145 f1_.set_secure(SEC_ENABLED);
1146 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001147 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001148 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001149 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001150 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001151 std::unique_ptr<SessionDescription> answer =
1152 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001153 const ContentInfo* ac = answer->GetContentByName("audio");
1154 const ContentInfo* vc = answer->GetContentByName("video");
1155 ASSERT_TRUE(ac != NULL);
1156 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001157 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001158 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001159 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001160 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001161 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001162 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1163 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001164 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001165 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001166}
1167
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001168// Create a typical video answer, and ensure it matches what we expect.
1169TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1170 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001171 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001172 f1_.set_secure(SEC_ENABLED);
1173 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001174 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001176 std::unique_ptr<SessionDescription> answer =
1177 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178 const ContentInfo* ac = answer->GetContentByName("audio");
1179 const ContentInfo* vc = answer->GetContentByName("video");
1180 ASSERT_TRUE(ac != NULL);
1181 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001182 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1183 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001184 const AudioContentDescription* acd = ac->media_description()->as_audio();
1185 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001186 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001187 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001188 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001189 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001191 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001192 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001193 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001194 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1195 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001196 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001197 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001198}
1199
jbauchcb560652016-08-04 05:20:32 -07001200// Create a typical video answer with GCM ciphers enabled, and ensure it
1201// matches what we expect.
1202TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1203 TestVideoGcmCipher(true, true);
1204}
1205
1206// Create a typical video answer with GCM ciphers enabled for the offer only,
1207// and ensure it matches what we expect.
1208TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1209 TestVideoGcmCipher(true, false);
1210}
1211
1212// Create a typical video answer with GCM ciphers enabled for the answer only,
1213// and ensure it matches what we expect.
1214TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1215 TestVideoGcmCipher(false, true);
1216}
1217
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001219 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001220 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 f1_.set_secure(SEC_ENABLED);
1222 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001223 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001225 std::unique_ptr<SessionDescription> answer =
1226 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001228 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001230 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001231 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1232 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001233 const AudioContentDescription* acd = ac->media_description()->as_audio();
1234 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001236 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001238 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001240 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001241 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001242 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001243 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001244 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001245 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001246 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247}
1248
jbauchcb560652016-08-04 05:20:32 -07001249TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001250 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001251 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001252 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001253 f1_.set_secure(SEC_ENABLED);
1254 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001255 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001256 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001257 std::unique_ptr<SessionDescription> answer =
1258 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001259 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001260 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001261 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001262 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001263 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1264 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001265 const AudioContentDescription* acd = ac->media_description()->as_audio();
1266 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001267 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001268 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001269 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001270 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001271 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001272 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001273 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001274 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001275 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001276 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001277 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001278 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001279}
1280
1281// The use_sctpmap flag should be set in a DataContentDescription by default.
1282// The answer's use_sctpmap flag should match the offer's.
1283TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1284 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001285 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001286 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001287 ASSERT_TRUE(offer.get() != NULL);
1288 ContentInfo* dc_offer = offer->GetContentByName("data");
1289 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001290 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001291 EXPECT_TRUE(dcd_offer->use_sctpmap());
1292
Steve Anton6fe1fba2018-12-11 10:15:23 -08001293 std::unique_ptr<SessionDescription> answer =
1294 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001295 const ContentInfo* dc_answer = answer->GetContentByName("data");
1296 ASSERT_TRUE(dc_answer != NULL);
1297 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001298 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001299 EXPECT_TRUE(dcd_answer->use_sctpmap());
1300}
1301
1302// The answer's use_sctpmap flag should match the offer's.
1303TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1304 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001305 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001306 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001307 ASSERT_TRUE(offer.get() != NULL);
1308 ContentInfo* dc_offer = offer->GetContentByName("data");
1309 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001310 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001311 dcd_offer->set_use_sctpmap(false);
1312
Steve Anton6fe1fba2018-12-11 10:15:23 -08001313 std::unique_ptr<SessionDescription> answer =
1314 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001315 const ContentInfo* dc_answer = answer->GetContentByName("data");
1316 ASSERT_TRUE(dc_answer != NULL);
1317 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001318 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001319 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001320}
1321
deadbeef8b7e9ad2017-05-25 09:38:55 -07001322// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1323// and "TCP/DTLS/SCTP" offers.
1324TEST_F(MediaSessionDescriptionFactoryTest,
1325 TestCreateDataAnswerToDifferentOfferedProtos) {
1326 // Need to enable DTLS offer/answer generation (disabled by default in this
1327 // test).
1328 f1_.set_secure(SEC_ENABLED);
1329 f2_.set_secure(SEC_ENABLED);
1330 tdf1_.set_secure(SEC_ENABLED);
1331 tdf2_.set_secure(SEC_ENABLED);
1332
1333 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001334 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001335 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001336 ASSERT_TRUE(offer.get() != nullptr);
1337 ContentInfo* dc_offer = offer->GetContentByName("data");
1338 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001339 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001340
1341 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1342 "TCP/DTLS/SCTP"};
1343 for (const std::string& proto : protos) {
1344 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001345 std::unique_ptr<SessionDescription> answer =
1346 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001347 const ContentInfo* dc_answer = answer->GetContentByName("data");
1348 ASSERT_TRUE(dc_answer != nullptr);
1349 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001350 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001351 EXPECT_FALSE(dc_answer->rejected);
1352 EXPECT_EQ(proto, dcd_answer->protocol());
1353 }
1354}
1355
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001356// Verifies that the order of the media contents in the offer is preserved in
1357// the answer.
1358TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1359 MediaSessionOptions opts;
1360
1361 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001362 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001363 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001364 ASSERT_TRUE(offer1.get() != NULL);
1365
1366 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001367 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1368 RtpTransceiverDirection::kRecvOnly, kActive,
1369 &opts);
kwiberg31022942016-03-11 14:18:21 -08001370 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001371 f1_.CreateOffer(opts, offer1.get()));
1372 ASSERT_TRUE(offer2.get() != NULL);
1373
1374 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001375 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1376 RtpTransceiverDirection::kRecvOnly, kActive,
1377 &opts);
kwiberg31022942016-03-11 14:18:21 -08001378 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001379 f1_.CreateOffer(opts, offer2.get()));
1380 ASSERT_TRUE(offer3.get() != NULL);
1381
Steve Anton6fe1fba2018-12-11 10:15:23 -08001382 std::unique_ptr<SessionDescription> answer =
1383 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001384 ASSERT_TRUE(answer.get() != NULL);
1385 EXPECT_EQ(3u, answer->contents().size());
1386 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1387 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1388 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1389}
1390
ossu075af922016-06-14 03:29:38 -07001391// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1392// answerer settings.
1393
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001394// This test that the media direction is set to send/receive in an answer if
1395// the offer is send receive.
1396TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001397 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1398 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001399}
1400
1401// This test that the media direction is set to receive only in an answer if
1402// the offer is send only.
1403TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001404 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1405 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001406}
1407
1408// This test that the media direction is set to send only in an answer if
1409// the offer is recv only.
1410TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001411 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1412 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001413}
1414
1415// This test that the media direction is set to inactive in an answer if
1416// the offer is inactive.
1417TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001418 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1419 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001420}
1421
1422// Test that a data content with an unknown protocol is rejected in an answer.
1423TEST_F(MediaSessionDescriptionFactoryTest,
1424 CreateDataAnswerToOfferWithUnknownProtocol) {
1425 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001426 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001427 f1_.set_secure(SEC_ENABLED);
1428 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001429 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001430 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001431 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001432 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001433 ASSERT_TRUE(dcd_offer != NULL);
1434 std::string protocol = "a weird unknown protocol";
1435 dcd_offer->set_protocol(protocol);
1436
Steve Anton6fe1fba2018-12-11 10:15:23 -08001437 std::unique_ptr<SessionDescription> answer =
1438 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001439
1440 const ContentInfo* dc_answer = answer->GetContentByName("data");
1441 ASSERT_TRUE(dc_answer != NULL);
1442 EXPECT_TRUE(dc_answer->rejected);
1443 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001444 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001445 ASSERT_TRUE(dcd_answer != NULL);
1446 EXPECT_EQ(protocol, dcd_answer->protocol());
1447}
1448
1449// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1450TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001451 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001452 f1_.set_secure(SEC_DISABLED);
1453 f2_.set_secure(SEC_DISABLED);
1454 tdf1_.set_secure(SEC_DISABLED);
1455 tdf2_.set_secure(SEC_DISABLED);
1456
Steve Anton6fe1fba2018-12-11 10:15:23 -08001457 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001458 const AudioContentDescription* offer_acd =
1459 GetFirstAudioContentDescription(offer.get());
1460 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001461 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001462
Steve Anton6fe1fba2018-12-11 10:15:23 -08001463 std::unique_ptr<SessionDescription> answer =
1464 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001465
1466 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1467 ASSERT_TRUE(ac_answer != NULL);
1468 EXPECT_FALSE(ac_answer->rejected);
1469
1470 const AudioContentDescription* answer_acd =
1471 GetFirstAudioContentDescription(answer.get());
1472 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001473 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001474}
1475
1476// Create a video offer and answer and ensure the RTP header extensions
1477// matches what we expect.
1478TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1479 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001480 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001481 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1482 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1483 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1484 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1485
Steve Anton6fe1fba2018-12-11 10:15:23 -08001486 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001487 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001488 std::unique_ptr<SessionDescription> answer =
1489 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001490
Yves Gerey665174f2018-06-19 15:03:05 +02001491 EXPECT_EQ(
1492 MAKE_VECTOR(kAudioRtpExtension1),
1493 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1494 EXPECT_EQ(
1495 MAKE_VECTOR(kVideoRtpExtension1),
1496 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1497 EXPECT_EQ(
1498 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1499 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1500 EXPECT_EQ(
1501 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1502 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001503}
1504
jbauch5869f502017-06-29 12:31:36 -07001505TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001506 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001507 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001508 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001509
1510 f1_.set_enable_encrypted_rtp_header_extensions(true);
1511 f2_.set_enable_encrypted_rtp_header_extensions(true);
1512
Yves Gerey665174f2018-06-19 15:03:05 +02001513 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1514 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1515 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1516 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001517
Steve Anton6fe1fba2018-12-11 10:15:23 -08001518 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001519 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001520 std::unique_ptr<SessionDescription> answer =
1521 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001522
Yves Gerey665174f2018-06-19 15:03:05 +02001523 EXPECT_EQ(
1524 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1525 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1526 EXPECT_EQ(
1527 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1528 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1529 EXPECT_EQ(
1530 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1531 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1532 EXPECT_EQ(
1533 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1534 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001535}
1536
1537TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001538 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001539 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001540 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001541
1542 f1_.set_enable_encrypted_rtp_header_extensions(true);
1543
Yves Gerey665174f2018-06-19 15:03:05 +02001544 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1545 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1546 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1547 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001548
Steve Anton6fe1fba2018-12-11 10:15:23 -08001549 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001550 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001551 std::unique_ptr<SessionDescription> answer =
1552 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001553
Yves Gerey665174f2018-06-19 15:03:05 +02001554 EXPECT_EQ(
1555 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1556 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1557 EXPECT_EQ(
1558 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1559 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1560 EXPECT_EQ(
1561 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1562 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1563 EXPECT_EQ(
1564 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1565 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001566}
1567
1568TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001569 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001570 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001571 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001572
1573 f2_.set_enable_encrypted_rtp_header_extensions(true);
1574
Yves Gerey665174f2018-06-19 15:03:05 +02001575 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1576 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1577 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1578 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001579
Steve Anton6fe1fba2018-12-11 10:15:23 -08001580 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001581 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001582 std::unique_ptr<SessionDescription> answer =
1583 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001584
Yves Gerey665174f2018-06-19 15:03:05 +02001585 EXPECT_EQ(
1586 MAKE_VECTOR(kAudioRtpExtension1),
1587 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1588 EXPECT_EQ(
1589 MAKE_VECTOR(kVideoRtpExtension1),
1590 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1591 EXPECT_EQ(
1592 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1593 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1594 EXPECT_EQ(
1595 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1596 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001597}
1598
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001599// Create an audio, video, data answer without legacy StreamParams.
1600TEST_F(MediaSessionDescriptionFactoryTest,
1601 TestCreateAnswerWithoutLegacyStreams) {
1602 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001603 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1604 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001605 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001606 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001607 std::unique_ptr<SessionDescription> answer =
1608 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001609 const ContentInfo* ac = answer->GetContentByName("audio");
1610 const ContentInfo* vc = answer->GetContentByName("video");
1611 const ContentInfo* dc = answer->GetContentByName("data");
1612 ASSERT_TRUE(ac != NULL);
1613 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001614 const AudioContentDescription* acd = ac->media_description()->as_audio();
1615 const VideoContentDescription* vcd = vc->media_description()->as_video();
1616 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001617
1618 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1619 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1620 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1621}
1622
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001623// Create a typical video answer, and ensure it matches what we expect.
1624TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1625 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001626 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1627 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1628 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001629
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001630 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001631 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1632 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1633 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634
kwiberg31022942016-03-11 14:18:21 -08001635 std::unique_ptr<SessionDescription> offer;
1636 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001637
1638 offer_opts.rtcp_mux_enabled = true;
1639 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001640 offer = f1_.CreateOffer(offer_opts, NULL);
1641 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001642 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1643 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1644 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1645 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1646 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1647 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1648 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1649 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1650 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1651 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1652 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1653 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1654
1655 offer_opts.rtcp_mux_enabled = true;
1656 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001657 offer = f1_.CreateOffer(offer_opts, NULL);
1658 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001659 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1660 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1661 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1662 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1663 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1664 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1665 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1666 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1667 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1668 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1669 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1670 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1671
1672 offer_opts.rtcp_mux_enabled = false;
1673 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001674 offer = f1_.CreateOffer(offer_opts, NULL);
1675 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001676 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1677 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1678 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1679 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1680 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1681 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1682 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1683 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1684 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1685 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1686 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1687 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1688
1689 offer_opts.rtcp_mux_enabled = false;
1690 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001691 offer = f1_.CreateOffer(offer_opts, NULL);
1692 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001693 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1694 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1695 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1696 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1697 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1698 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1699 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1700 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1701 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1702 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1703 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1704 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1705}
1706
1707// Create an audio-only answer to a video offer.
1708TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1709 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001710 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1711 RtpTransceiverDirection::kRecvOnly, kActive,
1712 &opts);
1713 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1714 RtpTransceiverDirection::kRecvOnly, kActive,
1715 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001716 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001717 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001718
1719 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001720 std::unique_ptr<SessionDescription> answer =
1721 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001722 const ContentInfo* ac = answer->GetContentByName("audio");
1723 const ContentInfo* vc = answer->GetContentByName("video");
1724 ASSERT_TRUE(ac != NULL);
1725 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001726 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 EXPECT_TRUE(vc->rejected);
1728}
1729
1730// Create an audio-only answer to an offer with data.
1731TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001732 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001733 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001734 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1735 RtpTransceiverDirection::kRecvOnly, kActive,
1736 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001737 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001738 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001739
1740 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001741 std::unique_ptr<SessionDescription> answer =
1742 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001743 const ContentInfo* ac = answer->GetContentByName("audio");
1744 const ContentInfo* dc = answer->GetContentByName("data");
1745 ASSERT_TRUE(ac != NULL);
1746 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001747 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001748 EXPECT_TRUE(dc->rejected);
1749}
1750
1751// Create an answer that rejects the contents which are rejected in the offer.
1752TEST_F(MediaSessionDescriptionFactoryTest,
1753 CreateAnswerToOfferWithRejectedMedia) {
1754 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001755 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1756 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001757 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001758 ASSERT_TRUE(offer.get() != NULL);
1759 ContentInfo* ac = offer->GetContentByName("audio");
1760 ContentInfo* vc = offer->GetContentByName("video");
1761 ContentInfo* dc = offer->GetContentByName("data");
1762 ASSERT_TRUE(ac != NULL);
1763 ASSERT_TRUE(vc != NULL);
1764 ASSERT_TRUE(dc != NULL);
1765 ac->rejected = true;
1766 vc->rejected = true;
1767 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001768 std::unique_ptr<SessionDescription> answer =
1769 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001770 ac = answer->GetContentByName("audio");
1771 vc = answer->GetContentByName("video");
1772 dc = answer->GetContentByName("data");
1773 ASSERT_TRUE(ac != NULL);
1774 ASSERT_TRUE(vc != NULL);
1775 ASSERT_TRUE(dc != NULL);
1776 EXPECT_TRUE(ac->rejected);
1777 EXPECT_TRUE(vc->rejected);
1778 EXPECT_TRUE(dc->rejected);
1779}
1780
Johannes Kron0854eb62018-10-10 22:33:20 +02001781TEST_F(MediaSessionDescriptionFactoryTest,
1782 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1783 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001784 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001785 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001786 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001787 ASSERT_TRUE(offer.get() != NULL);
1788 std::unique_ptr<SessionDescription> answer_no_support(
1789 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001790 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001791
1792 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001793 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001794 ASSERT_TRUE(offer.get() != NULL);
1795 std::unique_ptr<SessionDescription> answer_support(
1796 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001797 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001798}
1799
1800TEST_F(MediaSessionDescriptionFactoryTest,
1801 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1802 MediaSessionOptions opts;
1803 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001804 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001805 MediaContentDescription* video_offer =
1806 offer->GetContentDescriptionByName("video");
1807 ASSERT_TRUE(video_offer);
1808 MediaContentDescription* audio_offer =
1809 offer->GetContentDescriptionByName("audio");
1810 ASSERT_TRUE(audio_offer);
1811
1812 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001813 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1814 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001815
1816 ASSERT_TRUE(offer.get() != NULL);
1817 std::unique_ptr<SessionDescription> answer_no_support(
1818 f2_.CreateAnswer(offer.get(), opts, NULL));
1819 MediaContentDescription* video_answer =
1820 answer_no_support->GetContentDescriptionByName("video");
1821 MediaContentDescription* audio_answer =
1822 answer_no_support->GetContentDescriptionByName("audio");
1823 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001824 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001825 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001826 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001827
1828 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001829 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1830 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001831 ASSERT_TRUE(offer.get() != NULL);
1832 std::unique_ptr<SessionDescription> answer_support(
1833 f2_.CreateAnswer(offer.get(), opts, NULL));
1834 video_answer = answer_support->GetContentDescriptionByName("video");
1835 audio_answer = answer_support->GetContentDescriptionByName("audio");
1836 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001837 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001838 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001839 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001840}
1841
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001842// Create an audio and video offer with:
1843// - one video track
1844// - two audio tracks
1845// - two data tracks
1846// and ensure it matches what we expect. Also updates the initial offer by
1847// adding a new video track and replaces one of the audio tracks.
1848TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1849 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001850 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001851 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1852 {kMediaStream1}, 1, &opts);
1853 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1854 {kMediaStream1}, 1, &opts);
1855 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1856 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001857
Steve Anton4e70a722017-11-28 14:57:10 -08001858 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001859 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1860 {kMediaStream1}, 1, &opts);
1861 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1862 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001863
1864 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001865 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001866
1867 ASSERT_TRUE(offer.get() != NULL);
1868 const ContentInfo* ac = offer->GetContentByName("audio");
1869 const ContentInfo* vc = offer->GetContentByName("video");
1870 const ContentInfo* dc = offer->GetContentByName("data");
1871 ASSERT_TRUE(ac != NULL);
1872 ASSERT_TRUE(vc != NULL);
1873 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001874 const AudioContentDescription* acd = ac->media_description()->as_audio();
1875 const VideoContentDescription* vcd = vc->media_description()->as_video();
1876 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001877 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001878 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001879
1880 const StreamParamsVec& audio_streams = acd->streams();
1881 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001882 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001883 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1884 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1885 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1886 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1887 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1888 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1889
1890 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1891 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001892 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001893
1894 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1895 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001896 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001897
1898 const StreamParamsVec& video_streams = vcd->streams();
1899 ASSERT_EQ(1U, video_streams.size());
1900 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1901 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1902 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1903 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1904
1905 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1906 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001907 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001908
1909 const StreamParamsVec& data_streams = dcd->streams();
1910 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001911 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001912 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1913 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1914 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1915 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1916 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1917 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1918
1919 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001920 dcd->bandwidth()); // default bandwidth (auto)
1921 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001922 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001923
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001924 // Update the offer. Add a new video track that is not synched to the
1925 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001926 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
1927 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001928 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001929 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
1930 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001931 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001932 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
1933 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001934 std::unique_ptr<SessionDescription> updated_offer(
1935 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001936
1937 ASSERT_TRUE(updated_offer.get() != NULL);
1938 ac = updated_offer->GetContentByName("audio");
1939 vc = updated_offer->GetContentByName("video");
1940 dc = updated_offer->GetContentByName("data");
1941 ASSERT_TRUE(ac != NULL);
1942 ASSERT_TRUE(vc != NULL);
1943 ASSERT_TRUE(dc != NULL);
1944 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001945 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001946 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001947 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001948 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001949 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950
1951 EXPECT_EQ(acd->type(), updated_acd->type());
1952 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1953 EXPECT_EQ(vcd->type(), updated_vcd->type());
1954 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1955 EXPECT_EQ(dcd->type(), updated_dcd->type());
1956 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001957 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001958 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001959 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001960 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001961 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001962 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1963
1964 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1965 ASSERT_EQ(2U, updated_audio_streams.size());
1966 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1967 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1968 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1969 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1970 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1971
1972 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1973 ASSERT_EQ(2U, updated_video_streams.size());
1974 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1975 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001976 // All the media streams in one PeerConnection share one RTCP CNAME.
1977 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001978
1979 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1980 ASSERT_EQ(2U, updated_data_streams.size());
1981 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1982 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1983 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1984 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1985 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001986 // The stream correctly got the CNAME from the MediaSessionOptions.
1987 // The Expected RTCP CNAME is the default one as we are using the default
1988 // MediaSessionOptions.
1989 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990}
1991
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001992// Create an offer with simulcast video stream.
1993TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1994 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001995 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1996 RtpTransceiverDirection::kRecvOnly, kActive,
1997 &opts);
1998 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1999 RtpTransceiverDirection::kSendRecv, kActive,
2000 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002001 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002002 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2003 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002004 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002005
2006 ASSERT_TRUE(offer.get() != NULL);
2007 const ContentInfo* vc = offer->GetContentByName("video");
2008 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002009 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002010
2011 const StreamParamsVec& video_streams = vcd->streams();
2012 ASSERT_EQ(1U, video_streams.size());
2013 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2014 const SsrcGroup* sim_ssrc_group =
2015 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2016 ASSERT_TRUE(sim_ssrc_group != NULL);
2017 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2018}
2019
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002020MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2021 const RidDescription& rid1 = ::testing::get<0>(arg);
2022 const RidDescription& rid2 = ::testing::get<1>(arg);
2023 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2024}
2025
2026static void CheckSimulcastInSessionDescription(
2027 const SessionDescription* description,
2028 const std::string& content_name,
2029 const std::vector<RidDescription>& send_rids,
2030 const SimulcastLayerList& send_layers,
2031 const RidDescription& receive_rid,
2032 const SimulcastLayer& receive_layer) {
2033 ASSERT_NE(description, nullptr);
2034 const ContentInfo* content = description->GetContentByName(content_name);
2035 ASSERT_NE(content, nullptr);
2036 const MediaContentDescription* cd = content->media_description();
2037 ASSERT_NE(cd, nullptr);
2038 const StreamParamsVec& streams = cd->streams();
2039 ASSERT_THAT(streams, SizeIs(1));
2040 const StreamParams& stream = streams[0];
2041 ASSERT_THAT(stream.ssrcs, IsEmpty());
2042 EXPECT_TRUE(stream.has_rids());
2043 const std::vector<RidDescription> rids = stream.rids();
2044
2045 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2046
2047 ASSERT_TRUE(cd->has_receive_stream());
2048 const StreamParams& receive_stream = cd->receive_stream();
2049 EXPECT_THAT(receive_stream.ssrcs, IsEmpty());
2050 EXPECT_TRUE(receive_stream.has_rids());
2051 ASSERT_THAT(receive_stream.rids(), SizeIs(1));
2052
2053 EXPECT_EQ(receive_rid.rid, receive_stream.rids()[0].rid);
2054 EXPECT_EQ(receive_rid.direction, receive_stream.rids()[0].direction);
2055
2056 EXPECT_TRUE(cd->HasSimulcast());
2057 const SimulcastDescription& simulcast = cd->simulcast_description();
2058 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2059 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2060
2061 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(1));
2062 EXPECT_EQ(receive_layer, simulcast.receive_layers().GetAllLayers()[0]);
2063}
2064
2065// Create an offer with spec-compliant simulcast video stream.
2066TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2067 MediaSessionOptions opts;
2068 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2069 RtpTransceiverDirection::kSendRecv, kActive,
2070 &opts);
2071 RidDescription receive_rid("1", RidDirection::kReceive);
2072 SimulcastLayer receive_layer(receive_rid.rid, false);
2073 opts.media_description_options[0].receive_rids = {receive_rid};
2074 opts.media_description_options[0].receive_simulcast_layers.AddLayer(
2075 receive_layer);
2076 std::vector<RidDescription> send_rids;
2077 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2078 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2079 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2080 SimulcastLayerList simulcast_layers;
2081 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2082 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2083 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2084 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2085 {kMediaStream1}, send_rids,
2086 simulcast_layers, 0, &opts);
2087 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2088
2089 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
2090 simulcast_layers, receive_rid,
2091 receive_layer);
2092}
2093
2094// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2095// In this scenario, RIDs do not need to be negotiated (there is only one).
2096TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2097 MediaSessionOptions opts;
2098 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2099 RtpTransceiverDirection::kSendRecv, kActive,
2100 &opts);
2101 RidDescription rid("f", RidDirection::kSend);
2102 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2103 {kMediaStream1}, {rid},
2104 SimulcastLayerList(), 0, &opts);
2105 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2106
2107 ASSERT_NE(offer.get(), nullptr);
2108 const ContentInfo* content = offer->GetContentByName("video");
2109 ASSERT_NE(content, nullptr);
2110 const MediaContentDescription* cd = content->media_description();
2111 ASSERT_NE(cd, nullptr);
2112 EXPECT_FALSE(cd->has_receive_stream());
2113 const StreamParamsVec& streams = cd->streams();
2114 ASSERT_THAT(streams, SizeIs(1));
2115 const StreamParams& stream = streams[0];
2116 ASSERT_THAT(stream.ssrcs, IsEmpty());
2117 EXPECT_FALSE(stream.has_rids());
2118 EXPECT_FALSE(cd->HasSimulcast());
2119}
2120
2121// Create an answer with spec-compliant simulcast video stream.
2122// In this scenario, the SFU is the caller requesting that we send Simulcast.
2123TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2124 MediaSessionOptions offer_opts;
2125 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2126 RtpTransceiverDirection::kSendRecv, kActive,
2127 &offer_opts);
2128 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2129 {kMediaStream1}, 1, &offer_opts);
2130 std::unique_ptr<SessionDescription> offer =
2131 f1_.CreateOffer(offer_opts, nullptr);
2132
2133 MediaSessionOptions answer_opts;
2134 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2135 RtpTransceiverDirection::kSendRecv, kActive,
2136 &answer_opts);
2137
2138 RidDescription receive_rid("1", RidDirection::kReceive);
2139 SimulcastLayer receive_layer(receive_rid.rid, false);
2140 answer_opts.media_description_options[0].receive_rids = {receive_rid};
2141 answer_opts.media_description_options[0].receive_simulcast_layers.AddLayer(
2142 receive_layer);
2143 std::vector<RidDescription> rid_descriptions{
2144 RidDescription("f", RidDirection::kSend),
2145 RidDescription("h", RidDirection::kSend),
2146 RidDescription("q", RidDirection::kSend),
2147 };
2148 SimulcastLayerList simulcast_layers;
2149 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2150 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2151 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2152 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2153 {kMediaStream1}, rid_descriptions,
2154 simulcast_layers, 0, &answer_opts);
2155 std::unique_ptr<SessionDescription> answer =
2156 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2157
2158 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
2159 simulcast_layers, receive_rid,
2160 receive_layer);
2161}
2162
2163// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2164// In this scenario, RIDs do not need to be negotiated (there is only one).
2165// Note that RID Direction is not the same as the transceiver direction.
2166TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2167 MediaSessionOptions offer_opts;
2168 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2169 RtpTransceiverDirection::kSendRecv, kActive,
2170 &offer_opts);
2171 RidDescription rid_offer("f", RidDirection::kSend);
2172 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2173 {kMediaStream1}, {rid_offer},
2174 SimulcastLayerList(), 0, &offer_opts);
2175 std::unique_ptr<SessionDescription> offer =
2176 f1_.CreateOffer(offer_opts, nullptr);
2177
2178 MediaSessionOptions answer_opts;
2179 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2180 RtpTransceiverDirection::kSendRecv, kActive,
2181 &answer_opts);
2182
2183 RidDescription rid_answer("f", RidDirection::kReceive);
2184 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2185 {kMediaStream1}, {rid_answer},
2186 SimulcastLayerList(), 0, &answer_opts);
2187 std::unique_ptr<SessionDescription> answer =
2188 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2189
2190 ASSERT_NE(answer.get(), nullptr);
2191 const ContentInfo* content = offer->GetContentByName("video");
2192 ASSERT_NE(content, nullptr);
2193 const MediaContentDescription* cd = content->media_description();
2194 ASSERT_NE(cd, nullptr);
2195 EXPECT_FALSE(cd->has_receive_stream());
2196 const StreamParamsVec& streams = cd->streams();
2197 ASSERT_THAT(streams, SizeIs(1));
2198 const StreamParams& stream = streams[0];
2199 ASSERT_THAT(stream.ssrcs, IsEmpty());
2200 EXPECT_FALSE(stream.has_rids());
2201 EXPECT_FALSE(cd->HasSimulcast());
2202}
2203
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002204// Create an audio and video answer to a standard video offer with:
2205// - one video track
2206// - two audio tracks
2207// - two data tracks
2208// and ensure it matches what we expect. Also updates the initial answer by
2209// adding a new video track and removes one of the audio tracks.
2210TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2211 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002212 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2213 RtpTransceiverDirection::kRecvOnly, kActive,
2214 &offer_opts);
2215 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2216 RtpTransceiverDirection::kRecvOnly, kActive,
2217 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002218 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002219 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2220 RtpTransceiverDirection::kRecvOnly, kActive,
2221 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002222 f1_.set_secure(SEC_ENABLED);
2223 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002224 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002225
zhihuang1c378ed2017-08-17 14:10:50 -07002226 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002227 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2228 RtpTransceiverDirection::kSendRecv, kActive,
2229 &answer_opts);
2230 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2231 RtpTransceiverDirection::kSendRecv, kActive,
2232 &answer_opts);
2233 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2234 {kMediaStream1}, 1, &answer_opts);
2235 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2236 {kMediaStream1}, 1, &answer_opts);
2237 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2238 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002239
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002240 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2241 RtpTransceiverDirection::kSendRecv, kActive,
2242 &answer_opts);
2243 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2244 {kMediaStream1}, 1, &answer_opts);
2245 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2246 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002247 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002248
Steve Anton6fe1fba2018-12-11 10:15:23 -08002249 std::unique_ptr<SessionDescription> answer =
2250 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002251
2252 ASSERT_TRUE(answer.get() != NULL);
2253 const ContentInfo* ac = answer->GetContentByName("audio");
2254 const ContentInfo* vc = answer->GetContentByName("video");
2255 const ContentInfo* dc = answer->GetContentByName("data");
2256 ASSERT_TRUE(ac != NULL);
2257 ASSERT_TRUE(vc != NULL);
2258 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002259 const AudioContentDescription* acd = ac->media_description()->as_audio();
2260 const VideoContentDescription* vcd = vc->media_description()->as_video();
2261 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002262 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2263 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2264 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002265
2266 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002267 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002268
2269 const StreamParamsVec& audio_streams = acd->streams();
2270 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002271 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002272 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2273 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2274 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2275 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2276 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2277 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2278
2279 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2280 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2281
2282 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002283 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002284
2285 const StreamParamsVec& video_streams = vcd->streams();
2286 ASSERT_EQ(1U, video_streams.size());
2287 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2288 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2289 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2290 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2291
2292 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002293 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002294
2295 const StreamParamsVec& data_streams = dcd->streams();
2296 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002297 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002298 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2299 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2300 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2301 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2302 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2303 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2304
2305 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002306 dcd->bandwidth()); // default bandwidth (auto)
2307 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002308
2309 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002310 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002311 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2312 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002313 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2314 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002315 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002316 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002317
2318 ASSERT_TRUE(updated_answer.get() != NULL);
2319 ac = updated_answer->GetContentByName("audio");
2320 vc = updated_answer->GetContentByName("video");
2321 dc = updated_answer->GetContentByName("data");
2322 ASSERT_TRUE(ac != NULL);
2323 ASSERT_TRUE(vc != NULL);
2324 ASSERT_TRUE(dc != NULL);
2325 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002326 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002327 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002328 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002329 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002330 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002331
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002332 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002333 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002334 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002335 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002336 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002337 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2338
2339 EXPECT_EQ(acd->type(), updated_acd->type());
2340 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2341 EXPECT_EQ(vcd->type(), updated_vcd->type());
2342 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2343 EXPECT_EQ(dcd->type(), updated_dcd->type());
2344 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2345
2346 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2347 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002348 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002349
2350 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2351 ASSERT_EQ(2U, updated_video_streams.size());
2352 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2353 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002354 // All media streams in one PeerConnection share one CNAME.
2355 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002356
2357 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2358 ASSERT_EQ(1U, updated_data_streams.size());
2359 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2360}
2361
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002362// Create an updated offer after creating an answer to the original offer and
2363// verify that the codecs that were part of the original answer are not changed
2364// in the updated offer.
2365TEST_F(MediaSessionDescriptionFactoryTest,
2366 RespondentCreatesOfferAfterCreatingAnswer) {
2367 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002368 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002369
Steve Anton6fe1fba2018-12-11 10:15:23 -08002370 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2371 std::unique_ptr<SessionDescription> answer =
2372 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002373
2374 const AudioContentDescription* acd =
2375 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002376 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002377
2378 const VideoContentDescription* vcd =
2379 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002380 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002381
kwiberg31022942016-03-11 14:18:21 -08002382 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383 f2_.CreateOffer(opts, answer.get()));
2384
2385 // The expected audio codecs are the common audio codecs from the first
2386 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2387 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002388 // TODO(wu): |updated_offer| should not include the codec
2389 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002390 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002391 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002392 };
2393
2394 // The expected video codecs are the common video codecs from the first
2395 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2396 // preference order.
2397 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002398 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002399 };
2400
2401 const AudioContentDescription* updated_acd =
2402 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002403 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002404
2405 const VideoContentDescription* updated_vcd =
2406 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002407 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002408}
2409
Steve Anton5c72e712018-12-10 14:25:30 -08002410// Test that a reoffer does not reuse audio codecs from a previous media section
2411// that is being recycled.
2412TEST_F(MediaSessionDescriptionFactoryTest,
2413 ReOfferDoesNotReUseRecycledAudioCodecs) {
2414 f1_.set_video_codecs({});
2415 f2_.set_video_codecs({});
2416
2417 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002418 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2419 RtpTransceiverDirection::kSendRecv, kActive,
2420 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002421 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2422 std::unique_ptr<SessionDescription> answer =
2423 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002424
2425 // Recycle the media section by changing its mid.
2426 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002427 std::unique_ptr<SessionDescription> reoffer =
2428 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002429
2430 // Expect that the results of the first negotiation are ignored. If the m=
2431 // section was not recycled the payload types would match the initial offerer.
2432 const AudioContentDescription* acd =
2433 GetFirstAudioContentDescription(reoffer.get());
2434 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2435}
2436
2437// Test that a reoffer does not reuse video codecs from a previous media section
2438// that is being recycled.
2439TEST_F(MediaSessionDescriptionFactoryTest,
2440 ReOfferDoesNotReUseRecycledVideoCodecs) {
2441 f1_.set_audio_codecs({}, {});
2442 f2_.set_audio_codecs({}, {});
2443
2444 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002445 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2446 RtpTransceiverDirection::kSendRecv, kActive,
2447 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002448 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2449 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002450
2451 // Recycle the media section by changing its mid.
2452 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002453 std::unique_ptr<SessionDescription> reoffer =
2454 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002455
2456 // Expect that the results of the first negotiation are ignored. If the m=
2457 // section was not recycled the payload types would match the initial offerer.
2458 const VideoContentDescription* vcd =
2459 GetFirstVideoContentDescription(reoffer.get());
2460 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2461}
2462
2463// Test that a reanswer does not reuse audio codecs from a previous media
2464// section that is being recycled.
2465TEST_F(MediaSessionDescriptionFactoryTest,
2466 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2467 f1_.set_video_codecs({});
2468 f2_.set_video_codecs({});
2469
2470 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2471 // second offer/answer is forward (|f1_| as offerer).
2472 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002473 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2474 RtpTransceiverDirection::kSendRecv, kActive,
2475 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002476 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2477 std::unique_ptr<SessionDescription> answer =
2478 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002479
2480 // Recycle the media section by changing its mid.
2481 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002482 std::unique_ptr<SessionDescription> reoffer =
2483 f1_.CreateOffer(opts, answer.get());
2484 std::unique_ptr<SessionDescription> reanswer =
2485 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002486
2487 // Expect that the results of the first negotiation are ignored. If the m=
2488 // section was not recycled the payload types would match the initial offerer.
2489 const AudioContentDescription* acd =
2490 GetFirstAudioContentDescription(reanswer.get());
2491 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2492}
2493
2494// Test that a reanswer does not reuse video codecs from a previous media
2495// section that is being recycled.
2496TEST_F(MediaSessionDescriptionFactoryTest,
2497 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2498 f1_.set_audio_codecs({}, {});
2499 f2_.set_audio_codecs({}, {});
2500
2501 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2502 // second offer/answer is forward (|f1_| as offerer).
2503 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002504 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2505 RtpTransceiverDirection::kSendRecv, kActive,
2506 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002507 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2508 std::unique_ptr<SessionDescription> answer =
2509 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002510
2511 // Recycle the media section by changing its mid.
2512 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002513 std::unique_ptr<SessionDescription> reoffer =
2514 f1_.CreateOffer(opts, answer.get());
2515 std::unique_ptr<SessionDescription> reanswer =
2516 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002517
2518 // Expect that the results of the first negotiation are ignored. If the m=
2519 // section was not recycled the payload types would match the initial offerer.
2520 const VideoContentDescription* vcd =
2521 GetFirstVideoContentDescription(reanswer.get());
2522 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2523}
2524
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002525// Create an updated offer after creating an answer to the original offer and
2526// verify that the codecs that were part of the original answer are not changed
2527// in the updated offer. In this test Rtx is enabled.
2528TEST_F(MediaSessionDescriptionFactoryTest,
2529 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2530 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002531 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2532 RtpTransceiverDirection::kRecvOnly, kActive,
2533 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002534 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002535 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002536 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002537 f1_.set_video_codecs(f1_codecs);
2538
2539 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002540 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002541 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002542 f2_.set_video_codecs(f2_codecs);
2543
Steve Anton6fe1fba2018-12-11 10:15:23 -08002544 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002545 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002546 std::unique_ptr<SessionDescription> answer =
2547 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002548
2549 const VideoContentDescription* vcd =
2550 GetFirstVideoContentDescription(answer.get());
2551
2552 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002553 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2554 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002555
2556 EXPECT_EQ(expected_codecs, vcd->codecs());
2557
deadbeef67cf2c12016-04-13 10:07:16 -07002558 // Now, make sure we get same result (except for the order) if |f2_| creates
2559 // an updated offer even though the default payload types between |f1_| and
2560 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002561 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002562 f2_.CreateOffer(opts, answer.get()));
2563 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002564 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002565 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2566
2567 const VideoContentDescription* updated_vcd =
2568 GetFirstVideoContentDescription(updated_answer.get());
2569
2570 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2571}
2572
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002573// Regression test for:
2574// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2575// Existing codecs should always appear before new codecs in re-offers. But
2576// under a specific set of circumstances, the existing RTX codec was ending up
2577// added to the end of the list.
2578TEST_F(MediaSessionDescriptionFactoryTest,
2579 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2580 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002581 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2582 RtpTransceiverDirection::kRecvOnly, kActive,
2583 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002584 // We specifically choose different preferred payload types for VP8 to
2585 // trigger the issue.
2586 cricket::VideoCodec vp8_offerer(100, "VP8");
2587 cricket::VideoCodec vp8_offerer_rtx =
2588 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2589 cricket::VideoCodec vp8_answerer(110, "VP8");
2590 cricket::VideoCodec vp8_answerer_rtx =
2591 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2592 cricket::VideoCodec vp9(120, "VP9");
2593 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2594
2595 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2596 // We also specifically cause the answerer to prefer VP9, such that if it
2597 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2598 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2599 vp8_answerer_rtx};
2600
2601 f1_.set_video_codecs(f1_codecs);
2602 f2_.set_video_codecs(f2_codecs);
2603 std::vector<AudioCodec> audio_codecs;
2604 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2605 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2606
2607 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002608 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002609 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002610 std::unique_ptr<SessionDescription> answer =
2611 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002612
2613 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2614 // But if the bug is triggered, RTX for VP8 ends up last.
2615 std::unique_ptr<SessionDescription> updated_offer(
2616 f2_.CreateOffer(opts, answer.get()));
2617
2618 const VideoContentDescription* vcd =
2619 GetFirstVideoContentDescription(updated_offer.get());
2620 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2621 ASSERT_EQ(4u, codecs.size());
2622 EXPECT_EQ(vp8_offerer, codecs[0]);
2623 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2624 EXPECT_EQ(vp9, codecs[2]);
2625 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002626}
2627
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002628// Create an updated offer that adds video after creating an audio only answer
2629// to the original offer. This test verifies that if a video codec and the RTX
2630// codec have the same default payload type as an audio codec that is already in
2631// use, the added codecs payload types are changed.
2632TEST_F(MediaSessionDescriptionFactoryTest,
2633 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2634 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002635 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002636 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002637 f1_.set_video_codecs(f1_codecs);
2638
2639 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002640 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2641 RtpTransceiverDirection::kRecvOnly, kActive,
2642 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002643
Steve Anton6fe1fba2018-12-11 10:15:23 -08002644 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2645 std::unique_ptr<SessionDescription> answer =
2646 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002647
2648 const AudioContentDescription* acd =
2649 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002650 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002651
2652 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2653 // reference be the same as an audio codec that was negotiated in the
2654 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002655 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002656 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002657
2658 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2659 int used_pl_type = acd->codecs()[0].id;
2660 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002661 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002662 f2_.set_video_codecs(f2_codecs);
2663
kwiberg31022942016-03-11 14:18:21 -08002664 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002665 f2_.CreateOffer(opts, answer.get()));
2666 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002667 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002668 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2669
2670 const AudioContentDescription* updated_acd =
2671 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002672 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002673
2674 const VideoContentDescription* updated_vcd =
2675 GetFirstVideoContentDescription(updated_answer.get());
2676
2677 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002678 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002679 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680 EXPECT_NE(used_pl_type, new_h264_pl_type);
2681 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002682 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002683 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2684 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2685}
2686
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002687// Create an updated offer with RTX after creating an answer to an offer
2688// without RTX, and with different default payload types.
2689// Verify that the added RTX codec references the correct payload type.
2690TEST_F(MediaSessionDescriptionFactoryTest,
2691 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2692 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002693 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002694
2695 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2696 // This creates rtx for H264 with the payload type |f2_| uses.
2697 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2698 f2_.set_video_codecs(f2_codecs);
2699
Steve Anton6fe1fba2018-12-11 10:15:23 -08002700 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002701 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002702 std::unique_ptr<SessionDescription> answer =
2703 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002704
2705 const VideoContentDescription* vcd =
2706 GetFirstVideoContentDescription(answer.get());
2707
2708 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2709 EXPECT_EQ(expected_codecs, vcd->codecs());
2710
2711 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2712 // updated offer, even though the default payload types are different from
2713 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002714 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002715 f2_.CreateOffer(opts, answer.get()));
2716 ASSERT_TRUE(updated_offer);
2717
2718 const VideoContentDescription* updated_vcd =
2719 GetFirstVideoContentDescription(updated_offer.get());
2720
2721 // New offer should attempt to add H263, and RTX for H264.
2722 expected_codecs.push_back(kVideoCodecs2[1]);
2723 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2724 &expected_codecs);
2725 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2726}
2727
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002728// Test that RTX is ignored when there is no associated payload type parameter.
2729TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2730 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002731 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2732 RtpTransceiverDirection::kRecvOnly, kActive,
2733 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002734 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002735 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002736 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 f1_.set_video_codecs(f1_codecs);
2738
2739 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002740 // This creates RTX for H264 with the payload type |f2_| uses.
2741 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002742 f2_.set_video_codecs(f2_codecs);
2743
Steve Anton6fe1fba2018-12-11 10:15:23 -08002744 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002745 ASSERT_TRUE(offer.get() != NULL);
2746 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2747 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2748 // is possible to test that that RTX is dropped when
2749 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002750 MediaContentDescription* media_desc =
2751 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2752 ASSERT_TRUE(media_desc);
2753 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002754 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002755 for (VideoCodec& codec : codecs) {
2756 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2757 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758 }
2759 }
2760 desc->set_codecs(codecs);
2761
Steve Anton6fe1fba2018-12-11 10:15:23 -08002762 std::unique_ptr<SessionDescription> answer =
2763 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002764
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002765 std::vector<std::string> codec_names =
2766 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2767 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2768 cricket::kRtxCodecName));
2769}
2770
2771// Test that RTX will be filtered out in the answer if its associated payload
2772// type doesn't match the local value.
2773TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2774 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002775 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2776 RtpTransceiverDirection::kRecvOnly, kActive,
2777 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002778 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2779 // This creates RTX for H264 in sender.
2780 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2781 f1_.set_video_codecs(f1_codecs);
2782
2783 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2784 // This creates RTX for H263 in receiver.
2785 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2786 f2_.set_video_codecs(f2_codecs);
2787
Steve Anton6fe1fba2018-12-11 10:15:23 -08002788 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002789 ASSERT_TRUE(offer.get() != NULL);
2790 // Associated payload type doesn't match, therefore, RTX codec is removed in
2791 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002792 std::unique_ptr<SessionDescription> answer =
2793 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002794
2795 std::vector<std::string> codec_names =
2796 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2797 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2798 cricket::kRtxCodecName));
2799}
2800
2801// Test that when multiple RTX codecs are offered, only the matched RTX codec
2802// is added in the answer, and the unsupported RTX codec is filtered out.
2803TEST_F(MediaSessionDescriptionFactoryTest,
2804 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2805 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002806 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2807 RtpTransceiverDirection::kRecvOnly, kActive,
2808 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002809 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2810 // This creates RTX for H264-SVC in sender.
2811 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2812 f1_.set_video_codecs(f1_codecs);
2813
2814 // This creates RTX for H264 in sender.
2815 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2816 f1_.set_video_codecs(f1_codecs);
2817
2818 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2819 // This creates RTX for H264 in receiver.
2820 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2821 f2_.set_video_codecs(f2_codecs);
2822
2823 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2824 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002825 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002826 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002827 std::unique_ptr<SessionDescription> answer =
2828 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002829 const VideoContentDescription* vcd =
2830 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002831 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2832 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2833 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002834
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002835 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002836}
2837
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002838// Test that after one RTX codec has been negotiated, a new offer can attempt
2839// to add another.
2840TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2841 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002842 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2843 RtpTransceiverDirection::kRecvOnly, kActive,
2844 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002845 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2846 // This creates RTX for H264 for the offerer.
2847 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2848 f1_.set_video_codecs(f1_codecs);
2849
Steve Anton6fe1fba2018-12-11 10:15:23 -08002850 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002851 ASSERT_TRUE(offer);
2852 const VideoContentDescription* vcd =
2853 GetFirstVideoContentDescription(offer.get());
2854
2855 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2856 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2857 &expected_codecs);
2858 EXPECT_EQ(expected_codecs, vcd->codecs());
2859
2860 // Now, attempt to add RTX for H264-SVC.
2861 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2862 f1_.set_video_codecs(f1_codecs);
2863
kwiberg31022942016-03-11 14:18:21 -08002864 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002865 f1_.CreateOffer(opts, offer.get()));
2866 ASSERT_TRUE(updated_offer);
2867 vcd = GetFirstVideoContentDescription(updated_offer.get());
2868
2869 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2870 &expected_codecs);
2871 EXPECT_EQ(expected_codecs, vcd->codecs());
2872}
2873
Noah Richards2e7a0982015-05-18 14:02:54 -07002874// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2875// generated for each simulcast ssrc and correctly grouped.
2876TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2877 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002878 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2879 RtpTransceiverDirection::kSendRecv, kActive,
2880 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002881 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002882 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2883 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002884
2885 // Use a single real codec, and then add RTX for it.
2886 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002887 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002888 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2889 f1_.set_video_codecs(f1_codecs);
2890
2891 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2892 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002893 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002894 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002895 MediaContentDescription* media_desc =
2896 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2897 ASSERT_TRUE(media_desc);
2898 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002899 const StreamParamsVec& streams = desc->streams();
2900 // Single stream.
2901 ASSERT_EQ(1u, streams.size());
2902 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2903 EXPECT_EQ(6u, streams[0].ssrcs.size());
2904 // And should have a SIM group for the simulcast.
2905 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2906 // And a FID group for RTX.
2907 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002908 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002909 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2910 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002911 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002912 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2913 EXPECT_EQ(3u, fid_ssrcs.size());
2914}
2915
brandtr03d5fb12016-11-22 03:37:59 -08002916// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2917// together with a FEC-FR grouping.
2918TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2919 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002920 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2921 RtpTransceiverDirection::kSendRecv, kActive,
2922 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002923 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002924 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2925 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002926
2927 // Use a single real codec, and then add FlexFEC for it.
2928 std::vector<VideoCodec> f1_codecs;
2929 f1_codecs.push_back(VideoCodec(97, "H264"));
2930 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2931 f1_.set_video_codecs(f1_codecs);
2932
2933 // Ensure that the offer has a single FlexFEC ssrc and that
2934 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002935 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002936 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002937 MediaContentDescription* media_desc =
2938 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2939 ASSERT_TRUE(media_desc);
2940 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002941 const StreamParamsVec& streams = desc->streams();
2942 // Single stream.
2943 ASSERT_EQ(1u, streams.size());
2944 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2945 EXPECT_EQ(2u, streams[0].ssrcs.size());
2946 // And should have a FEC-FR group for FlexFEC.
2947 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2948 std::vector<uint32_t> primary_ssrcs;
2949 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2950 ASSERT_EQ(1u, primary_ssrcs.size());
2951 uint32_t flexfec_ssrc;
2952 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2953 EXPECT_NE(flexfec_ssrc, 0u);
2954}
2955
2956// Test that FlexFEC is disabled for simulcast.
2957// TODO(brandtr): Remove this test when we support simulcast, either through
2958// multiple FlexfecSenders, or through multistream protection.
2959TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2960 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002961 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2962 RtpTransceiverDirection::kSendRecv, kActive,
2963 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002964 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002965 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2966 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002967
2968 // Use a single real codec, and then add FlexFEC for it.
2969 std::vector<VideoCodec> f1_codecs;
2970 f1_codecs.push_back(VideoCodec(97, "H264"));
2971 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2972 f1_.set_video_codecs(f1_codecs);
2973
2974 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2975 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002976 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002977 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002978 MediaContentDescription* media_desc =
2979 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2980 ASSERT_TRUE(media_desc);
2981 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002982 const StreamParamsVec& streams = desc->streams();
2983 // Single stream.
2984 ASSERT_EQ(1u, streams.size());
2985 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2986 EXPECT_EQ(3u, streams[0].ssrcs.size());
2987 // And should have a SIM group for the simulcast.
2988 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2989 // And not a FEC-FR group for FlexFEC.
2990 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2991 std::vector<uint32_t> primary_ssrcs;
2992 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2993 EXPECT_EQ(3u, primary_ssrcs.size());
2994 for (uint32_t primary_ssrc : primary_ssrcs) {
2995 uint32_t flexfec_ssrc;
2996 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2997 }
2998}
2999
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003000// Create an updated offer after creating an answer to the original offer and
3001// verify that the RTP header extensions that were part of the original answer
3002// are not changed in the updated offer.
3003TEST_F(MediaSessionDescriptionFactoryTest,
3004 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3005 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003006 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003007
3008 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3009 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3010 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3011 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3012
Steve Anton6fe1fba2018-12-11 10:15:23 -08003013 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3014 std::unique_ptr<SessionDescription> answer =
3015 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003016
Yves Gerey665174f2018-06-19 15:03:05 +02003017 EXPECT_EQ(
3018 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3019 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3020 EXPECT_EQ(
3021 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3022 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003023
kwiberg31022942016-03-11 14:18:21 -08003024 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003025 f2_.CreateOffer(opts, answer.get()));
3026
3027 // The expected RTP header extensions in the new offer are the resulting
3028 // extensions from the first offer/answer exchange plus the extensions only
3029 // |f2_| offer.
3030 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003031 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003032 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3033 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3034 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003035 };
3036
3037 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003038 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003039 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3040 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3041 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003042 };
3043
3044 const AudioContentDescription* updated_acd =
3045 GetFirstAudioContentDescription(updated_offer.get());
3046 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3047 updated_acd->rtp_header_extensions());
3048
3049 const VideoContentDescription* updated_vcd =
3050 GetFirstVideoContentDescription(updated_offer.get());
3051 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3052 updated_vcd->rtp_header_extensions());
3053}
3054
deadbeefa5b273a2015-08-20 17:30:13 -07003055// Verify that if the same RTP extension URI is used for audio and video, the
3056// same ID is used. Also verify that the ID isn't changed when creating an
3057// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003058TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003059 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003060 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003061
3062 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3063 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3064
Steve Anton6fe1fba2018-12-11 10:15:23 -08003065 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003066
3067 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3068 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003069 const RtpExtension kExpectedVideoRtpExtension[] = {
3070 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003071 };
3072
Yves Gerey665174f2018-06-19 15:03:05 +02003073 EXPECT_EQ(
3074 MAKE_VECTOR(kAudioRtpExtension3),
3075 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3076 EXPECT_EQ(
3077 MAKE_VECTOR(kExpectedVideoRtpExtension),
3078 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003079
3080 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003081 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003082 f1_.CreateOffer(opts, offer.get()));
3083
3084 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003085 GetFirstAudioContentDescription(updated_offer.get())
3086 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003087 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003088 GetFirstVideoContentDescription(updated_offer.get())
3089 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003090}
3091
jbauch5869f502017-06-29 12:31:36 -07003092// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3093TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3094 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003095 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003096
3097 f1_.set_enable_encrypted_rtp_header_extensions(true);
3098 f2_.set_enable_encrypted_rtp_header_extensions(true);
3099
3100 f1_.set_audio_rtp_header_extensions(
3101 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3102 f1_.set_video_rtp_header_extensions(
3103 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3104
Steve Anton6fe1fba2018-12-11 10:15:23 -08003105 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003106
3107 // The extensions that are shared between audio and video should use the same
3108 // id.
3109 const RtpExtension kExpectedVideoRtpExtension[] = {
3110 kVideoRtpExtension3ForEncryption[0],
3111 kAudioRtpExtension3ForEncryptionOffer[1],
3112 kAudioRtpExtension3ForEncryptionOffer[2],
3113 };
3114
Yves Gerey665174f2018-06-19 15:03:05 +02003115 EXPECT_EQ(
3116 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3117 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3118 EXPECT_EQ(
3119 MAKE_VECTOR(kExpectedVideoRtpExtension),
3120 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003121
3122 // Nothing should change when creating a new offer
3123 std::unique_ptr<SessionDescription> updated_offer(
3124 f1_.CreateOffer(opts, offer.get()));
3125
3126 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003127 GetFirstAudioContentDescription(updated_offer.get())
3128 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003129 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003130 GetFirstVideoContentDescription(updated_offer.get())
3131 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003132}
3133
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003134TEST(MediaSessionDescription, CopySessionDescription) {
3135 SessionDescription source;
3136 cricket::ContentGroup group(cricket::CN_AUDIO);
3137 source.AddGroup(group);
3138 AudioContentDescription* acd(new AudioContentDescription());
3139 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3140 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003141 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003142 VideoContentDescription* vcd(new VideoContentDescription());
3143 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3144 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003145 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003146
kwiberg31022942016-03-11 14:18:21 -08003147 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003148 ASSERT_TRUE(copy.get() != NULL);
3149 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3150 const ContentInfo* ac = copy->GetContentByName("audio");
3151 const ContentInfo* vc = copy->GetContentByName("video");
3152 ASSERT_TRUE(ac != NULL);
3153 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003154 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003155 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003156 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3157 EXPECT_EQ(1u, acd->first_ssrc());
3158
Steve Anton5adfafd2017-12-20 16:34:00 -08003159 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003160 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003161 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3162 EXPECT_EQ(2u, vcd->first_ssrc());
3163}
3164
3165// The below TestTransportInfoXXX tests create different offers/answers, and
3166// ensure the TransportInfo in the SessionDescription matches what we expect.
3167TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3168 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003169 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3170 RtpTransceiverDirection::kRecvOnly, kActive,
3171 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003172 TestTransportInfo(true, options, false);
3173}
3174
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003175TEST_F(MediaSessionDescriptionFactoryTest,
3176 TestTransportInfoOfferIceRenomination) {
3177 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003178 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3179 RtpTransceiverDirection::kRecvOnly, kActive,
3180 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003181 options.media_description_options[0]
3182 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003183 TestTransportInfo(true, options, false);
3184}
3185
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003186TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3187 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003188 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3189 RtpTransceiverDirection::kRecvOnly, kActive,
3190 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003191 TestTransportInfo(true, options, true);
3192}
3193
3194TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3195 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003196 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3197 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3198 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003199 TestTransportInfo(true, options, false);
3200}
3201
3202TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003203 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003204 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003205 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3206 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3207 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003208 TestTransportInfo(true, options, true);
3209}
3210
3211TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3212 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003213 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3214 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3215 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003216 options.bundle_enabled = true;
3217 TestTransportInfo(true, options, false);
3218}
3219
3220TEST_F(MediaSessionDescriptionFactoryTest,
3221 TestTransportInfoOfferBundleCurrent) {
3222 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003223 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3224 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3225 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003226 options.bundle_enabled = true;
3227 TestTransportInfo(true, options, true);
3228}
3229
3230TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3231 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003232 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3233 RtpTransceiverDirection::kRecvOnly, kActive,
3234 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003235 TestTransportInfo(false, options, false);
3236}
3237
3238TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003239 TestTransportInfoAnswerIceRenomination) {
3240 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003241 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3242 RtpTransceiverDirection::kRecvOnly, kActive,
3243 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003244 options.media_description_options[0]
3245 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003246 TestTransportInfo(false, options, false);
3247}
3248
3249TEST_F(MediaSessionDescriptionFactoryTest,
3250 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003251 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003252 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3253 RtpTransceiverDirection::kRecvOnly, kActive,
3254 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003255 TestTransportInfo(false, options, true);
3256}
3257
3258TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3259 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003260 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3261 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3262 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003263 TestTransportInfo(false, options, false);
3264}
3265
3266TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003267 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003268 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003269 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3270 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3271 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003272 TestTransportInfo(false, options, true);
3273}
3274
3275TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3276 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003277 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3278 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3279 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003280 options.bundle_enabled = true;
3281 TestTransportInfo(false, options, false);
3282}
3283
3284TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003285 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003286 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003287 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3288 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3289 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003290 options.bundle_enabled = true;
3291 TestTransportInfo(false, options, true);
3292}
3293
3294// Create an offer with bundle enabled and verify the crypto parameters are
3295// the common set of the available cryptos.
3296TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3297 TestCryptoWithBundle(true);
3298}
3299
3300// Create an answer with bundle enabled and verify the crypto parameters are
3301// the common set of the available cryptos.
3302TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3303 TestCryptoWithBundle(false);
3304}
3305
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003306// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3307// DTLS is not enabled locally.
3308TEST_F(MediaSessionDescriptionFactoryTest,
3309 TestOfferDtlsSavpfWithoutDtlsFailed) {
3310 f1_.set_secure(SEC_ENABLED);
3311 f2_.set_secure(SEC_ENABLED);
3312 tdf1_.set_secure(SEC_DISABLED);
3313 tdf2_.set_secure(SEC_DISABLED);
3314
Steve Anton6fe1fba2018-12-11 10:15:23 -08003315 std::unique_ptr<SessionDescription> offer =
3316 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003317 ASSERT_TRUE(offer.get() != NULL);
3318 ContentInfo* offer_content = offer->GetContentByName("audio");
3319 ASSERT_TRUE(offer_content != NULL);
3320 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003321 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003322 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3323
Steve Anton6fe1fba2018-12-11 10:15:23 -08003324 std::unique_ptr<SessionDescription> answer =
3325 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003326 ASSERT_TRUE(answer != NULL);
3327 ContentInfo* answer_content = answer->GetContentByName("audio");
3328 ASSERT_TRUE(answer_content != NULL);
3329
3330 ASSERT_TRUE(answer_content->rejected);
3331}
3332
3333// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3334// UDP/TLS/RTP/SAVPF.
3335TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3336 f1_.set_secure(SEC_ENABLED);
3337 f2_.set_secure(SEC_ENABLED);
3338 tdf1_.set_secure(SEC_ENABLED);
3339 tdf2_.set_secure(SEC_ENABLED);
3340
Steve Anton6fe1fba2018-12-11 10:15:23 -08003341 std::unique_ptr<SessionDescription> offer =
3342 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003343 ASSERT_TRUE(offer.get() != NULL);
3344 ContentInfo* offer_content = offer->GetContentByName("audio");
3345 ASSERT_TRUE(offer_content != NULL);
3346 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003347 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003348 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3349
Steve Anton6fe1fba2018-12-11 10:15:23 -08003350 std::unique_ptr<SessionDescription> answer =
3351 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003352 ASSERT_TRUE(answer != NULL);
3353
3354 const ContentInfo* answer_content = answer->GetContentByName("audio");
3355 ASSERT_TRUE(answer_content != NULL);
3356 ASSERT_FALSE(answer_content->rejected);
3357
3358 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003359 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003360 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003361}
3362
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003363// Test that we include both SDES and DTLS in the offer, but only include SDES
3364// in the answer if DTLS isn't negotiated.
3365TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3366 f1_.set_secure(SEC_ENABLED);
3367 f2_.set_secure(SEC_ENABLED);
3368 tdf1_.set_secure(SEC_ENABLED);
3369 tdf2_.set_secure(SEC_DISABLED);
3370 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003371 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003372 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003373 const cricket::MediaContentDescription* audio_media_desc;
3374 const cricket::MediaContentDescription* video_media_desc;
3375 const cricket::TransportDescription* audio_trans_desc;
3376 const cricket::TransportDescription* video_trans_desc;
3377
3378 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003379 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003380 ASSERT_TRUE(offer.get() != NULL);
3381
Steve Antonb1c1de12017-12-21 15:14:30 -08003382 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003383 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003384 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003385 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003386 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003387 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3388
3389 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3390 ASSERT_TRUE(audio_trans_desc != NULL);
3391 video_trans_desc = offer->GetTransportDescriptionByName("video");
3392 ASSERT_TRUE(video_trans_desc != NULL);
3393 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3394 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3395
3396 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003397 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003398 ASSERT_TRUE(answer.get() != NULL);
3399
Steve Antonb1c1de12017-12-21 15:14:30 -08003400 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003401 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003402 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003403 ASSERT_TRUE(video_media_desc != NULL);
3404 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3405 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3406
3407 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3408 ASSERT_TRUE(audio_trans_desc != NULL);
3409 video_trans_desc = answer->GetTransportDescriptionByName("video");
3410 ASSERT_TRUE(video_trans_desc != NULL);
3411 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3412 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3413
3414 // Enable DTLS; the answer should now only have DTLS support.
3415 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003416 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003417 ASSERT_TRUE(answer.get() != NULL);
3418
Steve Antonb1c1de12017-12-21 15:14:30 -08003419 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003420 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003421 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003422 ASSERT_TRUE(video_media_desc != NULL);
3423 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3424 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003425 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3426 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003427
3428 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3429 ASSERT_TRUE(audio_trans_desc != NULL);
3430 video_trans_desc = answer->GetTransportDescriptionByName("video");
3431 ASSERT_TRUE(video_trans_desc != NULL);
3432 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3433 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003434
3435 // Try creating offer again. DTLS enabled now, crypto's should be empty
3436 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003437 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003438 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003439 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003440 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003441 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003442 ASSERT_TRUE(video_media_desc != NULL);
3443 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3444 EXPECT_TRUE(video_media_desc->cryptos().empty());
3445
3446 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3447 ASSERT_TRUE(audio_trans_desc != NULL);
3448 video_trans_desc = offer->GetTransportDescriptionByName("video");
3449 ASSERT_TRUE(video_trans_desc != NULL);
3450 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3451 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003452}
3453
3454// Test that an answer can't be created if cryptos are required but the offer is
3455// unsecure.
3456TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003457 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003458 f1_.set_secure(SEC_DISABLED);
3459 tdf1_.set_secure(SEC_DISABLED);
3460 f2_.set_secure(SEC_REQUIRED);
3461 tdf1_.set_secure(SEC_ENABLED);
3462
Steve Anton6fe1fba2018-12-11 10:15:23 -08003463 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003464 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003465 std::unique_ptr<SessionDescription> answer =
3466 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003467 EXPECT_TRUE(answer.get() == NULL);
3468}
3469
3470// Test that we accept a DTLS offer without SDES and create an appropriate
3471// answer.
3472TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3473 f1_.set_secure(SEC_DISABLED);
3474 f2_.set_secure(SEC_ENABLED);
3475 tdf1_.set_secure(SEC_ENABLED);
3476 tdf2_.set_secure(SEC_ENABLED);
3477 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003478 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3479 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3480 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003481
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003482 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003483 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003484 ASSERT_TRUE(offer.get() != NULL);
3485
3486 const AudioContentDescription* audio_offer =
3487 GetFirstAudioContentDescription(offer.get());
3488 ASSERT_TRUE(audio_offer->cryptos().empty());
3489 const VideoContentDescription* video_offer =
3490 GetFirstVideoContentDescription(offer.get());
3491 ASSERT_TRUE(video_offer->cryptos().empty());
3492 const DataContentDescription* data_offer =
3493 GetFirstDataContentDescription(offer.get());
3494 ASSERT_TRUE(data_offer->cryptos().empty());
3495
3496 const cricket::TransportDescription* audio_offer_trans_desc =
3497 offer->GetTransportDescriptionByName("audio");
3498 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3499 const cricket::TransportDescription* video_offer_trans_desc =
3500 offer->GetTransportDescriptionByName("video");
3501 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3502 const cricket::TransportDescription* data_offer_trans_desc =
3503 offer->GetTransportDescriptionByName("data");
3504 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3505
3506 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003507 std::unique_ptr<SessionDescription> answer =
3508 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003509 ASSERT_TRUE(answer.get() != NULL);
3510
3511 const cricket::TransportDescription* audio_answer_trans_desc =
3512 answer->GetTransportDescriptionByName("audio");
3513 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3514 const cricket::TransportDescription* video_answer_trans_desc =
3515 answer->GetTransportDescriptionByName("video");
3516 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3517 const cricket::TransportDescription* data_answer_trans_desc =
3518 answer->GetTransportDescriptionByName("data");
3519 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3520}
3521
3522// Verifies if vad_enabled option is set to false, CN codecs are not present in
3523// offer or answer.
3524TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3525 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003526 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003527 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003528 ASSERT_TRUE(offer.get() != NULL);
3529 const ContentInfo* audio_content = offer->GetContentByName("audio");
3530 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3531
3532 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003533 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003534 ASSERT_TRUE(offer.get() != NULL);
3535 audio_content = offer->GetContentByName("audio");
3536 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003537 std::unique_ptr<SessionDescription> answer =
3538 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003539 ASSERT_TRUE(answer.get() != NULL);
3540 audio_content = answer->GetContentByName("audio");
3541 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3542}
deadbeef44f08192015-12-15 16:20:09 -08003543
zhihuang1c378ed2017-08-17 14:10:50 -07003544// Test that the generated MIDs match the existing offer.
3545TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003546 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003547 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3548 RtpTransceiverDirection::kRecvOnly, kActive,
3549 &opts);
3550 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3551 RtpTransceiverDirection::kRecvOnly, kActive,
3552 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003553 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003554 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3555 RtpTransceiverDirection::kSendRecv, kActive,
3556 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003557 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003558 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003559 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003560 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003561
deadbeef44f08192015-12-15 16:20:09 -08003562 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3563 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3564 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3565 ASSERT_TRUE(audio_content != nullptr);
3566 ASSERT_TRUE(video_content != nullptr);
3567 ASSERT_TRUE(data_content != nullptr);
3568 EXPECT_EQ("audio_modified", audio_content->name);
3569 EXPECT_EQ("video_modified", video_content->name);
3570 EXPECT_EQ("data_modified", data_content->name);
3571}
zhihuangcf5b37c2016-05-05 11:44:35 -07003572
zhihuang1c378ed2017-08-17 14:10:50 -07003573// The following tests verify that the unified plan SDP is supported.
3574// Test that we can create an offer with multiple media sections of same media
3575// type.
3576TEST_F(MediaSessionDescriptionFactoryTest,
3577 CreateOfferWithMultipleAVMediaSections) {
3578 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003579 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3580 RtpTransceiverDirection::kSendRecv, kActive,
3581 &opts);
3582 AttachSenderToMediaDescriptionOptions(
3583 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003584
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003585 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3586 RtpTransceiverDirection::kSendRecv, kActive,
3587 &opts);
3588 AttachSenderToMediaDescriptionOptions(
3589 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003590
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003591 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3592 RtpTransceiverDirection::kSendRecv, kActive,
3593 &opts);
3594 AttachSenderToMediaDescriptionOptions(
3595 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003596
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003597 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3598 RtpTransceiverDirection::kSendRecv, kActive,
3599 &opts);
3600 AttachSenderToMediaDescriptionOptions(
3601 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003602 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003603 ASSERT_TRUE(offer);
3604
3605 ASSERT_EQ(4u, offer->contents().size());
3606 EXPECT_FALSE(offer->contents()[0].rejected);
3607 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003608 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003609 ASSERT_EQ(1u, acd->streams().size());
3610 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003611 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003612
3613 EXPECT_FALSE(offer->contents()[1].rejected);
3614 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003615 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003616 ASSERT_EQ(1u, vcd->streams().size());
3617 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003618 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003619
3620 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003621 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003622 ASSERT_EQ(1u, acd->streams().size());
3623 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003624 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003625
3626 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003627 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003628 ASSERT_EQ(1u, vcd->streams().size());
3629 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003630 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003631}
3632
3633// Test that we can create an answer with multiple media sections of same media
3634// type.
3635TEST_F(MediaSessionDescriptionFactoryTest,
3636 CreateAnswerWithMultipleAVMediaSections) {
3637 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003638 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3639 RtpTransceiverDirection::kSendRecv, kActive,
3640 &opts);
3641 AttachSenderToMediaDescriptionOptions(
3642 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003643
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003644 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3645 RtpTransceiverDirection::kSendRecv, kActive,
3646 &opts);
3647 AttachSenderToMediaDescriptionOptions(
3648 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003649
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003650 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3651 RtpTransceiverDirection::kSendRecv, kActive,
3652 &opts);
3653 AttachSenderToMediaDescriptionOptions(
3654 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003655
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003656 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3657 RtpTransceiverDirection::kSendRecv, kActive,
3658 &opts);
3659 AttachSenderToMediaDescriptionOptions(
3660 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003661
Steve Anton6fe1fba2018-12-11 10:15:23 -08003662 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003663 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003664 std::unique_ptr<SessionDescription> answer =
3665 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003666
3667 ASSERT_EQ(4u, answer->contents().size());
3668 EXPECT_FALSE(answer->contents()[0].rejected);
3669 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003670 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003671 ASSERT_EQ(1u, acd->streams().size());
3672 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003673 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003674
3675 EXPECT_FALSE(answer->contents()[1].rejected);
3676 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003677 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003678 ASSERT_EQ(1u, vcd->streams().size());
3679 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003680 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003681
3682 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003683 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003684 ASSERT_EQ(1u, acd->streams().size());
3685 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003686 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003687
3688 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003689 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003690 ASSERT_EQ(1u, vcd->streams().size());
3691 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003692 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003693}
3694
3695// Test that the media section will be rejected in offer if the corresponding
3696// MediaDescriptionOptions is stopped by the offerer.
3697TEST_F(MediaSessionDescriptionFactoryTest,
3698 CreateOfferWithMediaSectionStoppedByOfferer) {
3699 // Create an offer with two audio sections and one of them is stopped.
3700 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003701 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3702 RtpTransceiverDirection::kSendRecv, kActive,
3703 &offer_opts);
3704 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3705 RtpTransceiverDirection::kInactive, kStopped,
3706 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003707 std::unique_ptr<SessionDescription> offer =
3708 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003709 ASSERT_TRUE(offer);
3710 ASSERT_EQ(2u, offer->contents().size());
3711 EXPECT_FALSE(offer->contents()[0].rejected);
3712 EXPECT_TRUE(offer->contents()[1].rejected);
3713}
3714
3715// Test that the media section will be rejected in answer if the corresponding
3716// MediaDescriptionOptions is stopped by the offerer.
3717TEST_F(MediaSessionDescriptionFactoryTest,
3718 CreateAnswerWithMediaSectionStoppedByOfferer) {
3719 // Create an offer with two audio sections and one of them is stopped.
3720 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003721 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3722 RtpTransceiverDirection::kSendRecv, kActive,
3723 &offer_opts);
3724 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3725 RtpTransceiverDirection::kInactive, kStopped,
3726 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003727 std::unique_ptr<SessionDescription> offer =
3728 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003729 ASSERT_TRUE(offer);
3730 ASSERT_EQ(2u, offer->contents().size());
3731 EXPECT_FALSE(offer->contents()[0].rejected);
3732 EXPECT_TRUE(offer->contents()[1].rejected);
3733
3734 // Create an answer based on the offer.
3735 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003736 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3737 RtpTransceiverDirection::kSendRecv, kActive,
3738 &answer_opts);
3739 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3740 RtpTransceiverDirection::kSendRecv, kActive,
3741 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003742 std::unique_ptr<SessionDescription> answer =
3743 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003744 ASSERT_EQ(2u, answer->contents().size());
3745 EXPECT_FALSE(answer->contents()[0].rejected);
3746 EXPECT_TRUE(answer->contents()[1].rejected);
3747}
3748
3749// Test that the media section will be rejected in answer if the corresponding
3750// MediaDescriptionOptions is stopped by the answerer.
3751TEST_F(MediaSessionDescriptionFactoryTest,
3752 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3753 // Create an offer with two audio sections.
3754 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003755 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3756 RtpTransceiverDirection::kSendRecv, kActive,
3757 &offer_opts);
3758 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3759 RtpTransceiverDirection::kSendRecv, kActive,
3760 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003761 std::unique_ptr<SessionDescription> offer =
3762 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003763 ASSERT_TRUE(offer);
3764 ASSERT_EQ(2u, offer->contents().size());
3765 ASSERT_FALSE(offer->contents()[0].rejected);
3766 ASSERT_FALSE(offer->contents()[1].rejected);
3767
3768 // The answerer rejects one of the audio sections.
3769 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003770 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3771 RtpTransceiverDirection::kSendRecv, kActive,
3772 &answer_opts);
3773 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3774 RtpTransceiverDirection::kInactive, kStopped,
3775 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003776 std::unique_ptr<SessionDescription> answer =
3777 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003778 ASSERT_EQ(2u, answer->contents().size());
3779 EXPECT_FALSE(answer->contents()[0].rejected);
3780 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003781
3782 // The TransportInfo of the rejected m= section is expected to be added in the
3783 // answer.
3784 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003785}
3786
3787// Test the generated media sections has the same order of the
3788// corresponding MediaDescriptionOptions.
3789TEST_F(MediaSessionDescriptionFactoryTest,
3790 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3791 MediaSessionOptions opts;
3792 // This tests put video section first because normally audio comes first by
3793 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003794 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3795 RtpTransceiverDirection::kSendRecv, kActive,
3796 &opts);
3797 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3798 RtpTransceiverDirection::kSendRecv, kActive,
3799 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003800 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003801
3802 ASSERT_TRUE(offer);
3803 ASSERT_EQ(2u, offer->contents().size());
3804 EXPECT_EQ("video", offer->contents()[0].name);
3805 EXPECT_EQ("audio", offer->contents()[1].name);
3806}
3807
3808// Test that different media sections using the same codec have same payload
3809// type.
3810TEST_F(MediaSessionDescriptionFactoryTest,
3811 PayloadTypesSharedByMediaSectionsOfSameType) {
3812 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003813 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3814 RtpTransceiverDirection::kSendRecv, kActive,
3815 &opts);
3816 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3817 RtpTransceiverDirection::kSendRecv, kActive,
3818 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003819 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003820 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003821 ASSERT_TRUE(offer);
3822 ASSERT_EQ(2u, offer->contents().size());
3823 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003824 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003825 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003826 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003827 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3828 ASSERT_EQ(2u, vcd1->codecs().size());
3829 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3830 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3831 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3832 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3833
3834 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003835 std::unique_ptr<SessionDescription> answer =
3836 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003837 ASSERT_TRUE(answer);
3838 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003839 vcd1 = answer->contents()[0].media_description()->as_video();
3840 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003841 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3842 ASSERT_EQ(1u, vcd1->codecs().size());
3843 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3844 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3845}
3846
3847// Test that the codec preference order per media section is respected in
3848// subsequent offer.
3849TEST_F(MediaSessionDescriptionFactoryTest,
3850 CreateOfferRespectsCodecPreferenceOrder) {
3851 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003852 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3853 RtpTransceiverDirection::kSendRecv, kActive,
3854 &opts);
3855 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3856 RtpTransceiverDirection::kSendRecv, kActive,
3857 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003858 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003859 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003860 ASSERT_TRUE(offer);
3861 ASSERT_EQ(2u, offer->contents().size());
3862 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003863 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003864 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003865 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003866 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3867 EXPECT_EQ(video_codecs, vcd1->codecs());
3868 EXPECT_EQ(video_codecs, vcd2->codecs());
3869
3870 // Change the codec preference of the first video section and create a
3871 // follow-up offer.
3872 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3873 vcd1->set_codecs(video_codecs_reverse);
3874 std::unique_ptr<SessionDescription> updated_offer(
3875 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003876 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3877 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003878 // The video codec preference order should be respected.
3879 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3880 EXPECT_EQ(video_codecs, vcd2->codecs());
3881}
3882
3883// Test that the codec preference order per media section is respected in
3884// the answer.
3885TEST_F(MediaSessionDescriptionFactoryTest,
3886 CreateAnswerRespectsCodecPreferenceOrder) {
3887 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003888 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3889 RtpTransceiverDirection::kSendRecv, kActive,
3890 &opts);
3891 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3892 RtpTransceiverDirection::kSendRecv, kActive,
3893 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003894 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003895 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003896 ASSERT_TRUE(offer);
3897 ASSERT_EQ(2u, offer->contents().size());
3898 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003899 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003900 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003901 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003902 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3903 EXPECT_EQ(video_codecs, vcd1->codecs());
3904 EXPECT_EQ(video_codecs, vcd2->codecs());
3905
3906 // Change the codec preference of the first video section and create an
3907 // answer.
3908 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3909 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003910 std::unique_ptr<SessionDescription> answer =
3911 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003912 vcd1 = answer->contents()[0].media_description()->as_video();
3913 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003914 // The video codec preference order should be respected.
3915 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3916 EXPECT_EQ(video_codecs, vcd2->codecs());
3917}
3918
Zhi Huang6f367472017-11-22 13:20:02 -08003919// Test that when creating an answer, the codecs use local parameters instead of
3920// the remote ones.
3921TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3922 const std::string audio_param_name = "audio_param";
3923 const std::string audio_value1 = "audio_v1";
3924 const std::string audio_value2 = "audio_v2";
3925 const std::string video_param_name = "video_param";
3926 const std::string video_value1 = "video_v1";
3927 const std::string video_value2 = "video_v2";
3928
3929 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3930 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3931 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3932 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3933
3934 // Set the parameters for codecs.
3935 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3936 video_codecs1[0].SetParam(video_param_name, video_value1);
3937 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3938 video_codecs2[0].SetParam(video_param_name, video_value2);
3939
3940 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3941 f1_.set_video_codecs(video_codecs1);
3942 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3943 f2_.set_video_codecs(video_codecs2);
3944
3945 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003946 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3947 RtpTransceiverDirection::kSendRecv, kActive,
3948 &opts);
3949 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3950 RtpTransceiverDirection::kSendRecv, kActive,
3951 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003952
Steve Anton6fe1fba2018-12-11 10:15:23 -08003953 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003954 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003955 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3956 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003957 std::string value;
3958 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3959 EXPECT_EQ(audio_value1, value);
3960 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3961 EXPECT_EQ(video_value1, value);
3962
Steve Anton6fe1fba2018-12-11 10:15:23 -08003963 std::unique_ptr<SessionDescription> answer =
3964 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003965 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003966 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3967 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003968 // Use the parameters from the local codecs.
3969 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3970 EXPECT_EQ(audio_value2, value);
3971 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3972 EXPECT_EQ(video_value2, value);
3973}
3974
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003975// Test that matching packetization-mode is part of the criteria for matching
3976// H264 codecs (in addition to profile-level-id). Previously, this was not the
3977// case, so the first H264 codec with the same profile-level-id would match and
3978// the payload type in the answer would be incorrect.
3979// This is a regression test for bugs.webrtc.org/8808
3980TEST_F(MediaSessionDescriptionFactoryTest,
3981 H264MatchCriteriaIncludesPacketizationMode) {
3982 // Create two H264 codecs with the same profile level ID and different
3983 // packetization modes.
3984 VideoCodec h264_pm0(96, "H264");
3985 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3986 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3987 VideoCodec h264_pm1(97, "H264");
3988 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3989 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3990
3991 // Offerer will send both codecs, answerer should choose the one with matching
3992 // packetization mode (and not the first one it sees).
3993 f1_.set_video_codecs({h264_pm0, h264_pm1});
3994 f2_.set_video_codecs({h264_pm1});
3995
3996 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003997 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3998 RtpTransceiverDirection::kSendRecv, kActive,
3999 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004000
Steve Anton6fe1fba2018-12-11 10:15:23 -08004001 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004002 ASSERT_TRUE(offer);
4003
Steve Anton6fe1fba2018-12-11 10:15:23 -08004004 std::unique_ptr<SessionDescription> answer =
4005 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004006 ASSERT_TRUE(answer);
4007
4008 // Answer should have one negotiated codec with packetization-mode=1 using the
4009 // offered payload type.
4010 ASSERT_EQ(1u, answer->contents().size());
4011 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4012 ASSERT_EQ(1u, answer_vcd->codecs().size());
4013 auto answer_codec = answer_vcd->codecs()[0];
4014 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4015}
4016
zhihuangcf5b37c2016-05-05 11:44:35 -07004017class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4018 public:
4019 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07004020 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4021 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004022 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
4023 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004024 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4025 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004026 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
4027 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
4028 f1_.set_secure(SEC_ENABLED);
4029 f2_.set_secure(SEC_ENABLED);
4030 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004031 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004032 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004033 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004034 tdf1_.set_secure(SEC_ENABLED);
4035 tdf2_.set_secure(SEC_ENABLED);
4036 }
4037
4038 protected:
4039 MediaSessionDescriptionFactory f1_;
4040 MediaSessionDescriptionFactory f2_;
4041 TransportDescriptionFactory tdf1_;
4042 TransportDescriptionFactory tdf2_;
4043};
4044
4045TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4046 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004047 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004048 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004049 ASSERT_TRUE(offer.get() != nullptr);
4050 // Set the protocol for all the contents.
4051 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004052 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004053 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004054 std::unique_ptr<SessionDescription> answer =
4055 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004056 const ContentInfo* ac = answer->GetContentByName("audio");
4057 const ContentInfo* vc = answer->GetContentByName("video");
4058 ASSERT_TRUE(ac != nullptr);
4059 ASSERT_TRUE(vc != nullptr);
4060 EXPECT_FALSE(ac->rejected); // the offer is accepted
4061 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004062 const AudioContentDescription* acd = ac->media_description()->as_audio();
4063 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004064 EXPECT_EQ(GetParam(), acd->protocol());
4065 EXPECT_EQ(GetParam(), vcd->protocol());
4066}
4067
4068INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
4069 MediaProtocolTest,
4070 ::testing::ValuesIn(kMediaProtocols));
4071INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
4072 MediaProtocolTest,
4073 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004074
4075TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4076 TransportDescriptionFactory tdf;
4077 MediaSessionDescriptionFactory sf(&tdf);
4078 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4079 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4080
4081 // The merged list of codecs should contain any send codecs that are also
4082 // nominally in the recieve codecs list. Payload types should be picked from
4083 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4084 // (set to 1). This equals what happens when the send codecs are used in an
4085 // offer and the receive codecs are used in the following answer.
4086 const std::vector<AudioCodec> sendrecv_codecs =
4087 MAKE_VECTOR(kAudioCodecsAnswer);
4088 const std::vector<AudioCodec> no_codecs;
4089
4090 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4091 << "Please don't change shared test data!";
4092 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4093 << "Please don't change shared test data!";
4094 // Alter iLBC send codec to have zero channels, to test that that is handled
4095 // properly.
4096 send_codecs[1].channels = 0;
4097
4098 // Alther iLBC receive codec to be lowercase, to test that case conversions
4099 // are handled properly.
4100 recv_codecs[2].name = "ilbc";
4101
4102 // Test proper merge
4103 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004104 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4105 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4106 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004107
4108 // Test empty send codecs list
4109 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004110 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4111 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4112 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004113
4114 // Test empty recv codecs list
4115 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004116 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4117 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4118 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004119
4120 // Test all empty codec lists
4121 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004122 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4123 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4124 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004125}
4126
Amit Hilbuch77938e62018-12-21 09:23:38 -08004127// Checks that the RID extensions are added to the video RTP header extensions.
4128// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4129// not very well defined, as calling set() and immediately get() will yield
4130// an object that is not semantically equivalent to the set object.
4131TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4132 TransportDescriptionFactory tdf;
4133 MediaSessionDescriptionFactory sf(&tdf);
4134 sf.set_is_unified_plan(true);
4135 cricket::RtpHeaderExtensions extensions;
4136 sf.set_video_rtp_header_extensions(extensions);
4137 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4138 // Check to see that RID extensions were added to the extension list
4139 EXPECT_GE(result.size(), 2u);
4140 auto rid_extension = std::find_if(
4141 result.begin(), result.end(), [](const RtpExtension& extension) {
4142 return extension.uri == webrtc::RtpExtension::kRidUri;
4143 });
4144 EXPECT_NE(rid_extension, extensions.end());
4145 auto repaired_rid_extension = std::find_if(
4146 result.begin(), result.end(), [](const RtpExtension& extension) {
4147 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
4148 });
4149 EXPECT_NE(repaired_rid_extension, extensions.end());
4150}
4151
4152// Checks that the RID extensions are added to the audio RTP header extensions.
4153// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4154// not very well defined, as calling set() and immediately get() will yield
4155// an object that is not semantically equivalent to the set object.
4156TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4157 TransportDescriptionFactory tdf;
4158 MediaSessionDescriptionFactory sf(&tdf);
4159 sf.set_is_unified_plan(true);
4160 cricket::RtpHeaderExtensions extensions;
4161 sf.set_audio_rtp_header_extensions(extensions);
4162 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4163 // Check to see that RID extensions were added to the extension list
4164 EXPECT_GE(result.size(), 2u);
4165 auto rid_extension = std::find_if(
4166 result.begin(), result.end(), [](const RtpExtension& extension) {
4167 return extension.uri == webrtc::RtpExtension::kRidUri;
4168 });
4169 EXPECT_NE(rid_extension, extensions.end());
4170 auto repaired_rid_extension = std::find_if(
4171 result.begin(), result.end(), [](const RtpExtension& extension) {
4172 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
4173 });
4174 EXPECT_NE(repaired_rid_extension, extensions.end());
4175}
4176
ossu075af922016-06-14 03:29:38 -07004177namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004178// Compare the two vectors of codecs ignoring the payload type.
4179template <class Codec>
4180bool CodecsMatch(const std::vector<Codec>& codecs1,
4181 const std::vector<Codec>& codecs2) {
4182 if (codecs1.size() != codecs2.size()) {
4183 return false;
4184 }
4185
4186 for (size_t i = 0; i < codecs1.size(); ++i) {
4187 if (!codecs1[i].Matches(codecs2[i])) {
4188 return false;
4189 }
4190 }
4191 return true;
4192}
4193
Steve Anton4e70a722017-11-28 14:57:10 -08004194void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004195 TransportDescriptionFactory tdf;
4196 MediaSessionDescriptionFactory sf(&tdf);
4197 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4198 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4199 const std::vector<AudioCodec> sendrecv_codecs =
4200 MAKE_VECTOR(kAudioCodecsAnswer);
4201 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004202
4203 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004204 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4205 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004206
Steve Anton4e70a722017-11-28 14:57:10 -08004207 if (direction == RtpTransceiverDirection::kSendRecv ||
4208 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004209 AttachSenderToMediaDescriptionOptions(
4210 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004211 }
ossu075af922016-06-14 03:29:38 -07004212
Steve Anton6fe1fba2018-12-11 10:15:23 -08004213 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004214 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004215 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004216
4217 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004218 // that the codecs put in are right. This happens when we neither want to
4219 // send nor receive audio. The checks are still in place if at some point
4220 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004221 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004222 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004223 // sendrecv and inactive should both present lists as if the channel was
4224 // to be used for sending and receiving. Inactive essentially means it
4225 // might eventually be used anything, but we don't know more at this
4226 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004227 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004228 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004229 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004230 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004231 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004232 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004233 }
4234 }
4235}
4236
4237static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004238 AudioCodec(0, "codec0", 16000, -1, 1),
4239 AudioCodec(1, "codec1", 8000, 13300, 1),
4240 AudioCodec(2, "codec2", 8000, 64000, 1),
4241 AudioCodec(3, "codec3", 8000, 64000, 1),
4242 AudioCodec(4, "codec4", 8000, 0, 2),
4243 AudioCodec(5, "codec5", 32000, 0, 1),
4244 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004245
zhihuang1c378ed2017-08-17 14:10:50 -07004246/* The codecs groups below are chosen as per the matrix below. The objective
4247 * is to have different sets of codecs in the inputs, to get unique sets of
4248 * codecs after negotiation, depending on offer and answer communication
4249 * directions. One-way directions in the offer should either result in the
4250 * opposite direction in the answer, or an inactive answer. Regardless, the
4251 * choice of codecs should be as if the answer contained the opposite
4252 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004253 *
4254 * | Offer | Answer | Result
4255 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4256 * 0 | x - - | - x - | x - - - -
4257 * 1 | x x x | - x - | x - - x -
4258 * 2 | - x - | x - - | - x - - -
4259 * 3 | x x x | x - - | - x x - -
4260 * 4 | - x - | x x x | - x - - -
4261 * 5 | x - - | x x x | x - - - -
4262 * 6 | x x x | x x x | x x x x x
4263 */
4264// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004265static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4266static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004267// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4268// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004269static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4270static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004271// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004272static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4273static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4274static const int kResultSendrecv_SendCodecs[] = {3, 6};
4275static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4276static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004277
4278template <typename T, int IDXS>
4279std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4280 std::vector<T> out;
4281 out.reserve(IDXS);
4282 for (int idx : indices)
4283 out.push_back(array[idx]);
4284
4285 return out;
4286}
4287
Steve Anton4e70a722017-11-28 14:57:10 -08004288void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4289 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004290 bool add_legacy_stream) {
4291 TransportDescriptionFactory offer_tdf;
4292 TransportDescriptionFactory answer_tdf;
4293 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
4294 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
4295 offer_factory.set_audio_codecs(
4296 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4297 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4298 answer_factory.set_audio_codecs(
4299 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4300 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4301
ossu075af922016-06-14 03:29:38 -07004302 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004303 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4304 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004305
Steve Anton4e70a722017-11-28 14:57:10 -08004306 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004307 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4308 kAudioTrack1, {kMediaStream1}, 1,
4309 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004310 }
4311
Steve Anton6fe1fba2018-12-11 10:15:23 -08004312 std::unique_ptr<SessionDescription> offer =
4313 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004314 ASSERT_TRUE(offer.get() != NULL);
4315
4316 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004317 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4318 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004319
Steve Anton4e70a722017-11-28 14:57:10 -08004320 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004321 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4322 kAudioTrack1, {kMediaStream1}, 1,
4323 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004324 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004325 std::unique_ptr<SessionDescription> answer =
4326 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004327 const ContentInfo* ac = answer->GetContentByName("audio");
4328
zhihuang1c378ed2017-08-17 14:10:50 -07004329 // If the factory didn't add any audio content to the answer, we cannot
4330 // check that the codecs put in are right. This happens when we neither want
4331 // to send nor receive audio. The checks are still in place if at some point
4332 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004333 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004334 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4335 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004336
ossu075af922016-06-14 03:29:38 -07004337 std::vector<AudioCodec> target_codecs;
4338 // For offers with sendrecv or inactive, we should never reply with more
4339 // codecs than offered, with these codec sets.
4340 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004341 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004342 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4343 kResultSendrecv_SendrecvCodecs);
4344 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004345 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004346 target_codecs =
4347 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004348 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004349 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004350 target_codecs =
4351 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004352 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004353 case RtpTransceiverDirection::kSendRecv:
4354 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004355 target_codecs =
4356 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004357 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004358 target_codecs =
4359 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004360 } else {
4361 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4362 kResultSendrecv_SendrecvCodecs);
4363 }
4364 break;
4365 }
4366
zhihuang1c378ed2017-08-17 14:10:50 -07004367 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004368 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004369 bool first = true;
4370 os << "{";
4371 for (const auto& c : codecs) {
4372 os << (first ? " " : ", ") << c.id;
4373 first = false;
4374 }
4375 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004376 return os.Release();
ossu075af922016-06-14 03:29:38 -07004377 };
4378
4379 EXPECT_TRUE(acd->codecs() == target_codecs)
4380 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004381 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4382 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004383 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004384 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4385 << "; got: "
4386 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004387 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004388 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004389 << "Only inactive offers are allowed to not generate any audio "
4390 "content";
ossu075af922016-06-14 03:29:38 -07004391 }
4392}
brandtr03d5fb12016-11-22 03:37:59 -08004393
4394} // namespace
ossu075af922016-06-14 03:29:38 -07004395
4396class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004397 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004398
4399TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004400 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004401}
4402
4403INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
4404 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004405 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4406 RtpTransceiverDirection::kRecvOnly,
4407 RtpTransceiverDirection::kSendRecv,
4408 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004409
4410class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004411 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4412 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004413 bool>> {};
ossu075af922016-06-14 03:29:38 -07004414
4415TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004416 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4417 ::testing::get<1>(GetParam()),
4418 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004419}
4420
zhihuang1c378ed2017-08-17 14:10:50 -07004421INSTANTIATE_TEST_CASE_P(
4422 MediaSessionDescriptionFactoryTest,
4423 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004424 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4425 RtpTransceiverDirection::kRecvOnly,
4426 RtpTransceiverDirection::kSendRecv,
4427 RtpTransceiverDirection::kInactive),
4428 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4429 RtpTransceiverDirection::kRecvOnly,
4430 RtpTransceiverDirection::kSendRecv,
4431 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004432 ::testing::Bool()));