blob: 8525d61525d5a163c71362726863d836f6f63c38 [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"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080031#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080032#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000033
Yves Gerey665174f2018-06-19 15:03:05 +020034#define ASSERT_CRYPTO(cd, s, cs) \
35 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080036 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
38typedef std::vector<cricket::Candidate> Candidates;
39
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080040using cricket::AudioCodec;
41using cricket::AudioContentDescription;
42using cricket::ContentInfo;
43using cricket::CryptoParamsVec;
44using cricket::DataCodec;
45using cricket::DataContentDescription;
46using cricket::GetFirstAudioContent;
47using cricket::GetFirstAudioContentDescription;
48using cricket::GetFirstDataContent;
49using cricket::GetFirstDataContentDescription;
50using cricket::GetFirstVideoContent;
51using cricket::GetFirstVideoContentDescription;
52using cricket::kAutoBandwidth;
53using cricket::MEDIA_TYPE_AUDIO;
54using cricket::MEDIA_TYPE_DATA;
55using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070057using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080058using cricket::MediaProtocolType;
59using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::MediaSessionOptions;
61using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080062using cricket::RidDescription;
63using cricket::RidDirection;
64using cricket::SEC_DISABLED;
65using cricket::SEC_ENABLED;
66using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080068using cricket::SimulcastDescription;
69using cricket::SimulcastLayer;
70using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071using cricket::SsrcGroup;
72using cricket::StreamParams;
73using cricket::StreamParamsVec;
74using cricket::TransportDescription;
75using cricket::TransportDescriptionFactory;
76using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080078using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070079using rtc::CS_AEAD_AES_128_GCM;
80using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080081using rtc::CS_AES_CM_128_HMAC_SHA1_32;
82using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080083using rtc::UniqueRandomIdGenerator;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080084using testing::Each;
Steve Antone38a5a12018-11-21 16:05:15 -080085using testing::ElementsAreArray;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080086using testing::Eq;
87using testing::Field;
88using testing::IsEmpty;
89using testing::IsFalse;
90using testing::Ne;
91using testing::Pointwise;
92using testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070093using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080094using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095
96static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070097 AudioCodec(103, "ISAC", 16000, -1, 1),
98 AudioCodec(102, "iLBC", 8000, 13300, 1),
99 AudioCodec(0, "PCMU", 8000, 64000, 1),
100 AudioCodec(8, "PCMA", 8000, 64000, 1),
101 AudioCodec(117, "red", 8000, 0, 1),
102 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
104static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200105 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700106 AudioCodec(0, "PCMU", 8000, 64000, 1),
107 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108};
109
110static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700111 AudioCodec(102, "iLBC", 8000, 13300, 1),
112 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113};
114
perkj26752742016-10-24 01:21:16 -0700115static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
116 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117
zhihuang1c378ed2017-08-17 14:10:50 -0700118static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
119 VideoCodec(96, "H264-SVC")};
120
perkj26752742016-10-24 01:21:16 -0700121static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
122 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123
perkj26752742016-10-24 01:21:16 -0700124static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125
deadbeef67cf2c12016-04-13 10:07:16 -0700126static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
127 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128
deadbeef67cf2c12016-04-13 10:07:16 -0700129static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
130 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
deadbeef67cf2c12016-04-13 10:07:16 -0700132static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
133 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
isheriff6f8d6862016-05-26 11:24:55 -0700135static const RtpExtension kAudioRtpExtension1[] = {
136 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
137 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138};
139
jbauch5869f502017-06-29 12:31:36 -0700140static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
141 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
142 RtpExtension("http://google.com/testing/audio_something", 10),
143 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
144};
145
isheriff6f8d6862016-05-26 11:24:55 -0700146static const RtpExtension kAudioRtpExtension2[] = {
147 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
148 RtpExtension("http://google.com/testing/audio_something_else", 8),
149 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150};
151
isheriff6f8d6862016-05-26 11:24:55 -0700152static const RtpExtension kAudioRtpExtension3[] = {
153 RtpExtension("http://google.com/testing/audio_something", 2),
154 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700155};
156
jbauch5869f502017-06-29 12:31:36 -0700157static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
158 RtpExtension("http://google.com/testing/audio_something", 2),
159 // Use RTP extension that supports encryption.
160 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
161};
162
163static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
164 RtpExtension("http://google.com/testing/audio_something", 2),
165 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
166 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
167};
168
isheriff6f8d6862016-05-26 11:24:55 -0700169static const RtpExtension kAudioRtpExtensionAnswer[] = {
170 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000171};
172
jbauch5869f502017-06-29 12:31:36 -0700173static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
174 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
175};
176
isheriff6f8d6862016-05-26 11:24:55 -0700177static const RtpExtension kVideoRtpExtension1[] = {
178 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
179 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000180};
181
jbauch5869f502017-06-29 12:31:36 -0700182static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
184 RtpExtension("http://google.com/testing/video_something", 13),
185 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
186};
187
isheriff6f8d6862016-05-26 11:24:55 -0700188static const RtpExtension kVideoRtpExtension2[] = {
189 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
190 RtpExtension("http://google.com/testing/video_something_else", 14),
191 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192};
193
isheriff6f8d6862016-05-26 11:24:55 -0700194static const RtpExtension kVideoRtpExtension3[] = {
195 RtpExtension("http://google.com/testing/video_something", 4),
196 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700197};
198
jbauch5869f502017-06-29 12:31:36 -0700199static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
200 RtpExtension("http://google.com/testing/video_something", 4),
201 // Use RTP extension that supports encryption.
202 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
203};
204
isheriff6f8d6862016-05-26 11:24:55 -0700205static const RtpExtension kVideoRtpExtensionAnswer[] = {
206 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000207};
208
jbauch5869f502017-06-29 12:31:36 -0700209static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
210 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
211};
212
Peter Boström0c4e06b2015-10-07 12:23:21 +0200213static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
214static const uint32_t kSimSsrc[] = {10, 20, 30};
215static const uint32_t kFec1Ssrc[] = {10, 11};
216static const uint32_t kFec2Ssrc[] = {20, 21};
217static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218
219static const char kMediaStream1[] = "stream_1";
220static const char kMediaStream2[] = "stream_2";
221static const char kVideoTrack1[] = "video_1";
222static const char kVideoTrack2[] = "video_2";
223static const char kAudioTrack1[] = "audio_1";
224static const char kAudioTrack2[] = "audio_2";
225static const char kAudioTrack3[] = "audio_3";
226static const char kDataTrack1[] = "data_1";
227static const char kDataTrack2[] = "data_2";
228static const char kDataTrack3[] = "data_3";
229
zhihuangcf5b37c2016-05-05 11:44:35 -0700230static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
231 "RTP/SAVPF"};
232static const char* kMediaProtocolsDtls[] = {
233 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
234 "UDP/TLS/RTP/SAVP"};
235
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700236// SRTP cipher name negotiated by the tests. This must be updated if the
237// default changes.
238static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
239static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
240
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800241// These constants are used to make the code using "AddMediaDescriptionOptions"
242// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700243static constexpr bool kStopped = true;
244static constexpr bool kActive = false;
245
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000246static bool IsMediaContentOfType(const ContentInfo* content,
247 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800248 RTC_DCHECK(content);
249 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000250}
251
Steve Anton4e70a722017-11-28 14:57:10 -0800252static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800253 RTC_DCHECK(content);
254 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000255}
256
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000257static void AddRtxCodec(const VideoCodec& rtx_codec,
258 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800259 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000260 codecs->push_back(rtx_codec);
261}
262
263template <class T>
264static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
265 std::vector<std::string> codec_names;
266 for (const auto& codec : codecs) {
267 codec_names.push_back(codec.name);
268 }
269 return codec_names;
270}
271
zhihuang1c378ed2017-08-17 14:10:50 -0700272// This is used for test only. MIDs are not the identification of the
273// MediaDescriptionOptions since some end points may not support MID and the SDP
274// may not contain 'mid'.
275std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
276 const std::string& mid,
277 MediaSessionOptions* opts) {
278 return std::find_if(
279 opts->media_description_options.begin(),
280 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700281 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
282}
283
284std::vector<MediaDescriptionOptions>::const_iterator
285FindFirstMediaDescriptionByMid(const std::string& mid,
286 const MediaSessionOptions& opts) {
287 return std::find_if(
288 opts.media_description_options.begin(),
289 opts.media_description_options.end(),
290 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700291}
292
293// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800294static void AddMediaDescriptionOptions(MediaType type,
295 const std::string& mid,
296 RtpTransceiverDirection direction,
297 bool stopped,
298 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800299 opts->media_description_options.push_back(
300 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700301}
302
Steve Anton4e70a722017-11-28 14:57:10 -0800303static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700304 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800305 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
306 opts);
307 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
308 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700309}
310
311static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800312 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700313 MediaSessionOptions* opts) {
314 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800315 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700316}
317
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800318static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700319 const std::string& mid,
320 MediaType type,
321 const std::string& track_id,
322 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800323 const std::vector<RidDescription>& rids,
324 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700325 int num_sim_layer,
326 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700327 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
328 switch (type) {
329 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700330 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700331 break;
332 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800333 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
334 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700335 break;
336 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700337 RTC_CHECK(stream_ids.size() == 1U);
338 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700339 break;
340 default:
341 RTC_NOTREACHED();
342 }
343}
344
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800345static void AttachSenderToMediaDescriptionOptions(
346 const std::string& mid,
347 MediaType type,
348 const std::string& track_id,
349 const std::vector<std::string>& stream_ids,
350 int num_sim_layer,
351 MediaSessionOptions* session_options) {
352 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
353 SimulcastLayerList(), num_sim_layer,
354 session_options);
355}
356
zhihuang1c378ed2017-08-17 14:10:50 -0700357static void DetachSenderFromMediaSection(const std::string& mid,
358 const std::string& track_id,
359 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700360 std::vector<cricket::SenderOptions>& sender_options_list =
361 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
362 auto sender_it =
363 std::find_if(sender_options_list.begin(), sender_options_list.end(),
364 [track_id](const cricket::SenderOptions& sender_options) {
365 return sender_options.track_id == track_id;
366 });
367 RTC_DCHECK(sender_it != sender_options_list.end());
368 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700369}
370
371// Helper function used to create a default MediaSessionOptions for Plan B SDP.
372// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
373static MediaSessionOptions CreatePlanBMediaSessionOptions() {
374 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800375 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
376 RtpTransceiverDirection::kRecvOnly, kActive,
377 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700378 return session_options;
379}
380
381// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
382// was designed for Plan B SDP, where only one audio "m=" section and one video
383// "m=" section could be generated, and ordering couldn't be controlled. Many of
384// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385class MediaSessionDescriptionFactoryTest : public testing::Test {
386 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800387 MediaSessionDescriptionFactoryTest()
388 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700389 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
390 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000391 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
392 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700393 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
394 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
396 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200397 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700398 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200399 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700400 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000401 }
402
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000403 // Create a video StreamParamsVec object with:
404 // - one video stream with 3 simulcast streams and FEC,
405 StreamParamsVec CreateComplexVideoStreamParamsVec() {
406 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
407 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
408 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
409 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
410
411 std::vector<SsrcGroup> ssrc_groups;
412 ssrc_groups.push_back(sim_group);
413 ssrc_groups.push_back(fec_group1);
414 ssrc_groups.push_back(fec_group2);
415 ssrc_groups.push_back(fec_group3);
416
417 StreamParams simulcast_params;
418 simulcast_params.id = kVideoTrack1;
419 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
420 simulcast_params.ssrc_groups = ssrc_groups;
421 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800422 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000423
424 StreamParamsVec video_streams;
425 video_streams.push_back(simulcast_params);
426
427 return video_streams;
428 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429
430 bool CompareCryptoParams(const CryptoParamsVec& c1,
431 const CryptoParamsVec& c2) {
432 if (c1.size() != c2.size())
433 return false;
434 for (size_t i = 0; i < c1.size(); ++i)
435 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
436 c1[i].key_params != c2[i].key_params ||
437 c1[i].session_params != c2[i].session_params)
438 return false;
439 return true;
440 }
441
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700442 // Returns true if the transport info contains "renomination" as an
443 // ICE option.
444 bool GetIceRenomination(const TransportInfo* transport_info) {
445 const std::vector<std::string>& ice_options =
446 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700447 auto iter =
448 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700449 return iter != ice_options.end();
450 }
451
zhihuang1c378ed2017-08-17 14:10:50 -0700452 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700453 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454 bool has_current_desc) {
455 const std::string current_audio_ufrag = "current_audio_ufrag";
456 const std::string current_audio_pwd = "current_audio_pwd";
457 const std::string current_video_ufrag = "current_video_ufrag";
458 const std::string current_video_pwd = "current_video_pwd";
459 const std::string current_data_ufrag = "current_data_ufrag";
460 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800461 std::unique_ptr<SessionDescription> current_desc;
462 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800464 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800465 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200466 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800467 TransportDescription(current_audio_ufrag, current_audio_pwd)));
468 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200469 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800470 TransportDescription(current_video_ufrag, current_video_pwd)));
471 current_desc->AddTransportInfo(TransportInfo(
472 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 }
474 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800475 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000476 } else {
kwiberg31022942016-03-11 14:18:21 -0800477 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800478 offer = f1_.CreateOffer(options, NULL);
479 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480 }
481 ASSERT_TRUE(desc.get() != NULL);
482 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000483 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 EXPECT_TRUE(ti_audio != NULL);
485 if (has_current_desc) {
486 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
487 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
488 } else {
489 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
490 ti_audio->description.ice_ufrag.size());
491 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
492 ti_audio->description.ice_pwd.size());
493 }
zhihuang1c378ed2017-08-17 14:10:50 -0700494 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700495 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700496 EXPECT_EQ(
497 media_desc_options_it->transport_options.enable_ice_renomination,
498 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499
500 } else {
501 EXPECT_TRUE(ti_audio == NULL);
502 }
503 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000504 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 EXPECT_TRUE(ti_video != NULL);
506 if (options.bundle_enabled) {
507 EXPECT_EQ(ti_audio->description.ice_ufrag,
508 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200509 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 } else {
511 if (has_current_desc) {
512 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
513 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
514 } else {
515 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
516 ti_video->description.ice_ufrag.size());
517 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
518 ti_video->description.ice_pwd.size());
519 }
520 }
zhihuang1c378ed2017-08-17 14:10:50 -0700521 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700522 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700523 EXPECT_EQ(
524 media_desc_options_it->transport_options.enable_ice_renomination,
525 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 } else {
527 EXPECT_TRUE(ti_video == NULL);
528 }
529 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
530 if (options.has_data()) {
531 EXPECT_TRUE(ti_data != NULL);
532 if (options.bundle_enabled) {
533 EXPECT_EQ(ti_audio->description.ice_ufrag,
534 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200535 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 } else {
537 if (has_current_desc) {
538 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
539 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
540 } else {
541 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
542 ti_data->description.ice_ufrag.size());
543 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
544 ti_data->description.ice_pwd.size());
545 }
546 }
zhihuang1c378ed2017-08-17 14:10:50 -0700547 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700548 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700549 EXPECT_EQ(
550 media_desc_options_it->transport_options.enable_ice_renomination,
551 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700552
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 } else {
554 EXPECT_TRUE(ti_video == NULL);
555 }
556 }
557
558 void TestCryptoWithBundle(bool offer) {
559 f1_.set_secure(SEC_ENABLED);
560 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800561 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
562 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
563 &options);
kwiberg31022942016-03-11 14:18:21 -0800564 std::unique_ptr<SessionDescription> ref_desc;
565 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 if (offer) {
567 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800568 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800570 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 } else {
572 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800573 ref_desc = f1_.CreateOffer(options, NULL);
574 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800576 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800578 desc->GetContentDescriptionByName("audio");
579 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800581 desc->GetContentDescriptionByName("video");
582 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
584 video_media_desc->cryptos()));
585 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800586 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 audio_media_desc->cryptos()[0].cipher_suite);
588
589 // Verify the selected crypto is one from the reference audio
590 // media content.
591 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800592 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 bool found = false;
594 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
595 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200596 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 found = true;
598 break;
599 }
600 }
601 EXPECT_TRUE(found);
602 }
603
604 // This test that the audio and video media direction is set to
605 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700606 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800608 RtpTransceiverDirection direction_in_offer,
609 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700610 MediaSessionOptions offer_opts;
611 AddAudioVideoSections(direction_in_offer, &offer_opts);
612
Steve Anton6fe1fba2018-12-11 10:15:23 -0800613 std::unique_ptr<SessionDescription> offer =
614 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700616 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700618 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620
zhihuang1c378ed2017-08-17 14:10:50 -0700621 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800622 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800623 std::unique_ptr<SessionDescription> answer =
624 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 const AudioContentDescription* acd_answer =
626 GetFirstAudioContentDescription(answer.get());
627 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
628 const VideoContentDescription* vcd_answer =
629 GetFirstVideoContentDescription(answer.get());
630 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
631 }
632
633 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800634 RTC_DCHECK(content);
635 RTC_CHECK(content->media_description());
636 const cricket::AudioContentDescription* audio_desc =
637 content->media_description()->as_audio();
638 RTC_CHECK(audio_desc);
639 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
640 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800642 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 }
644 return true;
645 }
646
jbauchcb560652016-08-04 05:20:32 -0700647 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
648 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800649 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700650 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700651
jbauchcb560652016-08-04 05:20:32 -0700652 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800653 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700654 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700655
jbauchcb560652016-08-04 05:20:32 -0700656 f1_.set_secure(SEC_ENABLED);
657 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800658 std::unique_ptr<SessionDescription> offer =
659 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700660 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800661 std::unique_ptr<SessionDescription> answer =
662 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700663 const ContentInfo* ac = answer->GetContentByName("audio");
664 const ContentInfo* vc = answer->GetContentByName("video");
665 ASSERT_TRUE(ac != NULL);
666 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800667 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
668 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800669 const AudioContentDescription* acd = ac->media_description()->as_audio();
670 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700671 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800672 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700673 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700674 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700675 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
676 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700677 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700678 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700679 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700680 }
681 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800682 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200683 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
684 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700685 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700686 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700687 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700688 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700689 }
Steve Antone38a5a12018-11-21 16:05:15 -0800690 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700691 }
692
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000693 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800694 UniqueRandomIdGenerator ssrc_generator1;
695 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696 MediaSessionDescriptionFactory f1_;
697 MediaSessionDescriptionFactory f2_;
698 TransportDescriptionFactory tdf1_;
699 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700};
701
702// Create a typical audio offer, and ensure it matches what we expect.
703TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
704 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800705 std::unique_ptr<SessionDescription> offer =
706 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 ASSERT_TRUE(offer.get() != NULL);
708 const ContentInfo* ac = offer->GetContentByName("audio");
709 const ContentInfo* vc = offer->GetContentByName("video");
710 ASSERT_TRUE(ac != NULL);
711 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800712 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800713 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000714 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700715 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700716 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000717 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
718 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700719 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800720 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000721}
722
723// Create a typical video offer, and ensure it matches what we expect.
724TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
725 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800726 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800728 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 ASSERT_TRUE(offer.get() != NULL);
730 const ContentInfo* ac = offer->GetContentByName("audio");
731 const ContentInfo* vc = offer->GetContentByName("video");
732 ASSERT_TRUE(ac != NULL);
733 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800734 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
735 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800736 const AudioContentDescription* acd = ac->media_description()->as_audio();
737 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700739 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700740 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
742 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700743 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800744 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
746 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700747 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
749 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700750 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800751 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752}
753
754// Test creating an offer with bundle where the Codecs have the same dynamic
755// RTP playlod type. The test verifies that the offer don't contain the
756// duplicate RTP payload types.
757TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
758 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700759 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
761 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
762 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
763
764 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800765 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
766 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800768 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 const VideoContentDescription* vcd =
770 GetFirstVideoContentDescription(offer.get());
771 const AudioContentDescription* acd =
772 GetFirstAudioContentDescription(offer.get());
773 const DataContentDescription* dcd =
774 GetFirstDataContentDescription(offer.get());
775 ASSERT_TRUE(NULL != vcd);
776 ASSERT_TRUE(NULL != acd);
777 ASSERT_TRUE(NULL != dcd);
778 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
779 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
780 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
781 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
782 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
783 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
784}
785
zhihuang1c378ed2017-08-17 14:10:50 -0700786// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787// after an audio only session has been negotiated.
788TEST_F(MediaSessionDescriptionFactoryTest,
789 TestCreateUpdatedVideoOfferWithBundle) {
790 f1_.set_secure(SEC_ENABLED);
791 f2_.set_secure(SEC_ENABLED);
792 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800793 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
794 RtpTransceiverDirection::kRecvOnly, kActive,
795 &opts);
796 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
797 RtpTransceiverDirection::kInactive, kStopped,
798 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 opts.data_channel_type = cricket::DCT_NONE;
800 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800801 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
802 std::unique_ptr<SessionDescription> answer =
803 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804
805 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800806 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
807 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
808 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800810 std::unique_ptr<SessionDescription> updated_offer(
811 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812
813 const AudioContentDescription* acd =
814 GetFirstAudioContentDescription(updated_offer.get());
815 const VideoContentDescription* vcd =
816 GetFirstVideoContentDescription(updated_offer.get());
817 const DataContentDescription* dcd =
818 GetFirstDataContentDescription(updated_offer.get());
819 EXPECT_TRUE(NULL != vcd);
820 EXPECT_TRUE(NULL != acd);
821 EXPECT_TRUE(NULL != dcd);
822
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700823 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800824 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700825 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800826 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700827 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800828 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829}
deadbeef44f08192015-12-15 16:20:09 -0800830
wu@webrtc.org78187522013-10-07 23:32:02 +0000831// Create a RTP data offer, and ensure it matches what we expect.
832TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800834 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
835 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800837 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 ASSERT_TRUE(offer.get() != NULL);
839 const ContentInfo* ac = offer->GetContentByName("audio");
840 const ContentInfo* dc = offer->GetContentByName("data");
841 ASSERT_TRUE(ac != NULL);
842 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800843 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
844 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800845 const AudioContentDescription* acd = ac->media_description()->as_audio();
846 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700848 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700849 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
851 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700852 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800853 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
855 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700856 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200858 dcd->bandwidth()); // default bandwidth (auto)
859 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700860 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800861 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862}
863
wu@webrtc.org78187522013-10-07 23:32:02 +0000864// Create an SCTP data offer with bundle without error.
865TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
866 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000867 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800868 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000869 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800870 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000871 EXPECT_TRUE(offer.get() != NULL);
872 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
873}
874
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000875// Test creating an sctp data channel from an already generated offer.
876TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
877 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000878 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800879 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000880 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800881 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000882 ASSERT_TRUE(offer1.get() != NULL);
883 const ContentInfo* data = offer1->GetContentByName("data");
884 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800885 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000886
887 // Now set data_channel_type to 'none' (default) and make sure that the
888 // datachannel type that gets generated from the previous offer, is of the
889 // same type.
890 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800891 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000892 f1_.CreateOffer(opts, offer1.get()));
893 data = offer2->GetContentByName("data");
894 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800895 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000896}
897
Steve Anton2bed3972019-01-04 17:04:30 -0800898// Test that if BUNDLE is enabled and all media sections are rejected then the
899// BUNDLE group is not present in the re-offer.
900TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
901 MediaSessionOptions opts;
902 opts.bundle_enabled = true;
903 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
904 RtpTransceiverDirection::kSendRecv, kActive,
905 &opts);
906 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
907
908 opts.media_description_options[0].stopped = true;
909 std::unique_ptr<SessionDescription> reoffer =
910 f1_.CreateOffer(opts, offer.get());
911
912 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
913}
914
915// Test that if BUNDLE is enabled and the remote re-offer does not include a
916// BUNDLE group since all media sections are rejected, then the re-answer also
917// does not include a BUNDLE group.
918TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
919 MediaSessionOptions opts;
920 opts.bundle_enabled = true;
921 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
922 RtpTransceiverDirection::kSendRecv, kActive,
923 &opts);
924 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
925 std::unique_ptr<SessionDescription> answer =
926 f2_.CreateAnswer(offer.get(), opts, nullptr);
927
928 opts.media_description_options[0].stopped = true;
929 std::unique_ptr<SessionDescription> reoffer =
930 f1_.CreateOffer(opts, offer.get());
931 std::unique_ptr<SessionDescription> reanswer =
932 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
933
934 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
935}
936
937// Test that if BUNDLE is enabled and the previous offerer-tagged media section
938// was rejected then the new offerer-tagged media section is the non-rejected
939// media section.
940TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
941 MediaSessionOptions opts;
942 opts.bundle_enabled = true;
943 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
944 RtpTransceiverDirection::kSendRecv, kActive,
945 &opts);
946 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
947
948 // Reject the audio m= section and add a video m= section.
949 opts.media_description_options[0].stopped = true;
950 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
951 RtpTransceiverDirection::kSendRecv, kActive,
952 &opts);
953 std::unique_ptr<SessionDescription> reoffer =
954 f1_.CreateOffer(opts, offer.get());
955
956 const cricket::ContentGroup* bundle_group =
957 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
958 ASSERT_TRUE(bundle_group);
959 EXPECT_FALSE(bundle_group->HasContentName("audio"));
960 EXPECT_TRUE(bundle_group->HasContentName("video"));
961}
962
963// Test that if BUNDLE is enabled and the previous offerer-tagged media section
964// was rejected and a new media section is added, then the re-answer BUNDLE
965// group will contain only the non-rejected media section.
966TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
967 MediaSessionOptions opts;
968 opts.bundle_enabled = true;
969 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
970 RtpTransceiverDirection::kSendRecv, kActive,
971 &opts);
972 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
973 std::unique_ptr<SessionDescription> answer =
974 f2_.CreateAnswer(offer.get(), opts, nullptr);
975
976 // Reject the audio m= section and add a video m= section.
977 opts.media_description_options[0].stopped = true;
978 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
979 RtpTransceiverDirection::kSendRecv, kActive,
980 &opts);
981 std::unique_ptr<SessionDescription> reoffer =
982 f1_.CreateOffer(opts, offer.get());
983 std::unique_ptr<SessionDescription> reanswer =
984 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
985
986 const cricket::ContentGroup* bundle_group =
987 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
988 ASSERT_TRUE(bundle_group);
989 EXPECT_FALSE(bundle_group->HasContentName("audio"));
990 EXPECT_TRUE(bundle_group->HasContentName("video"));
991}
992
993// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
994// and there is still a non-rejected media section that was in the initial
995// offer, then the ICE credentials do not change in the reoffer offerer-tagged
996// media section.
997TEST_F(MediaSessionDescriptionFactoryTest,
998 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
999 MediaSessionOptions opts;
1000 opts.bundle_enabled = true;
1001 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1002 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1003 std::unique_ptr<SessionDescription> answer =
1004 f2_.CreateAnswer(offer.get(), opts, nullptr);
1005
1006 // Reject the audio m= section.
1007 opts.media_description_options[0].stopped = true;
1008 std::unique_ptr<SessionDescription> reoffer =
1009 f1_.CreateOffer(opts, offer.get());
1010
1011 const TransportDescription* offer_tagged =
1012 offer->GetTransportDescriptionByName("audio");
1013 ASSERT_TRUE(offer_tagged);
1014 const TransportDescription* reoffer_tagged =
1015 reoffer->GetTransportDescriptionByName("video");
1016 ASSERT_TRUE(reoffer_tagged);
1017 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1018 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1019}
1020
1021// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1022// and there is still a non-rejected media section that was in the initial
1023// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1024// media section.
1025TEST_F(MediaSessionDescriptionFactoryTest,
1026 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1027 MediaSessionOptions opts;
1028 opts.bundle_enabled = true;
1029 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1030 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1031 std::unique_ptr<SessionDescription> answer =
1032 f2_.CreateAnswer(offer.get(), opts, nullptr);
1033
1034 // Reject the audio m= section.
1035 opts.media_description_options[0].stopped = true;
1036 std::unique_ptr<SessionDescription> reoffer =
1037 f1_.CreateOffer(opts, offer.get());
1038 std::unique_ptr<SessionDescription> reanswer =
1039 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1040
1041 const TransportDescription* answer_tagged =
1042 answer->GetTransportDescriptionByName("audio");
1043 ASSERT_TRUE(answer_tagged);
1044 const TransportDescription* reanswer_tagged =
1045 reanswer->GetTransportDescriptionByName("video");
1046 ASSERT_TRUE(reanswer_tagged);
1047 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1048 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1049}
1050
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001051// Create an audio, video offer without legacy StreamParams.
1052TEST_F(MediaSessionDescriptionFactoryTest,
1053 TestCreateOfferWithoutLegacyStreams) {
1054 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001055 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001056 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001057 ASSERT_TRUE(offer.get() != NULL);
1058 const ContentInfo* ac = offer->GetContentByName("audio");
1059 const ContentInfo* vc = offer->GetContentByName("video");
1060 ASSERT_TRUE(ac != NULL);
1061 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001062 const AudioContentDescription* acd = ac->media_description()->as_audio();
1063 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064
Yves Gerey665174f2018-06-19 15:03:05 +02001065 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1066 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001067}
1068
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001069// Creates an audio+video sendonly offer.
1070TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001071 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001072 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001073 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1074 {kMediaStream1}, 1, &opts);
1075 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1076 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001077
Steve Anton6fe1fba2018-12-11 10:15:23 -08001078 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001079 ASSERT_TRUE(offer.get() != NULL);
1080 EXPECT_EQ(2u, offer->contents().size());
1081 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1082 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1083
Steve Anton4e70a722017-11-28 14:57:10 -08001084 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1085 GetMediaDirection(&offer->contents()[0]));
1086 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1087 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001088}
1089
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001090// Verifies that the order of the media contents in the current
1091// SessionDescription is preserved in the new SessionDescription.
1092TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1093 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001094 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001095
kwiberg31022942016-03-11 14:18:21 -08001096 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001097 ASSERT_TRUE(offer1.get() != NULL);
1098 EXPECT_EQ(1u, offer1->contents().size());
1099 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1100
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001101 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1102 RtpTransceiverDirection::kRecvOnly, kActive,
1103 &opts);
kwiberg31022942016-03-11 14:18:21 -08001104 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001105 f1_.CreateOffer(opts, offer1.get()));
1106 ASSERT_TRUE(offer2.get() != NULL);
1107 EXPECT_EQ(2u, offer2->contents().size());
1108 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1109 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1110
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001111 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1112 RtpTransceiverDirection::kRecvOnly, kActive,
1113 &opts);
kwiberg31022942016-03-11 14:18:21 -08001114 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001115 f1_.CreateOffer(opts, offer2.get()));
1116 ASSERT_TRUE(offer3.get() != NULL);
1117 EXPECT_EQ(3u, offer3->contents().size());
1118 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1119 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1120 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001121}
1122
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001123// Create a typical audio answer, and ensure it matches what we expect.
1124TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1125 f1_.set_secure(SEC_ENABLED);
1126 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001127 std::unique_ptr<SessionDescription> offer =
1128 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001129 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001130 std::unique_ptr<SessionDescription> answer =
1131 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132 const ContentInfo* ac = answer->GetContentByName("audio");
1133 const ContentInfo* vc = answer->GetContentByName("video");
1134 ASSERT_TRUE(ac != NULL);
1135 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001136 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001137 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001139 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001140 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001141 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1142 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001143 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001144 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001145}
1146
jbauchcb560652016-08-04 05:20:32 -07001147// Create a typical audio answer with GCM ciphers enabled, and ensure it
1148// matches what we expect.
1149TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1150 f1_.set_secure(SEC_ENABLED);
1151 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001152 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001153 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001154 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001155 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001156 std::unique_ptr<SessionDescription> answer =
1157 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001158 const ContentInfo* ac = answer->GetContentByName("audio");
1159 const ContentInfo* vc = answer->GetContentByName("video");
1160 ASSERT_TRUE(ac != NULL);
1161 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001162 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001163 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001164 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001165 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001166 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001167 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1168 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001169 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001170 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001171}
1172
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001173// Create a typical video answer, and ensure it matches what we expect.
1174TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1175 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001176 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177 f1_.set_secure(SEC_ENABLED);
1178 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001179 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001180 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001181 std::unique_ptr<SessionDescription> answer =
1182 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 const ContentInfo* ac = answer->GetContentByName("audio");
1184 const ContentInfo* vc = answer->GetContentByName("video");
1185 ASSERT_TRUE(ac != NULL);
1186 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001187 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1188 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001189 const AudioContentDescription* acd = ac->media_description()->as_audio();
1190 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001192 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001193 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001194 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001196 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001198 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001199 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1200 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001201 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001202 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203}
1204
jbauchcb560652016-08-04 05:20:32 -07001205// Create a typical video answer with GCM ciphers enabled, and ensure it
1206// matches what we expect.
1207TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1208 TestVideoGcmCipher(true, true);
1209}
1210
1211// Create a typical video answer with GCM ciphers enabled for the offer only,
1212// and ensure it matches what we expect.
1213TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1214 TestVideoGcmCipher(true, false);
1215}
1216
1217// Create a typical video answer with GCM ciphers enabled for the answer only,
1218// and ensure it matches what we expect.
1219TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1220 TestVideoGcmCipher(false, true);
1221}
1222
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001223TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001224 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001225 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226 f1_.set_secure(SEC_ENABLED);
1227 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001228 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001230 std::unique_ptr<SessionDescription> answer =
1231 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001232 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001233 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001234 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001235 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001236 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1237 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001238 const AudioContentDescription* acd = ac->media_description()->as_audio();
1239 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001241 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001243 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001245 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001246 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001247 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001248 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001249 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001250 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001251 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001252}
1253
jbauchcb560652016-08-04 05:20:32 -07001254TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001255 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001256 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001257 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001258 f1_.set_secure(SEC_ENABLED);
1259 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001260 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001261 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001262 std::unique_ptr<SessionDescription> answer =
1263 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001264 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001265 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001266 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001267 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001268 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1269 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001270 const AudioContentDescription* acd = ac->media_description()->as_audio();
1271 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001272 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001273 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001274 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001275 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001276 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001277 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001278 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001279 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001280 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001281 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001282 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001283 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001284}
1285
1286// The use_sctpmap flag should be set in a DataContentDescription by default.
1287// The answer's use_sctpmap flag should match the offer's.
1288TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1289 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001290 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001291 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001292 ASSERT_TRUE(offer.get() != NULL);
1293 ContentInfo* dc_offer = offer->GetContentByName("data");
1294 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001295 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001296 EXPECT_TRUE(dcd_offer->use_sctpmap());
1297
Steve Anton6fe1fba2018-12-11 10:15:23 -08001298 std::unique_ptr<SessionDescription> answer =
1299 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001300 const ContentInfo* dc_answer = answer->GetContentByName("data");
1301 ASSERT_TRUE(dc_answer != NULL);
1302 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001303 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001304 EXPECT_TRUE(dcd_answer->use_sctpmap());
1305}
1306
1307// The answer's use_sctpmap flag should match the offer's.
1308TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1309 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001310 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001311 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001312 ASSERT_TRUE(offer.get() != NULL);
1313 ContentInfo* dc_offer = offer->GetContentByName("data");
1314 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001315 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001316 dcd_offer->set_use_sctpmap(false);
1317
Steve Anton6fe1fba2018-12-11 10:15:23 -08001318 std::unique_ptr<SessionDescription> answer =
1319 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001320 const ContentInfo* dc_answer = answer->GetContentByName("data");
1321 ASSERT_TRUE(dc_answer != NULL);
1322 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001323 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001324 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001325}
1326
deadbeef8b7e9ad2017-05-25 09:38:55 -07001327// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1328// and "TCP/DTLS/SCTP" offers.
1329TEST_F(MediaSessionDescriptionFactoryTest,
1330 TestCreateDataAnswerToDifferentOfferedProtos) {
1331 // Need to enable DTLS offer/answer generation (disabled by default in this
1332 // test).
1333 f1_.set_secure(SEC_ENABLED);
1334 f2_.set_secure(SEC_ENABLED);
1335 tdf1_.set_secure(SEC_ENABLED);
1336 tdf2_.set_secure(SEC_ENABLED);
1337
1338 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001339 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001340 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001341 ASSERT_TRUE(offer.get() != nullptr);
1342 ContentInfo* dc_offer = offer->GetContentByName("data");
1343 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001344 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001345
1346 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1347 "TCP/DTLS/SCTP"};
1348 for (const std::string& proto : protos) {
1349 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001350 std::unique_ptr<SessionDescription> answer =
1351 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001352 const ContentInfo* dc_answer = answer->GetContentByName("data");
1353 ASSERT_TRUE(dc_answer != nullptr);
1354 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001355 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001356 EXPECT_FALSE(dc_answer->rejected);
1357 EXPECT_EQ(proto, dcd_answer->protocol());
1358 }
1359}
1360
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001361// Verifies that the order of the media contents in the offer is preserved in
1362// the answer.
1363TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1364 MediaSessionOptions opts;
1365
1366 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001367 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001368 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001369 ASSERT_TRUE(offer1.get() != NULL);
1370
1371 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001372 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1373 RtpTransceiverDirection::kRecvOnly, kActive,
1374 &opts);
kwiberg31022942016-03-11 14:18:21 -08001375 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001376 f1_.CreateOffer(opts, offer1.get()));
1377 ASSERT_TRUE(offer2.get() != NULL);
1378
1379 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001380 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1381 RtpTransceiverDirection::kRecvOnly, kActive,
1382 &opts);
kwiberg31022942016-03-11 14:18:21 -08001383 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001384 f1_.CreateOffer(opts, offer2.get()));
1385 ASSERT_TRUE(offer3.get() != NULL);
1386
Steve Anton6fe1fba2018-12-11 10:15:23 -08001387 std::unique_ptr<SessionDescription> answer =
1388 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001389 ASSERT_TRUE(answer.get() != NULL);
1390 EXPECT_EQ(3u, answer->contents().size());
1391 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1392 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1393 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1394}
1395
ossu075af922016-06-14 03:29:38 -07001396// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1397// answerer settings.
1398
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001399// This test that the media direction is set to send/receive in an answer if
1400// the offer is send receive.
1401TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001402 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1403 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001404}
1405
1406// This test that the media direction is set to receive only in an answer if
1407// the offer is send only.
1408TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001409 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1410 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001411}
1412
1413// This test that the media direction is set to send only in an answer if
1414// the offer is recv only.
1415TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001416 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1417 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001418}
1419
1420// This test that the media direction is set to inactive in an answer if
1421// the offer is inactive.
1422TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001423 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1424 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001425}
1426
1427// Test that a data content with an unknown protocol is rejected in an answer.
1428TEST_F(MediaSessionDescriptionFactoryTest,
1429 CreateDataAnswerToOfferWithUnknownProtocol) {
1430 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001431 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001432 f1_.set_secure(SEC_ENABLED);
1433 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001434 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001435 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001436 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001437 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001438 ASSERT_TRUE(dcd_offer != NULL);
1439 std::string protocol = "a weird unknown protocol";
1440 dcd_offer->set_protocol(protocol);
1441
Steve Anton6fe1fba2018-12-11 10:15:23 -08001442 std::unique_ptr<SessionDescription> answer =
1443 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001444
1445 const ContentInfo* dc_answer = answer->GetContentByName("data");
1446 ASSERT_TRUE(dc_answer != NULL);
1447 EXPECT_TRUE(dc_answer->rejected);
1448 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001449 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001450 ASSERT_TRUE(dcd_answer != NULL);
1451 EXPECT_EQ(protocol, dcd_answer->protocol());
1452}
1453
1454// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1455TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001456 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001457 f1_.set_secure(SEC_DISABLED);
1458 f2_.set_secure(SEC_DISABLED);
1459 tdf1_.set_secure(SEC_DISABLED);
1460 tdf2_.set_secure(SEC_DISABLED);
1461
Steve Anton6fe1fba2018-12-11 10:15:23 -08001462 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001463 const AudioContentDescription* offer_acd =
1464 GetFirstAudioContentDescription(offer.get());
1465 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001466 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001467
Steve Anton6fe1fba2018-12-11 10:15:23 -08001468 std::unique_ptr<SessionDescription> answer =
1469 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001470
1471 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1472 ASSERT_TRUE(ac_answer != NULL);
1473 EXPECT_FALSE(ac_answer->rejected);
1474
1475 const AudioContentDescription* answer_acd =
1476 GetFirstAudioContentDescription(answer.get());
1477 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001478 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001479}
1480
1481// Create a video offer and answer and ensure the RTP header extensions
1482// matches what we expect.
1483TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1484 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001485 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001486 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1487 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1488 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1489 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1490
Steve Anton6fe1fba2018-12-11 10:15:23 -08001491 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001492 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001493 std::unique_ptr<SessionDescription> answer =
1494 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001495
Yves Gerey665174f2018-06-19 15:03:05 +02001496 EXPECT_EQ(
1497 MAKE_VECTOR(kAudioRtpExtension1),
1498 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1499 EXPECT_EQ(
1500 MAKE_VECTOR(kVideoRtpExtension1),
1501 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1502 EXPECT_EQ(
1503 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1504 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1505 EXPECT_EQ(
1506 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1507 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001508}
1509
jbauch5869f502017-06-29 12:31:36 -07001510TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001511 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001512 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001513 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001514
1515 f1_.set_enable_encrypted_rtp_header_extensions(true);
1516 f2_.set_enable_encrypted_rtp_header_extensions(true);
1517
Yves Gerey665174f2018-06-19 15:03:05 +02001518 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1519 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1520 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1521 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001522
Steve Anton6fe1fba2018-12-11 10:15:23 -08001523 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001524 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001525 std::unique_ptr<SessionDescription> answer =
1526 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001527
Yves Gerey665174f2018-06-19 15:03:05 +02001528 EXPECT_EQ(
1529 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1530 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1531 EXPECT_EQ(
1532 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1533 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1534 EXPECT_EQ(
1535 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1536 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1537 EXPECT_EQ(
1538 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1539 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001540}
1541
1542TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001543 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001544 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001545 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001546
1547 f1_.set_enable_encrypted_rtp_header_extensions(true);
1548
Yves Gerey665174f2018-06-19 15:03:05 +02001549 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1550 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1551 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1552 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001553
Steve Anton6fe1fba2018-12-11 10:15:23 -08001554 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001555 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001556 std::unique_ptr<SessionDescription> answer =
1557 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001558
Yves Gerey665174f2018-06-19 15:03:05 +02001559 EXPECT_EQ(
1560 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1561 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1562 EXPECT_EQ(
1563 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1564 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1565 EXPECT_EQ(
1566 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1567 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1568 EXPECT_EQ(
1569 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1570 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001571}
1572
1573TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001574 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001575 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001576 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001577
1578 f2_.set_enable_encrypted_rtp_header_extensions(true);
1579
Yves Gerey665174f2018-06-19 15:03:05 +02001580 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1581 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1582 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1583 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001584
Steve Anton6fe1fba2018-12-11 10:15:23 -08001585 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001586 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001587 std::unique_ptr<SessionDescription> answer =
1588 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001589
Yves Gerey665174f2018-06-19 15:03:05 +02001590 EXPECT_EQ(
1591 MAKE_VECTOR(kAudioRtpExtension1),
1592 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1593 EXPECT_EQ(
1594 MAKE_VECTOR(kVideoRtpExtension1),
1595 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1596 EXPECT_EQ(
1597 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1598 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1599 EXPECT_EQ(
1600 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1601 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001602}
1603
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604// Create an audio, video, data answer without legacy StreamParams.
1605TEST_F(MediaSessionDescriptionFactoryTest,
1606 TestCreateAnswerWithoutLegacyStreams) {
1607 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001608 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1609 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001610 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001612 std::unique_ptr<SessionDescription> answer =
1613 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001614 const ContentInfo* ac = answer->GetContentByName("audio");
1615 const ContentInfo* vc = answer->GetContentByName("video");
1616 const ContentInfo* dc = answer->GetContentByName("data");
1617 ASSERT_TRUE(ac != NULL);
1618 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001619 const AudioContentDescription* acd = ac->media_description()->as_audio();
1620 const VideoContentDescription* vcd = vc->media_description()->as_video();
1621 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622
1623 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1624 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1625 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1626}
1627
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001628// Create a typical video answer, and ensure it matches what we expect.
1629TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1630 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001631 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1632 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1633 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001634
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001636 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1637 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1638 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639
kwiberg31022942016-03-11 14:18:21 -08001640 std::unique_ptr<SessionDescription> offer;
1641 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001642
1643 offer_opts.rtcp_mux_enabled = true;
1644 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001645 offer = f1_.CreateOffer(offer_opts, NULL);
1646 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001647 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1648 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1649 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1650 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1651 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1652 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1653 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1654 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1655 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1656 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1657 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1658 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1659
1660 offer_opts.rtcp_mux_enabled = true;
1661 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001662 offer = f1_.CreateOffer(offer_opts, NULL);
1663 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001664 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1665 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1666 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1667 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1668 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1669 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1670 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1671 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1672 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1673 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1674 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1675 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1676
1677 offer_opts.rtcp_mux_enabled = false;
1678 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001679 offer = f1_.CreateOffer(offer_opts, NULL);
1680 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001681 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1682 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1683 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1684 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1685 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1686 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1687 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1688 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1689 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1690 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1691 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1692 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1693
1694 offer_opts.rtcp_mux_enabled = false;
1695 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001696 offer = f1_.CreateOffer(offer_opts, NULL);
1697 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1699 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1700 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1701 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1702 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1703 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1704 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1705 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1706 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1707 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1708 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1709 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1710}
1711
1712// Create an audio-only answer to a video offer.
1713TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1714 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001715 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1716 RtpTransceiverDirection::kRecvOnly, kActive,
1717 &opts);
1718 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1719 RtpTransceiverDirection::kRecvOnly, kActive,
1720 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001721 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001722 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001723
1724 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001725 std::unique_ptr<SessionDescription> answer =
1726 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 const ContentInfo* ac = answer->GetContentByName("audio");
1728 const ContentInfo* vc = answer->GetContentByName("video");
1729 ASSERT_TRUE(ac != NULL);
1730 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001731 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732 EXPECT_TRUE(vc->rejected);
1733}
1734
1735// Create an audio-only answer to an offer with data.
1736TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001737 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001738 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001739 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1740 RtpTransceiverDirection::kRecvOnly, kActive,
1741 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001742 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001743 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001744
1745 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001746 std::unique_ptr<SessionDescription> answer =
1747 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001748 const ContentInfo* ac = answer->GetContentByName("audio");
1749 const ContentInfo* dc = answer->GetContentByName("data");
1750 ASSERT_TRUE(ac != NULL);
1751 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001752 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753 EXPECT_TRUE(dc->rejected);
1754}
1755
1756// Create an answer that rejects the contents which are rejected in the offer.
1757TEST_F(MediaSessionDescriptionFactoryTest,
1758 CreateAnswerToOfferWithRejectedMedia) {
1759 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001760 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1761 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001762 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001763 ASSERT_TRUE(offer.get() != NULL);
1764 ContentInfo* ac = offer->GetContentByName("audio");
1765 ContentInfo* vc = offer->GetContentByName("video");
1766 ContentInfo* dc = offer->GetContentByName("data");
1767 ASSERT_TRUE(ac != NULL);
1768 ASSERT_TRUE(vc != NULL);
1769 ASSERT_TRUE(dc != NULL);
1770 ac->rejected = true;
1771 vc->rejected = true;
1772 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001773 std::unique_ptr<SessionDescription> answer =
1774 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775 ac = answer->GetContentByName("audio");
1776 vc = answer->GetContentByName("video");
1777 dc = answer->GetContentByName("data");
1778 ASSERT_TRUE(ac != NULL);
1779 ASSERT_TRUE(vc != NULL);
1780 ASSERT_TRUE(dc != NULL);
1781 EXPECT_TRUE(ac->rejected);
1782 EXPECT_TRUE(vc->rejected);
1783 EXPECT_TRUE(dc->rejected);
1784}
1785
Johannes Kron0854eb62018-10-10 22:33:20 +02001786TEST_F(MediaSessionDescriptionFactoryTest,
1787 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1788 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001789 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001790 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001791 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001792 ASSERT_TRUE(offer.get() != NULL);
1793 std::unique_ptr<SessionDescription> answer_no_support(
1794 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001795 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001796
1797 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001798 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001799 ASSERT_TRUE(offer.get() != NULL);
1800 std::unique_ptr<SessionDescription> answer_support(
1801 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001802 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001803}
1804
1805TEST_F(MediaSessionDescriptionFactoryTest,
1806 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1807 MediaSessionOptions opts;
1808 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001809 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001810 MediaContentDescription* video_offer =
1811 offer->GetContentDescriptionByName("video");
1812 ASSERT_TRUE(video_offer);
1813 MediaContentDescription* audio_offer =
1814 offer->GetContentDescriptionByName("audio");
1815 ASSERT_TRUE(audio_offer);
1816
1817 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001818 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1819 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001820
1821 ASSERT_TRUE(offer.get() != NULL);
1822 std::unique_ptr<SessionDescription> answer_no_support(
1823 f2_.CreateAnswer(offer.get(), opts, NULL));
1824 MediaContentDescription* video_answer =
1825 answer_no_support->GetContentDescriptionByName("video");
1826 MediaContentDescription* audio_answer =
1827 answer_no_support->GetContentDescriptionByName("audio");
1828 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001829 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001830 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001831 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001832
1833 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001834 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1835 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001836 ASSERT_TRUE(offer.get() != NULL);
1837 std::unique_ptr<SessionDescription> answer_support(
1838 f2_.CreateAnswer(offer.get(), opts, NULL));
1839 video_answer = answer_support->GetContentDescriptionByName("video");
1840 audio_answer = answer_support->GetContentDescriptionByName("audio");
1841 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001842 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001843 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001844 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001845}
1846
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847// Create an audio and video offer with:
1848// - one video track
1849// - two audio tracks
1850// - two data tracks
1851// and ensure it matches what we expect. Also updates the initial offer by
1852// adding a new video track and replaces one of the audio tracks.
1853TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1854 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001855 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001856 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1857 {kMediaStream1}, 1, &opts);
1858 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1859 {kMediaStream1}, 1, &opts);
1860 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1861 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001862
Steve Anton4e70a722017-11-28 14:57:10 -08001863 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001864 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1865 {kMediaStream1}, 1, &opts);
1866 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1867 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001868
1869 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001870 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871
1872 ASSERT_TRUE(offer.get() != NULL);
1873 const ContentInfo* ac = offer->GetContentByName("audio");
1874 const ContentInfo* vc = offer->GetContentByName("video");
1875 const ContentInfo* dc = offer->GetContentByName("data");
1876 ASSERT_TRUE(ac != NULL);
1877 ASSERT_TRUE(vc != NULL);
1878 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001879 const AudioContentDescription* acd = ac->media_description()->as_audio();
1880 const VideoContentDescription* vcd = vc->media_description()->as_video();
1881 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001882 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001883 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884
1885 const StreamParamsVec& audio_streams = acd->streams();
1886 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001887 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001888 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1889 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1890 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1891 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1892 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1893 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1894
1895 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1896 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001897 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001898
1899 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1900 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001901 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001902
1903 const StreamParamsVec& video_streams = vcd->streams();
1904 ASSERT_EQ(1U, video_streams.size());
1905 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1906 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1907 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1908 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1909
1910 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1911 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001912 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001913
1914 const StreamParamsVec& data_streams = dcd->streams();
1915 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001916 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001917 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1918 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1919 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1920 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1921 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1922 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1923
1924 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001925 dcd->bandwidth()); // default bandwidth (auto)
1926 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001927 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001928
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001929 // Update the offer. Add a new video track that is not synched to the
1930 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001931 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
1932 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001933 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001934 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
1935 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001936 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001937 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
1938 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001939 std::unique_ptr<SessionDescription> updated_offer(
1940 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941
1942 ASSERT_TRUE(updated_offer.get() != NULL);
1943 ac = updated_offer->GetContentByName("audio");
1944 vc = updated_offer->GetContentByName("video");
1945 dc = updated_offer->GetContentByName("data");
1946 ASSERT_TRUE(ac != NULL);
1947 ASSERT_TRUE(vc != NULL);
1948 ASSERT_TRUE(dc != NULL);
1949 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001950 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001952 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001954 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001955
1956 EXPECT_EQ(acd->type(), updated_acd->type());
1957 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1958 EXPECT_EQ(vcd->type(), updated_vcd->type());
1959 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1960 EXPECT_EQ(dcd->type(), updated_dcd->type());
1961 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001962 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001963 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001964 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001966 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001967 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1968
1969 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1970 ASSERT_EQ(2U, updated_audio_streams.size());
1971 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1972 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1973 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1974 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1975 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1976
1977 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1978 ASSERT_EQ(2U, updated_video_streams.size());
1979 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1980 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001981 // All the media streams in one PeerConnection share one RTCP CNAME.
1982 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983
1984 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1985 ASSERT_EQ(2U, updated_data_streams.size());
1986 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1987 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1988 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1989 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1990 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001991 // The stream correctly got the CNAME from the MediaSessionOptions.
1992 // The Expected RTCP CNAME is the default one as we are using the default
1993 // MediaSessionOptions.
1994 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001995}
1996
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001997// Create an offer with simulcast video stream.
1998TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1999 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002000 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2001 RtpTransceiverDirection::kRecvOnly, kActive,
2002 &opts);
2003 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2004 RtpTransceiverDirection::kSendRecv, kActive,
2005 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002006 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002007 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2008 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002009 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002010
2011 ASSERT_TRUE(offer.get() != NULL);
2012 const ContentInfo* vc = offer->GetContentByName("video");
2013 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002014 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002015
2016 const StreamParamsVec& video_streams = vcd->streams();
2017 ASSERT_EQ(1U, video_streams.size());
2018 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2019 const SsrcGroup* sim_ssrc_group =
2020 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2021 ASSERT_TRUE(sim_ssrc_group != NULL);
2022 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2023}
2024
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002025MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2026 const RidDescription& rid1 = ::testing::get<0>(arg);
2027 const RidDescription& rid2 = ::testing::get<1>(arg);
2028 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2029}
2030
2031static void CheckSimulcastInSessionDescription(
2032 const SessionDescription* description,
2033 const std::string& content_name,
2034 const std::vector<RidDescription>& send_rids,
2035 const SimulcastLayerList& send_layers,
2036 const RidDescription& receive_rid,
2037 const SimulcastLayer& receive_layer) {
2038 ASSERT_NE(description, nullptr);
2039 const ContentInfo* content = description->GetContentByName(content_name);
2040 ASSERT_NE(content, nullptr);
2041 const MediaContentDescription* cd = content->media_description();
2042 ASSERT_NE(cd, nullptr);
2043 const StreamParamsVec& streams = cd->streams();
2044 ASSERT_THAT(streams, SizeIs(1));
2045 const StreamParams& stream = streams[0];
2046 ASSERT_THAT(stream.ssrcs, IsEmpty());
2047 EXPECT_TRUE(stream.has_rids());
2048 const std::vector<RidDescription> rids = stream.rids();
2049
2050 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2051
2052 ASSERT_TRUE(cd->has_receive_stream());
2053 const StreamParams& receive_stream = cd->receive_stream();
2054 EXPECT_THAT(receive_stream.ssrcs, IsEmpty());
2055 EXPECT_TRUE(receive_stream.has_rids());
2056 ASSERT_THAT(receive_stream.rids(), SizeIs(1));
2057
2058 EXPECT_EQ(receive_rid.rid, receive_stream.rids()[0].rid);
2059 EXPECT_EQ(receive_rid.direction, receive_stream.rids()[0].direction);
2060
2061 EXPECT_TRUE(cd->HasSimulcast());
2062 const SimulcastDescription& simulcast = cd->simulcast_description();
2063 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2064 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2065
2066 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(1));
2067 EXPECT_EQ(receive_layer, simulcast.receive_layers().GetAllLayers()[0]);
2068}
2069
2070// Create an offer with spec-compliant simulcast video stream.
2071TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2072 MediaSessionOptions opts;
2073 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2074 RtpTransceiverDirection::kSendRecv, kActive,
2075 &opts);
2076 RidDescription receive_rid("1", RidDirection::kReceive);
2077 SimulcastLayer receive_layer(receive_rid.rid, false);
2078 opts.media_description_options[0].receive_rids = {receive_rid};
2079 opts.media_description_options[0].receive_simulcast_layers.AddLayer(
2080 receive_layer);
2081 std::vector<RidDescription> send_rids;
2082 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2083 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2084 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2085 SimulcastLayerList simulcast_layers;
2086 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2087 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2088 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2089 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2090 {kMediaStream1}, send_rids,
2091 simulcast_layers, 0, &opts);
2092 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2093
2094 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
2095 simulcast_layers, receive_rid,
2096 receive_layer);
2097}
2098
2099// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2100// In this scenario, RIDs do not need to be negotiated (there is only one).
2101TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2102 MediaSessionOptions opts;
2103 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2104 RtpTransceiverDirection::kSendRecv, kActive,
2105 &opts);
2106 RidDescription rid("f", RidDirection::kSend);
2107 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2108 {kMediaStream1}, {rid},
2109 SimulcastLayerList(), 0, &opts);
2110 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2111
2112 ASSERT_NE(offer.get(), nullptr);
2113 const ContentInfo* content = offer->GetContentByName("video");
2114 ASSERT_NE(content, nullptr);
2115 const MediaContentDescription* cd = content->media_description();
2116 ASSERT_NE(cd, nullptr);
2117 EXPECT_FALSE(cd->has_receive_stream());
2118 const StreamParamsVec& streams = cd->streams();
2119 ASSERT_THAT(streams, SizeIs(1));
2120 const StreamParams& stream = streams[0];
2121 ASSERT_THAT(stream.ssrcs, IsEmpty());
2122 EXPECT_FALSE(stream.has_rids());
2123 EXPECT_FALSE(cd->HasSimulcast());
2124}
2125
2126// Create an answer with spec-compliant simulcast video stream.
2127// In this scenario, the SFU is the caller requesting that we send Simulcast.
2128TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2129 MediaSessionOptions offer_opts;
2130 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2131 RtpTransceiverDirection::kSendRecv, kActive,
2132 &offer_opts);
2133 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2134 {kMediaStream1}, 1, &offer_opts);
2135 std::unique_ptr<SessionDescription> offer =
2136 f1_.CreateOffer(offer_opts, nullptr);
2137
2138 MediaSessionOptions answer_opts;
2139 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2140 RtpTransceiverDirection::kSendRecv, kActive,
2141 &answer_opts);
2142
2143 RidDescription receive_rid("1", RidDirection::kReceive);
2144 SimulcastLayer receive_layer(receive_rid.rid, false);
2145 answer_opts.media_description_options[0].receive_rids = {receive_rid};
2146 answer_opts.media_description_options[0].receive_simulcast_layers.AddLayer(
2147 receive_layer);
2148 std::vector<RidDescription> rid_descriptions{
2149 RidDescription("f", RidDirection::kSend),
2150 RidDescription("h", RidDirection::kSend),
2151 RidDescription("q", RidDirection::kSend),
2152 };
2153 SimulcastLayerList simulcast_layers;
2154 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2155 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2156 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2157 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2158 {kMediaStream1}, rid_descriptions,
2159 simulcast_layers, 0, &answer_opts);
2160 std::unique_ptr<SessionDescription> answer =
2161 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2162
2163 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
2164 simulcast_layers, receive_rid,
2165 receive_layer);
2166}
2167
2168// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2169// In this scenario, RIDs do not need to be negotiated (there is only one).
2170// Note that RID Direction is not the same as the transceiver direction.
2171TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2172 MediaSessionOptions offer_opts;
2173 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2174 RtpTransceiverDirection::kSendRecv, kActive,
2175 &offer_opts);
2176 RidDescription rid_offer("f", RidDirection::kSend);
2177 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2178 {kMediaStream1}, {rid_offer},
2179 SimulcastLayerList(), 0, &offer_opts);
2180 std::unique_ptr<SessionDescription> offer =
2181 f1_.CreateOffer(offer_opts, nullptr);
2182
2183 MediaSessionOptions answer_opts;
2184 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2185 RtpTransceiverDirection::kSendRecv, kActive,
2186 &answer_opts);
2187
2188 RidDescription rid_answer("f", RidDirection::kReceive);
2189 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2190 {kMediaStream1}, {rid_answer},
2191 SimulcastLayerList(), 0, &answer_opts);
2192 std::unique_ptr<SessionDescription> answer =
2193 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2194
2195 ASSERT_NE(answer.get(), nullptr);
2196 const ContentInfo* content = offer->GetContentByName("video");
2197 ASSERT_NE(content, nullptr);
2198 const MediaContentDescription* cd = content->media_description();
2199 ASSERT_NE(cd, nullptr);
2200 EXPECT_FALSE(cd->has_receive_stream());
2201 const StreamParamsVec& streams = cd->streams();
2202 ASSERT_THAT(streams, SizeIs(1));
2203 const StreamParams& stream = streams[0];
2204 ASSERT_THAT(stream.ssrcs, IsEmpty());
2205 EXPECT_FALSE(stream.has_rids());
2206 EXPECT_FALSE(cd->HasSimulcast());
2207}
2208
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002209// Create an audio and video answer to a standard video offer with:
2210// - one video track
2211// - two audio tracks
2212// - two data tracks
2213// and ensure it matches what we expect. Also updates the initial answer by
2214// adding a new video track and removes one of the audio tracks.
2215TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2216 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002217 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2218 RtpTransceiverDirection::kRecvOnly, kActive,
2219 &offer_opts);
2220 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2221 RtpTransceiverDirection::kRecvOnly, kActive,
2222 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002223 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002224 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2225 RtpTransceiverDirection::kRecvOnly, kActive,
2226 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002227 f1_.set_secure(SEC_ENABLED);
2228 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002229 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002230
zhihuang1c378ed2017-08-17 14:10:50 -07002231 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002232 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2233 RtpTransceiverDirection::kSendRecv, kActive,
2234 &answer_opts);
2235 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2236 RtpTransceiverDirection::kSendRecv, kActive,
2237 &answer_opts);
2238 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2239 {kMediaStream1}, 1, &answer_opts);
2240 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2241 {kMediaStream1}, 1, &answer_opts);
2242 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2243 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002244
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002245 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2246 RtpTransceiverDirection::kSendRecv, kActive,
2247 &answer_opts);
2248 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2249 {kMediaStream1}, 1, &answer_opts);
2250 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2251 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002252 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002253
Steve Anton6fe1fba2018-12-11 10:15:23 -08002254 std::unique_ptr<SessionDescription> answer =
2255 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002256
2257 ASSERT_TRUE(answer.get() != NULL);
2258 const ContentInfo* ac = answer->GetContentByName("audio");
2259 const ContentInfo* vc = answer->GetContentByName("video");
2260 const ContentInfo* dc = answer->GetContentByName("data");
2261 ASSERT_TRUE(ac != NULL);
2262 ASSERT_TRUE(vc != NULL);
2263 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002264 const AudioContentDescription* acd = ac->media_description()->as_audio();
2265 const VideoContentDescription* vcd = vc->media_description()->as_video();
2266 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002267 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2268 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2269 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002270
2271 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002272 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002273
2274 const StreamParamsVec& audio_streams = acd->streams();
2275 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002276 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002277 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2278 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2279 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2280 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2281 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2282 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2283
2284 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2285 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2286
2287 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002288 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002289
2290 const StreamParamsVec& video_streams = vcd->streams();
2291 ASSERT_EQ(1U, video_streams.size());
2292 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2293 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2294 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2295 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2296
2297 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002298 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002299
2300 const StreamParamsVec& data_streams = dcd->streams();
2301 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002302 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002303 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2304 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2305 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2306 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2307 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2308 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2309
2310 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002311 dcd->bandwidth()); // default bandwidth (auto)
2312 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002313
2314 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002315 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002316 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2317 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002318 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2319 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002320 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002321 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002322
2323 ASSERT_TRUE(updated_answer.get() != NULL);
2324 ac = updated_answer->GetContentByName("audio");
2325 vc = updated_answer->GetContentByName("video");
2326 dc = updated_answer->GetContentByName("data");
2327 ASSERT_TRUE(ac != NULL);
2328 ASSERT_TRUE(vc != NULL);
2329 ASSERT_TRUE(dc != NULL);
2330 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002331 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002332 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002333 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002334 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002335 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002336
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002337 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002338 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002339 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002341 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002342 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2343
2344 EXPECT_EQ(acd->type(), updated_acd->type());
2345 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2346 EXPECT_EQ(vcd->type(), updated_vcd->type());
2347 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2348 EXPECT_EQ(dcd->type(), updated_dcd->type());
2349 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2350
2351 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2352 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002353 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002354
2355 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2356 ASSERT_EQ(2U, updated_video_streams.size());
2357 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2358 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002359 // All media streams in one PeerConnection share one CNAME.
2360 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002361
2362 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2363 ASSERT_EQ(1U, updated_data_streams.size());
2364 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2365}
2366
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002367// Create an updated offer after creating an answer to the original offer and
2368// verify that the codecs that were part of the original answer are not changed
2369// in the updated offer.
2370TEST_F(MediaSessionDescriptionFactoryTest,
2371 RespondentCreatesOfferAfterCreatingAnswer) {
2372 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002373 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002374
Steve Anton6fe1fba2018-12-11 10:15:23 -08002375 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2376 std::unique_ptr<SessionDescription> answer =
2377 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002378
2379 const AudioContentDescription* acd =
2380 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002381 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382
2383 const VideoContentDescription* vcd =
2384 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002385 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002386
kwiberg31022942016-03-11 14:18:21 -08002387 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002388 f2_.CreateOffer(opts, answer.get()));
2389
2390 // The expected audio codecs are the common audio codecs from the first
2391 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2392 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002393 // TODO(wu): |updated_offer| should not include the codec
2394 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002395 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002396 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002397 };
2398
2399 // The expected video codecs are the common video codecs from the first
2400 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2401 // preference order.
2402 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002403 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002404 };
2405
2406 const AudioContentDescription* updated_acd =
2407 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002408 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002409
2410 const VideoContentDescription* updated_vcd =
2411 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002412 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002413}
2414
Steve Anton5c72e712018-12-10 14:25:30 -08002415// Test that a reoffer does not reuse audio codecs from a previous media section
2416// that is being recycled.
2417TEST_F(MediaSessionDescriptionFactoryTest,
2418 ReOfferDoesNotReUseRecycledAudioCodecs) {
2419 f1_.set_video_codecs({});
2420 f2_.set_video_codecs({});
2421
2422 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002423 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2424 RtpTransceiverDirection::kSendRecv, kActive,
2425 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002426 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2427 std::unique_ptr<SessionDescription> answer =
2428 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002429
2430 // Recycle the media section by changing its mid.
2431 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002432 std::unique_ptr<SessionDescription> reoffer =
2433 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002434
2435 // Expect that the results of the first negotiation are ignored. If the m=
2436 // section was not recycled the payload types would match the initial offerer.
2437 const AudioContentDescription* acd =
2438 GetFirstAudioContentDescription(reoffer.get());
2439 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2440}
2441
2442// Test that a reoffer does not reuse video codecs from a previous media section
2443// that is being recycled.
2444TEST_F(MediaSessionDescriptionFactoryTest,
2445 ReOfferDoesNotReUseRecycledVideoCodecs) {
2446 f1_.set_audio_codecs({}, {});
2447 f2_.set_audio_codecs({}, {});
2448
2449 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002450 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2451 RtpTransceiverDirection::kSendRecv, kActive,
2452 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002453 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2454 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002455
2456 // Recycle the media section by changing its mid.
2457 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002458 std::unique_ptr<SessionDescription> reoffer =
2459 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002460
2461 // Expect that the results of the first negotiation are ignored. If the m=
2462 // section was not recycled the payload types would match the initial offerer.
2463 const VideoContentDescription* vcd =
2464 GetFirstVideoContentDescription(reoffer.get());
2465 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2466}
2467
2468// Test that a reanswer does not reuse audio codecs from a previous media
2469// section that is being recycled.
2470TEST_F(MediaSessionDescriptionFactoryTest,
2471 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2472 f1_.set_video_codecs({});
2473 f2_.set_video_codecs({});
2474
2475 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2476 // second offer/answer is forward (|f1_| as offerer).
2477 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002478 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2479 RtpTransceiverDirection::kSendRecv, kActive,
2480 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002481 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2482 std::unique_ptr<SessionDescription> answer =
2483 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002484
2485 // Recycle the media section by changing its mid.
2486 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002487 std::unique_ptr<SessionDescription> reoffer =
2488 f1_.CreateOffer(opts, answer.get());
2489 std::unique_ptr<SessionDescription> reanswer =
2490 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002491
2492 // Expect that the results of the first negotiation are ignored. If the m=
2493 // section was not recycled the payload types would match the initial offerer.
2494 const AudioContentDescription* acd =
2495 GetFirstAudioContentDescription(reanswer.get());
2496 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2497}
2498
2499// Test that a reanswer does not reuse video codecs from a previous media
2500// section that is being recycled.
2501TEST_F(MediaSessionDescriptionFactoryTest,
2502 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2503 f1_.set_audio_codecs({}, {});
2504 f2_.set_audio_codecs({}, {});
2505
2506 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2507 // second offer/answer is forward (|f1_| as offerer).
2508 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002509 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2510 RtpTransceiverDirection::kSendRecv, kActive,
2511 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002512 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2513 std::unique_ptr<SessionDescription> answer =
2514 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002515
2516 // Recycle the media section by changing its mid.
2517 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002518 std::unique_ptr<SessionDescription> reoffer =
2519 f1_.CreateOffer(opts, answer.get());
2520 std::unique_ptr<SessionDescription> reanswer =
2521 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002522
2523 // Expect that the results of the first negotiation are ignored. If the m=
2524 // section was not recycled the payload types would match the initial offerer.
2525 const VideoContentDescription* vcd =
2526 GetFirstVideoContentDescription(reanswer.get());
2527 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2528}
2529
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530// Create an updated offer after creating an answer to the original offer and
2531// verify that the codecs that were part of the original answer are not changed
2532// in the updated offer. In this test Rtx is enabled.
2533TEST_F(MediaSessionDescriptionFactoryTest,
2534 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2535 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002536 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2537 RtpTransceiverDirection::kRecvOnly, kActive,
2538 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002539 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002540 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002541 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002542 f1_.set_video_codecs(f1_codecs);
2543
2544 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002545 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002546 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002547 f2_.set_video_codecs(f2_codecs);
2548
Steve Anton6fe1fba2018-12-11 10:15:23 -08002549 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002550 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002551 std::unique_ptr<SessionDescription> answer =
2552 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002553
2554 const VideoContentDescription* vcd =
2555 GetFirstVideoContentDescription(answer.get());
2556
2557 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002558 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2559 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002560
2561 EXPECT_EQ(expected_codecs, vcd->codecs());
2562
deadbeef67cf2c12016-04-13 10:07:16 -07002563 // Now, make sure we get same result (except for the order) if |f2_| creates
2564 // an updated offer even though the default payload types between |f1_| and
2565 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002566 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002567 f2_.CreateOffer(opts, answer.get()));
2568 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002569 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002570 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2571
2572 const VideoContentDescription* updated_vcd =
2573 GetFirstVideoContentDescription(updated_answer.get());
2574
2575 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2576}
2577
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002578// Regression test for:
2579// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2580// Existing codecs should always appear before new codecs in re-offers. But
2581// under a specific set of circumstances, the existing RTX codec was ending up
2582// added to the end of the list.
2583TEST_F(MediaSessionDescriptionFactoryTest,
2584 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2585 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002586 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2587 RtpTransceiverDirection::kRecvOnly, kActive,
2588 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002589 // We specifically choose different preferred payload types for VP8 to
2590 // trigger the issue.
2591 cricket::VideoCodec vp8_offerer(100, "VP8");
2592 cricket::VideoCodec vp8_offerer_rtx =
2593 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2594 cricket::VideoCodec vp8_answerer(110, "VP8");
2595 cricket::VideoCodec vp8_answerer_rtx =
2596 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2597 cricket::VideoCodec vp9(120, "VP9");
2598 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2599
2600 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2601 // We also specifically cause the answerer to prefer VP9, such that if it
2602 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2603 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2604 vp8_answerer_rtx};
2605
2606 f1_.set_video_codecs(f1_codecs);
2607 f2_.set_video_codecs(f2_codecs);
2608 std::vector<AudioCodec> audio_codecs;
2609 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2610 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2611
2612 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002613 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002614 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002615 std::unique_ptr<SessionDescription> answer =
2616 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002617
2618 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2619 // But if the bug is triggered, RTX for VP8 ends up last.
2620 std::unique_ptr<SessionDescription> updated_offer(
2621 f2_.CreateOffer(opts, answer.get()));
2622
2623 const VideoContentDescription* vcd =
2624 GetFirstVideoContentDescription(updated_offer.get());
2625 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2626 ASSERT_EQ(4u, codecs.size());
2627 EXPECT_EQ(vp8_offerer, codecs[0]);
2628 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2629 EXPECT_EQ(vp9, codecs[2]);
2630 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002631}
2632
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002633// Create an updated offer that adds video after creating an audio only answer
2634// to the original offer. This test verifies that if a video codec and the RTX
2635// codec have the same default payload type as an audio codec that is already in
2636// use, the added codecs payload types are changed.
2637TEST_F(MediaSessionDescriptionFactoryTest,
2638 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2639 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002640 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002641 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642 f1_.set_video_codecs(f1_codecs);
2643
2644 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002645 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2646 RtpTransceiverDirection::kRecvOnly, kActive,
2647 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002648
Steve Anton6fe1fba2018-12-11 10:15:23 -08002649 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2650 std::unique_ptr<SessionDescription> answer =
2651 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002652
2653 const AudioContentDescription* acd =
2654 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002655 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002656
2657 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2658 // reference be the same as an audio codec that was negotiated in the
2659 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002660 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002661 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002662
2663 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2664 int used_pl_type = acd->codecs()[0].id;
2665 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002666 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002667 f2_.set_video_codecs(f2_codecs);
2668
kwiberg31022942016-03-11 14:18:21 -08002669 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670 f2_.CreateOffer(opts, answer.get()));
2671 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002672 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002673 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2674
2675 const AudioContentDescription* updated_acd =
2676 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002677 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002678
2679 const VideoContentDescription* updated_vcd =
2680 GetFirstVideoContentDescription(updated_answer.get());
2681
2682 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002683 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002684 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002685 EXPECT_NE(used_pl_type, new_h264_pl_type);
2686 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002687 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002688 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2689 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2690}
2691
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002692// Create an updated offer with RTX after creating an answer to an offer
2693// without RTX, and with different default payload types.
2694// Verify that the added RTX codec references the correct payload type.
2695TEST_F(MediaSessionDescriptionFactoryTest,
2696 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2697 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002698 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002699
2700 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2701 // This creates rtx for H264 with the payload type |f2_| uses.
2702 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2703 f2_.set_video_codecs(f2_codecs);
2704
Steve Anton6fe1fba2018-12-11 10:15:23 -08002705 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002706 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002707 std::unique_ptr<SessionDescription> answer =
2708 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002709
2710 const VideoContentDescription* vcd =
2711 GetFirstVideoContentDescription(answer.get());
2712
2713 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2714 EXPECT_EQ(expected_codecs, vcd->codecs());
2715
2716 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2717 // updated offer, even though the default payload types are different from
2718 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002719 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002720 f2_.CreateOffer(opts, answer.get()));
2721 ASSERT_TRUE(updated_offer);
2722
2723 const VideoContentDescription* updated_vcd =
2724 GetFirstVideoContentDescription(updated_offer.get());
2725
2726 // New offer should attempt to add H263, and RTX for H264.
2727 expected_codecs.push_back(kVideoCodecs2[1]);
2728 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2729 &expected_codecs);
2730 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2731}
2732
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002733// Test that RTX is ignored when there is no associated payload type parameter.
2734TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2735 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002736 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2737 RtpTransceiverDirection::kRecvOnly, kActive,
2738 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002739 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002740 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002741 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002742 f1_.set_video_codecs(f1_codecs);
2743
2744 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002745 // This creates RTX for H264 with the payload type |f2_| uses.
2746 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002747 f2_.set_video_codecs(f2_codecs);
2748
Steve Anton6fe1fba2018-12-11 10:15:23 -08002749 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002750 ASSERT_TRUE(offer.get() != NULL);
2751 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2752 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2753 // is possible to test that that RTX is dropped when
2754 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002755 MediaContentDescription* media_desc =
2756 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2757 ASSERT_TRUE(media_desc);
2758 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002759 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002760 for (VideoCodec& codec : codecs) {
2761 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2762 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002763 }
2764 }
2765 desc->set_codecs(codecs);
2766
Steve Anton6fe1fba2018-12-11 10:15:23 -08002767 std::unique_ptr<SessionDescription> answer =
2768 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002769
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002770 std::vector<std::string> codec_names =
2771 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2772 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2773 cricket::kRtxCodecName));
2774}
2775
2776// Test that RTX will be filtered out in the answer if its associated payload
2777// type doesn't match the local value.
2778TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2779 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002780 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2781 RtpTransceiverDirection::kRecvOnly, kActive,
2782 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002783 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2784 // This creates RTX for H264 in sender.
2785 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2786 f1_.set_video_codecs(f1_codecs);
2787
2788 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2789 // This creates RTX for H263 in receiver.
2790 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2791 f2_.set_video_codecs(f2_codecs);
2792
Steve Anton6fe1fba2018-12-11 10:15:23 -08002793 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002794 ASSERT_TRUE(offer.get() != NULL);
2795 // Associated payload type doesn't match, therefore, RTX codec is removed in
2796 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002797 std::unique_ptr<SessionDescription> answer =
2798 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002799
2800 std::vector<std::string> codec_names =
2801 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2802 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2803 cricket::kRtxCodecName));
2804}
2805
2806// Test that when multiple RTX codecs are offered, only the matched RTX codec
2807// is added in the answer, and the unsupported RTX codec is filtered out.
2808TEST_F(MediaSessionDescriptionFactoryTest,
2809 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2810 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002811 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2812 RtpTransceiverDirection::kRecvOnly, kActive,
2813 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002814 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2815 // This creates RTX for H264-SVC in sender.
2816 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2817 f1_.set_video_codecs(f1_codecs);
2818
2819 // This creates RTX for H264 in sender.
2820 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2821 f1_.set_video_codecs(f1_codecs);
2822
2823 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2824 // This creates RTX for H264 in receiver.
2825 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2826 f2_.set_video_codecs(f2_codecs);
2827
2828 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2829 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002830 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002831 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002832 std::unique_ptr<SessionDescription> answer =
2833 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002834 const VideoContentDescription* vcd =
2835 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002836 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2837 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2838 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002839
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002840 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002841}
2842
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002843// Test that after one RTX codec has been negotiated, a new offer can attempt
2844// to add another.
2845TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2846 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002847 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2848 RtpTransceiverDirection::kRecvOnly, kActive,
2849 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002850 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2851 // This creates RTX for H264 for the offerer.
2852 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2853 f1_.set_video_codecs(f1_codecs);
2854
Steve Anton6fe1fba2018-12-11 10:15:23 -08002855 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002856 ASSERT_TRUE(offer);
2857 const VideoContentDescription* vcd =
2858 GetFirstVideoContentDescription(offer.get());
2859
2860 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2861 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2862 &expected_codecs);
2863 EXPECT_EQ(expected_codecs, vcd->codecs());
2864
2865 // Now, attempt to add RTX for H264-SVC.
2866 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2867 f1_.set_video_codecs(f1_codecs);
2868
kwiberg31022942016-03-11 14:18:21 -08002869 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002870 f1_.CreateOffer(opts, offer.get()));
2871 ASSERT_TRUE(updated_offer);
2872 vcd = GetFirstVideoContentDescription(updated_offer.get());
2873
2874 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2875 &expected_codecs);
2876 EXPECT_EQ(expected_codecs, vcd->codecs());
2877}
2878
Noah Richards2e7a0982015-05-18 14:02:54 -07002879// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2880// generated for each simulcast ssrc and correctly grouped.
2881TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2882 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002883 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2884 RtpTransceiverDirection::kSendRecv, kActive,
2885 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002886 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002887 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2888 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002889
2890 // Use a single real codec, and then add RTX for it.
2891 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002892 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002893 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2894 f1_.set_video_codecs(f1_codecs);
2895
2896 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2897 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002898 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002899 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002900 MediaContentDescription* media_desc =
2901 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2902 ASSERT_TRUE(media_desc);
2903 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002904 const StreamParamsVec& streams = desc->streams();
2905 // Single stream.
2906 ASSERT_EQ(1u, streams.size());
2907 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2908 EXPECT_EQ(6u, streams[0].ssrcs.size());
2909 // And should have a SIM group for the simulcast.
2910 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2911 // And a FID group for RTX.
2912 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002913 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002914 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2915 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002916 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002917 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2918 EXPECT_EQ(3u, fid_ssrcs.size());
2919}
2920
brandtr03d5fb12016-11-22 03:37:59 -08002921// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2922// together with a FEC-FR grouping.
2923TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2924 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002925 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2926 RtpTransceiverDirection::kSendRecv, kActive,
2927 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002928 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002929 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2930 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002931
2932 // Use a single real codec, and then add FlexFEC for it.
2933 std::vector<VideoCodec> f1_codecs;
2934 f1_codecs.push_back(VideoCodec(97, "H264"));
2935 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2936 f1_.set_video_codecs(f1_codecs);
2937
2938 // Ensure that the offer has a single FlexFEC ssrc and that
2939 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002941 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002942 MediaContentDescription* media_desc =
2943 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2944 ASSERT_TRUE(media_desc);
2945 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002946 const StreamParamsVec& streams = desc->streams();
2947 // Single stream.
2948 ASSERT_EQ(1u, streams.size());
2949 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2950 EXPECT_EQ(2u, streams[0].ssrcs.size());
2951 // And should have a FEC-FR group for FlexFEC.
2952 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2953 std::vector<uint32_t> primary_ssrcs;
2954 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2955 ASSERT_EQ(1u, primary_ssrcs.size());
2956 uint32_t flexfec_ssrc;
2957 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2958 EXPECT_NE(flexfec_ssrc, 0u);
2959}
2960
2961// Test that FlexFEC is disabled for simulcast.
2962// TODO(brandtr): Remove this test when we support simulcast, either through
2963// multiple FlexfecSenders, or through multistream protection.
2964TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2965 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002966 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2967 RtpTransceiverDirection::kSendRecv, kActive,
2968 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002969 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002970 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2971 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002972
2973 // Use a single real codec, and then add FlexFEC for it.
2974 std::vector<VideoCodec> f1_codecs;
2975 f1_codecs.push_back(VideoCodec(97, "H264"));
2976 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2977 f1_.set_video_codecs(f1_codecs);
2978
2979 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2980 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002981 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002982 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002983 MediaContentDescription* media_desc =
2984 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2985 ASSERT_TRUE(media_desc);
2986 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002987 const StreamParamsVec& streams = desc->streams();
2988 // Single stream.
2989 ASSERT_EQ(1u, streams.size());
2990 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2991 EXPECT_EQ(3u, streams[0].ssrcs.size());
2992 // And should have a SIM group for the simulcast.
2993 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2994 // And not a FEC-FR group for FlexFEC.
2995 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2996 std::vector<uint32_t> primary_ssrcs;
2997 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2998 EXPECT_EQ(3u, primary_ssrcs.size());
2999 for (uint32_t primary_ssrc : primary_ssrcs) {
3000 uint32_t flexfec_ssrc;
3001 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3002 }
3003}
3004
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003005// Create an updated offer after creating an answer to the original offer and
3006// verify that the RTP header extensions that were part of the original answer
3007// are not changed in the updated offer.
3008TEST_F(MediaSessionDescriptionFactoryTest,
3009 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3010 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003011 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003012
3013 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3014 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3015 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3016 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3017
Steve Anton6fe1fba2018-12-11 10:15:23 -08003018 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3019 std::unique_ptr<SessionDescription> answer =
3020 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003021
Yves Gerey665174f2018-06-19 15:03:05 +02003022 EXPECT_EQ(
3023 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3024 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3025 EXPECT_EQ(
3026 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3027 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003028
kwiberg31022942016-03-11 14:18:21 -08003029 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003030 f2_.CreateOffer(opts, answer.get()));
3031
3032 // The expected RTP header extensions in the new offer are the resulting
3033 // extensions from the first offer/answer exchange plus the extensions only
3034 // |f2_| offer.
3035 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003036 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003037 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3038 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3039 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003040 };
3041
3042 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003043 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003044 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3045 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3046 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003047 };
3048
3049 const AudioContentDescription* updated_acd =
3050 GetFirstAudioContentDescription(updated_offer.get());
3051 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3052 updated_acd->rtp_header_extensions());
3053
3054 const VideoContentDescription* updated_vcd =
3055 GetFirstVideoContentDescription(updated_offer.get());
3056 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3057 updated_vcd->rtp_header_extensions());
3058}
3059
deadbeefa5b273a2015-08-20 17:30:13 -07003060// Verify that if the same RTP extension URI is used for audio and video, the
3061// same ID is used. Also verify that the ID isn't changed when creating an
3062// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003063TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003064 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003065 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003066
3067 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3068 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3069
Steve Anton6fe1fba2018-12-11 10:15:23 -08003070 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003071
3072 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3073 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003074 const RtpExtension kExpectedVideoRtpExtension[] = {
3075 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003076 };
3077
Yves Gerey665174f2018-06-19 15:03:05 +02003078 EXPECT_EQ(
3079 MAKE_VECTOR(kAudioRtpExtension3),
3080 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3081 EXPECT_EQ(
3082 MAKE_VECTOR(kExpectedVideoRtpExtension),
3083 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003084
3085 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003086 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003087 f1_.CreateOffer(opts, offer.get()));
3088
3089 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003090 GetFirstAudioContentDescription(updated_offer.get())
3091 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003092 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003093 GetFirstVideoContentDescription(updated_offer.get())
3094 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003095}
3096
jbauch5869f502017-06-29 12:31:36 -07003097// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3098TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3099 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003100 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003101
3102 f1_.set_enable_encrypted_rtp_header_extensions(true);
3103 f2_.set_enable_encrypted_rtp_header_extensions(true);
3104
3105 f1_.set_audio_rtp_header_extensions(
3106 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3107 f1_.set_video_rtp_header_extensions(
3108 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3109
Steve Anton6fe1fba2018-12-11 10:15:23 -08003110 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003111
3112 // The extensions that are shared between audio and video should use the same
3113 // id.
3114 const RtpExtension kExpectedVideoRtpExtension[] = {
3115 kVideoRtpExtension3ForEncryption[0],
3116 kAudioRtpExtension3ForEncryptionOffer[1],
3117 kAudioRtpExtension3ForEncryptionOffer[2],
3118 };
3119
Yves Gerey665174f2018-06-19 15:03:05 +02003120 EXPECT_EQ(
3121 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3122 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3123 EXPECT_EQ(
3124 MAKE_VECTOR(kExpectedVideoRtpExtension),
3125 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003126
3127 // Nothing should change when creating a new offer
3128 std::unique_ptr<SessionDescription> updated_offer(
3129 f1_.CreateOffer(opts, offer.get()));
3130
3131 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003132 GetFirstAudioContentDescription(updated_offer.get())
3133 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003134 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003135 GetFirstVideoContentDescription(updated_offer.get())
3136 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003137}
3138
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003139TEST(MediaSessionDescription, CopySessionDescription) {
3140 SessionDescription source;
3141 cricket::ContentGroup group(cricket::CN_AUDIO);
3142 source.AddGroup(group);
3143 AudioContentDescription* acd(new AudioContentDescription());
3144 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3145 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003146 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003147 VideoContentDescription* vcd(new VideoContentDescription());
3148 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3149 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003150 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003151
kwiberg31022942016-03-11 14:18:21 -08003152 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003153 ASSERT_TRUE(copy.get() != NULL);
3154 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3155 const ContentInfo* ac = copy->GetContentByName("audio");
3156 const ContentInfo* vc = copy->GetContentByName("video");
3157 ASSERT_TRUE(ac != NULL);
3158 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003159 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003160 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003161 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3162 EXPECT_EQ(1u, acd->first_ssrc());
3163
Steve Anton5adfafd2017-12-20 16:34:00 -08003164 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003165 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003166 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3167 EXPECT_EQ(2u, vcd->first_ssrc());
3168}
3169
3170// The below TestTransportInfoXXX tests create different offers/answers, and
3171// ensure the TransportInfo in the SessionDescription matches what we expect.
3172TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3173 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003174 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3175 RtpTransceiverDirection::kRecvOnly, kActive,
3176 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003177 TestTransportInfo(true, options, false);
3178}
3179
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003180TEST_F(MediaSessionDescriptionFactoryTest,
3181 TestTransportInfoOfferIceRenomination) {
3182 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003183 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3184 RtpTransceiverDirection::kRecvOnly, kActive,
3185 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003186 options.media_description_options[0]
3187 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003188 TestTransportInfo(true, options, false);
3189}
3190
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003191TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3192 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003193 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3194 RtpTransceiverDirection::kRecvOnly, kActive,
3195 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003196 TestTransportInfo(true, options, true);
3197}
3198
3199TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3200 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003201 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3202 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3203 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003204 TestTransportInfo(true, options, false);
3205}
3206
3207TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003208 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003209 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003210 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3211 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3212 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003213 TestTransportInfo(true, options, true);
3214}
3215
3216TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3217 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003218 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3219 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3220 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003221 options.bundle_enabled = true;
3222 TestTransportInfo(true, options, false);
3223}
3224
3225TEST_F(MediaSessionDescriptionFactoryTest,
3226 TestTransportInfoOfferBundleCurrent) {
3227 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003228 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3229 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3230 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003231 options.bundle_enabled = true;
3232 TestTransportInfo(true, options, true);
3233}
3234
3235TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3236 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003237 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3238 RtpTransceiverDirection::kRecvOnly, kActive,
3239 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003240 TestTransportInfo(false, options, false);
3241}
3242
3243TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003244 TestTransportInfoAnswerIceRenomination) {
3245 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003246 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3247 RtpTransceiverDirection::kRecvOnly, kActive,
3248 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003249 options.media_description_options[0]
3250 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003251 TestTransportInfo(false, options, false);
3252}
3253
3254TEST_F(MediaSessionDescriptionFactoryTest,
3255 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003256 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003257 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3258 RtpTransceiverDirection::kRecvOnly, kActive,
3259 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003260 TestTransportInfo(false, options, true);
3261}
3262
3263TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3264 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003265 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3266 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3267 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003268 TestTransportInfo(false, options, false);
3269}
3270
3271TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003272 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003273 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003274 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3275 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3276 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003277 TestTransportInfo(false, options, true);
3278}
3279
3280TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3281 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003282 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3283 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3284 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003285 options.bundle_enabled = true;
3286 TestTransportInfo(false, options, false);
3287}
3288
3289TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003290 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003291 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003292 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3293 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3294 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003295 options.bundle_enabled = true;
3296 TestTransportInfo(false, options, true);
3297}
3298
3299// Create an offer with bundle enabled and verify the crypto parameters are
3300// the common set of the available cryptos.
3301TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3302 TestCryptoWithBundle(true);
3303}
3304
3305// Create an answer with bundle enabled and verify the crypto parameters are
3306// the common set of the available cryptos.
3307TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3308 TestCryptoWithBundle(false);
3309}
3310
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003311// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3312// DTLS is not enabled locally.
3313TEST_F(MediaSessionDescriptionFactoryTest,
3314 TestOfferDtlsSavpfWithoutDtlsFailed) {
3315 f1_.set_secure(SEC_ENABLED);
3316 f2_.set_secure(SEC_ENABLED);
3317 tdf1_.set_secure(SEC_DISABLED);
3318 tdf2_.set_secure(SEC_DISABLED);
3319
Steve Anton6fe1fba2018-12-11 10:15:23 -08003320 std::unique_ptr<SessionDescription> offer =
3321 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003322 ASSERT_TRUE(offer.get() != NULL);
3323 ContentInfo* offer_content = offer->GetContentByName("audio");
3324 ASSERT_TRUE(offer_content != NULL);
3325 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003326 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003327 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3328
Steve Anton6fe1fba2018-12-11 10:15:23 -08003329 std::unique_ptr<SessionDescription> answer =
3330 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003331 ASSERT_TRUE(answer != NULL);
3332 ContentInfo* answer_content = answer->GetContentByName("audio");
3333 ASSERT_TRUE(answer_content != NULL);
3334
3335 ASSERT_TRUE(answer_content->rejected);
3336}
3337
3338// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3339// UDP/TLS/RTP/SAVPF.
3340TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3341 f1_.set_secure(SEC_ENABLED);
3342 f2_.set_secure(SEC_ENABLED);
3343 tdf1_.set_secure(SEC_ENABLED);
3344 tdf2_.set_secure(SEC_ENABLED);
3345
Steve Anton6fe1fba2018-12-11 10:15:23 -08003346 std::unique_ptr<SessionDescription> offer =
3347 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003348 ASSERT_TRUE(offer.get() != NULL);
3349 ContentInfo* offer_content = offer->GetContentByName("audio");
3350 ASSERT_TRUE(offer_content != NULL);
3351 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003352 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003353 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3354
Steve Anton6fe1fba2018-12-11 10:15:23 -08003355 std::unique_ptr<SessionDescription> answer =
3356 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003357 ASSERT_TRUE(answer != NULL);
3358
3359 const ContentInfo* answer_content = answer->GetContentByName("audio");
3360 ASSERT_TRUE(answer_content != NULL);
3361 ASSERT_FALSE(answer_content->rejected);
3362
3363 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003364 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003365 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003366}
3367
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003368// Test that we include both SDES and DTLS in the offer, but only include SDES
3369// in the answer if DTLS isn't negotiated.
3370TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3371 f1_.set_secure(SEC_ENABLED);
3372 f2_.set_secure(SEC_ENABLED);
3373 tdf1_.set_secure(SEC_ENABLED);
3374 tdf2_.set_secure(SEC_DISABLED);
3375 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003376 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003377 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003378 const cricket::MediaContentDescription* audio_media_desc;
3379 const cricket::MediaContentDescription* video_media_desc;
3380 const cricket::TransportDescription* audio_trans_desc;
3381 const cricket::TransportDescription* video_trans_desc;
3382
3383 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003384 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003385 ASSERT_TRUE(offer.get() != NULL);
3386
Steve Antonb1c1de12017-12-21 15:14:30 -08003387 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003388 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003389 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003390 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003391 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003392 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3393
3394 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3395 ASSERT_TRUE(audio_trans_desc != NULL);
3396 video_trans_desc = offer->GetTransportDescriptionByName("video");
3397 ASSERT_TRUE(video_trans_desc != NULL);
3398 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3399 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3400
3401 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003402 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003403 ASSERT_TRUE(answer.get() != NULL);
3404
Steve Antonb1c1de12017-12-21 15:14:30 -08003405 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003406 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003407 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003408 ASSERT_TRUE(video_media_desc != NULL);
3409 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3410 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3411
3412 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3413 ASSERT_TRUE(audio_trans_desc != NULL);
3414 video_trans_desc = answer->GetTransportDescriptionByName("video");
3415 ASSERT_TRUE(video_trans_desc != NULL);
3416 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3417 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3418
3419 // Enable DTLS; the answer should now only have DTLS support.
3420 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003421 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003422 ASSERT_TRUE(answer.get() != NULL);
3423
Steve Antonb1c1de12017-12-21 15:14:30 -08003424 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003425 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003426 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003427 ASSERT_TRUE(video_media_desc != NULL);
3428 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3429 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003430 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3431 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003432
3433 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3434 ASSERT_TRUE(audio_trans_desc != NULL);
3435 video_trans_desc = answer->GetTransportDescriptionByName("video");
3436 ASSERT_TRUE(video_trans_desc != NULL);
3437 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3438 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003439
3440 // Try creating offer again. DTLS enabled now, crypto's should be empty
3441 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003442 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003443 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003444 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003445 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003446 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003447 ASSERT_TRUE(video_media_desc != NULL);
3448 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3449 EXPECT_TRUE(video_media_desc->cryptos().empty());
3450
3451 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3452 ASSERT_TRUE(audio_trans_desc != NULL);
3453 video_trans_desc = offer->GetTransportDescriptionByName("video");
3454 ASSERT_TRUE(video_trans_desc != NULL);
3455 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3456 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003457}
3458
3459// Test that an answer can't be created if cryptos are required but the offer is
3460// unsecure.
3461TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003462 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003463 f1_.set_secure(SEC_DISABLED);
3464 tdf1_.set_secure(SEC_DISABLED);
3465 f2_.set_secure(SEC_REQUIRED);
3466 tdf1_.set_secure(SEC_ENABLED);
3467
Steve Anton6fe1fba2018-12-11 10:15:23 -08003468 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003469 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003470 std::unique_ptr<SessionDescription> answer =
3471 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003472 EXPECT_TRUE(answer.get() == NULL);
3473}
3474
3475// Test that we accept a DTLS offer without SDES and create an appropriate
3476// answer.
3477TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3478 f1_.set_secure(SEC_DISABLED);
3479 f2_.set_secure(SEC_ENABLED);
3480 tdf1_.set_secure(SEC_ENABLED);
3481 tdf2_.set_secure(SEC_ENABLED);
3482 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003483 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3484 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3485 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003486
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003487 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003488 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003489 ASSERT_TRUE(offer.get() != NULL);
3490
3491 const AudioContentDescription* audio_offer =
3492 GetFirstAudioContentDescription(offer.get());
3493 ASSERT_TRUE(audio_offer->cryptos().empty());
3494 const VideoContentDescription* video_offer =
3495 GetFirstVideoContentDescription(offer.get());
3496 ASSERT_TRUE(video_offer->cryptos().empty());
3497 const DataContentDescription* data_offer =
3498 GetFirstDataContentDescription(offer.get());
3499 ASSERT_TRUE(data_offer->cryptos().empty());
3500
3501 const cricket::TransportDescription* audio_offer_trans_desc =
3502 offer->GetTransportDescriptionByName("audio");
3503 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3504 const cricket::TransportDescription* video_offer_trans_desc =
3505 offer->GetTransportDescriptionByName("video");
3506 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3507 const cricket::TransportDescription* data_offer_trans_desc =
3508 offer->GetTransportDescriptionByName("data");
3509 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3510
3511 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003512 std::unique_ptr<SessionDescription> answer =
3513 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003514 ASSERT_TRUE(answer.get() != NULL);
3515
3516 const cricket::TransportDescription* audio_answer_trans_desc =
3517 answer->GetTransportDescriptionByName("audio");
3518 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3519 const cricket::TransportDescription* video_answer_trans_desc =
3520 answer->GetTransportDescriptionByName("video");
3521 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3522 const cricket::TransportDescription* data_answer_trans_desc =
3523 answer->GetTransportDescriptionByName("data");
3524 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3525}
3526
3527// Verifies if vad_enabled option is set to false, CN codecs are not present in
3528// offer or answer.
3529TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3530 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003531 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003532 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003533 ASSERT_TRUE(offer.get() != NULL);
3534 const ContentInfo* audio_content = offer->GetContentByName("audio");
3535 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3536
3537 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003538 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003539 ASSERT_TRUE(offer.get() != NULL);
3540 audio_content = offer->GetContentByName("audio");
3541 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003542 std::unique_ptr<SessionDescription> answer =
3543 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003544 ASSERT_TRUE(answer.get() != NULL);
3545 audio_content = answer->GetContentByName("audio");
3546 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3547}
deadbeef44f08192015-12-15 16:20:09 -08003548
zhihuang1c378ed2017-08-17 14:10:50 -07003549// Test that the generated MIDs match the existing offer.
3550TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003551 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003552 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3553 RtpTransceiverDirection::kRecvOnly, kActive,
3554 &opts);
3555 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3556 RtpTransceiverDirection::kRecvOnly, kActive,
3557 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003558 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003559 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3560 RtpTransceiverDirection::kSendRecv, kActive,
3561 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003562 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003563 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003564 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003565 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003566
deadbeef44f08192015-12-15 16:20:09 -08003567 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3568 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3569 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3570 ASSERT_TRUE(audio_content != nullptr);
3571 ASSERT_TRUE(video_content != nullptr);
3572 ASSERT_TRUE(data_content != nullptr);
3573 EXPECT_EQ("audio_modified", audio_content->name);
3574 EXPECT_EQ("video_modified", video_content->name);
3575 EXPECT_EQ("data_modified", data_content->name);
3576}
zhihuangcf5b37c2016-05-05 11:44:35 -07003577
zhihuang1c378ed2017-08-17 14:10:50 -07003578// The following tests verify that the unified plan SDP is supported.
3579// Test that we can create an offer with multiple media sections of same media
3580// type.
3581TEST_F(MediaSessionDescriptionFactoryTest,
3582 CreateOfferWithMultipleAVMediaSections) {
3583 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003584 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3585 RtpTransceiverDirection::kSendRecv, kActive,
3586 &opts);
3587 AttachSenderToMediaDescriptionOptions(
3588 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003589
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003590 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3591 RtpTransceiverDirection::kSendRecv, kActive,
3592 &opts);
3593 AttachSenderToMediaDescriptionOptions(
3594 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003595
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003596 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3597 RtpTransceiverDirection::kSendRecv, kActive,
3598 &opts);
3599 AttachSenderToMediaDescriptionOptions(
3600 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003601
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003602 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3603 RtpTransceiverDirection::kSendRecv, kActive,
3604 &opts);
3605 AttachSenderToMediaDescriptionOptions(
3606 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003607 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003608 ASSERT_TRUE(offer);
3609
3610 ASSERT_EQ(4u, offer->contents().size());
3611 EXPECT_FALSE(offer->contents()[0].rejected);
3612 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003613 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003614 ASSERT_EQ(1u, acd->streams().size());
3615 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003616 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003617
3618 EXPECT_FALSE(offer->contents()[1].rejected);
3619 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003620 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003621 ASSERT_EQ(1u, vcd->streams().size());
3622 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003623 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003624
3625 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003626 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003627 ASSERT_EQ(1u, acd->streams().size());
3628 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003629 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003630
3631 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003632 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003633 ASSERT_EQ(1u, vcd->streams().size());
3634 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003635 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003636}
3637
3638// Test that we can create an answer with multiple media sections of same media
3639// type.
3640TEST_F(MediaSessionDescriptionFactoryTest,
3641 CreateAnswerWithMultipleAVMediaSections) {
3642 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003643 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3644 RtpTransceiverDirection::kSendRecv, kActive,
3645 &opts);
3646 AttachSenderToMediaDescriptionOptions(
3647 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003648
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003649 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3650 RtpTransceiverDirection::kSendRecv, kActive,
3651 &opts);
3652 AttachSenderToMediaDescriptionOptions(
3653 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003654
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003655 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3656 RtpTransceiverDirection::kSendRecv, kActive,
3657 &opts);
3658 AttachSenderToMediaDescriptionOptions(
3659 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003660
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003661 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3662 RtpTransceiverDirection::kSendRecv, kActive,
3663 &opts);
3664 AttachSenderToMediaDescriptionOptions(
3665 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003666
Steve Anton6fe1fba2018-12-11 10:15:23 -08003667 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003668 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003669 std::unique_ptr<SessionDescription> answer =
3670 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003671
3672 ASSERT_EQ(4u, answer->contents().size());
3673 EXPECT_FALSE(answer->contents()[0].rejected);
3674 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003675 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003676 ASSERT_EQ(1u, acd->streams().size());
3677 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003678 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003679
3680 EXPECT_FALSE(answer->contents()[1].rejected);
3681 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003682 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003683 ASSERT_EQ(1u, vcd->streams().size());
3684 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003685 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003686
3687 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003688 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003689 ASSERT_EQ(1u, acd->streams().size());
3690 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003691 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003692
3693 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003694 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003695 ASSERT_EQ(1u, vcd->streams().size());
3696 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003697 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003698}
3699
3700// Test that the media section will be rejected in offer if the corresponding
3701// MediaDescriptionOptions is stopped by the offerer.
3702TEST_F(MediaSessionDescriptionFactoryTest,
3703 CreateOfferWithMediaSectionStoppedByOfferer) {
3704 // Create an offer with two audio sections and one of them is stopped.
3705 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003706 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3707 RtpTransceiverDirection::kSendRecv, kActive,
3708 &offer_opts);
3709 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3710 RtpTransceiverDirection::kInactive, kStopped,
3711 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003712 std::unique_ptr<SessionDescription> offer =
3713 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003714 ASSERT_TRUE(offer);
3715 ASSERT_EQ(2u, offer->contents().size());
3716 EXPECT_FALSE(offer->contents()[0].rejected);
3717 EXPECT_TRUE(offer->contents()[1].rejected);
3718}
3719
3720// Test that the media section will be rejected in answer if the corresponding
3721// MediaDescriptionOptions is stopped by the offerer.
3722TEST_F(MediaSessionDescriptionFactoryTest,
3723 CreateAnswerWithMediaSectionStoppedByOfferer) {
3724 // Create an offer with two audio sections and one of them is stopped.
3725 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003726 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3727 RtpTransceiverDirection::kSendRecv, kActive,
3728 &offer_opts);
3729 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3730 RtpTransceiverDirection::kInactive, kStopped,
3731 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003732 std::unique_ptr<SessionDescription> offer =
3733 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003734 ASSERT_TRUE(offer);
3735 ASSERT_EQ(2u, offer->contents().size());
3736 EXPECT_FALSE(offer->contents()[0].rejected);
3737 EXPECT_TRUE(offer->contents()[1].rejected);
3738
3739 // Create an answer based on the offer.
3740 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003741 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3742 RtpTransceiverDirection::kSendRecv, kActive,
3743 &answer_opts);
3744 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3745 RtpTransceiverDirection::kSendRecv, kActive,
3746 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003747 std::unique_ptr<SessionDescription> answer =
3748 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003749 ASSERT_EQ(2u, answer->contents().size());
3750 EXPECT_FALSE(answer->contents()[0].rejected);
3751 EXPECT_TRUE(answer->contents()[1].rejected);
3752}
3753
3754// Test that the media section will be rejected in answer if the corresponding
3755// MediaDescriptionOptions is stopped by the answerer.
3756TEST_F(MediaSessionDescriptionFactoryTest,
3757 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3758 // Create an offer with two audio sections.
3759 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003760 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3761 RtpTransceiverDirection::kSendRecv, kActive,
3762 &offer_opts);
3763 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3764 RtpTransceiverDirection::kSendRecv, kActive,
3765 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003766 std::unique_ptr<SessionDescription> offer =
3767 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003768 ASSERT_TRUE(offer);
3769 ASSERT_EQ(2u, offer->contents().size());
3770 ASSERT_FALSE(offer->contents()[0].rejected);
3771 ASSERT_FALSE(offer->contents()[1].rejected);
3772
3773 // The answerer rejects one of the audio sections.
3774 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003775 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3776 RtpTransceiverDirection::kSendRecv, kActive,
3777 &answer_opts);
3778 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3779 RtpTransceiverDirection::kInactive, kStopped,
3780 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003781 std::unique_ptr<SessionDescription> answer =
3782 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003783 ASSERT_EQ(2u, answer->contents().size());
3784 EXPECT_FALSE(answer->contents()[0].rejected);
3785 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003786
3787 // The TransportInfo of the rejected m= section is expected to be added in the
3788 // answer.
3789 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003790}
3791
3792// Test the generated media sections has the same order of the
3793// corresponding MediaDescriptionOptions.
3794TEST_F(MediaSessionDescriptionFactoryTest,
3795 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3796 MediaSessionOptions opts;
3797 // This tests put video section first because normally audio comes first by
3798 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003799 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3800 RtpTransceiverDirection::kSendRecv, kActive,
3801 &opts);
3802 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3803 RtpTransceiverDirection::kSendRecv, kActive,
3804 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003805 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003806
3807 ASSERT_TRUE(offer);
3808 ASSERT_EQ(2u, offer->contents().size());
3809 EXPECT_EQ("video", offer->contents()[0].name);
3810 EXPECT_EQ("audio", offer->contents()[1].name);
3811}
3812
3813// Test that different media sections using the same codec have same payload
3814// type.
3815TEST_F(MediaSessionDescriptionFactoryTest,
3816 PayloadTypesSharedByMediaSectionsOfSameType) {
3817 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003818 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3819 RtpTransceiverDirection::kSendRecv, kActive,
3820 &opts);
3821 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3822 RtpTransceiverDirection::kSendRecv, kActive,
3823 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003824 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003825 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003826 ASSERT_TRUE(offer);
3827 ASSERT_EQ(2u, offer->contents().size());
3828 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003829 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003830 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003831 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003832 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3833 ASSERT_EQ(2u, vcd1->codecs().size());
3834 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3835 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3836 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3837 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3838
3839 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003840 std::unique_ptr<SessionDescription> answer =
3841 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003842 ASSERT_TRUE(answer);
3843 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003844 vcd1 = answer->contents()[0].media_description()->as_video();
3845 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003846 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3847 ASSERT_EQ(1u, vcd1->codecs().size());
3848 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3849 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3850}
3851
3852// Test that the codec preference order per media section is respected in
3853// subsequent offer.
3854TEST_F(MediaSessionDescriptionFactoryTest,
3855 CreateOfferRespectsCodecPreferenceOrder) {
3856 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003857 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3858 RtpTransceiverDirection::kSendRecv, kActive,
3859 &opts);
3860 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3861 RtpTransceiverDirection::kSendRecv, kActive,
3862 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003863 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003864 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003865 ASSERT_TRUE(offer);
3866 ASSERT_EQ(2u, offer->contents().size());
3867 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003868 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003869 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003870 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003871 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3872 EXPECT_EQ(video_codecs, vcd1->codecs());
3873 EXPECT_EQ(video_codecs, vcd2->codecs());
3874
3875 // Change the codec preference of the first video section and create a
3876 // follow-up offer.
3877 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3878 vcd1->set_codecs(video_codecs_reverse);
3879 std::unique_ptr<SessionDescription> updated_offer(
3880 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003881 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3882 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003883 // The video codec preference order should be respected.
3884 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3885 EXPECT_EQ(video_codecs, vcd2->codecs());
3886}
3887
3888// Test that the codec preference order per media section is respected in
3889// the answer.
3890TEST_F(MediaSessionDescriptionFactoryTest,
3891 CreateAnswerRespectsCodecPreferenceOrder) {
3892 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003893 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3894 RtpTransceiverDirection::kSendRecv, kActive,
3895 &opts);
3896 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3897 RtpTransceiverDirection::kSendRecv, kActive,
3898 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003899 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003900 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003901 ASSERT_TRUE(offer);
3902 ASSERT_EQ(2u, offer->contents().size());
3903 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003904 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003905 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003906 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003907 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3908 EXPECT_EQ(video_codecs, vcd1->codecs());
3909 EXPECT_EQ(video_codecs, vcd2->codecs());
3910
3911 // Change the codec preference of the first video section and create an
3912 // answer.
3913 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3914 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003915 std::unique_ptr<SessionDescription> answer =
3916 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003917 vcd1 = answer->contents()[0].media_description()->as_video();
3918 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003919 // The video codec preference order should be respected.
3920 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3921 EXPECT_EQ(video_codecs, vcd2->codecs());
3922}
3923
Zhi Huang6f367472017-11-22 13:20:02 -08003924// Test that when creating an answer, the codecs use local parameters instead of
3925// the remote ones.
3926TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3927 const std::string audio_param_name = "audio_param";
3928 const std::string audio_value1 = "audio_v1";
3929 const std::string audio_value2 = "audio_v2";
3930 const std::string video_param_name = "video_param";
3931 const std::string video_value1 = "video_v1";
3932 const std::string video_value2 = "video_v2";
3933
3934 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3935 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3936 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3937 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3938
3939 // Set the parameters for codecs.
3940 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3941 video_codecs1[0].SetParam(video_param_name, video_value1);
3942 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3943 video_codecs2[0].SetParam(video_param_name, video_value2);
3944
3945 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3946 f1_.set_video_codecs(video_codecs1);
3947 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3948 f2_.set_video_codecs(video_codecs2);
3949
3950 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003951 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3952 RtpTransceiverDirection::kSendRecv, kActive,
3953 &opts);
3954 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3955 RtpTransceiverDirection::kSendRecv, kActive,
3956 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003957
Steve Anton6fe1fba2018-12-11 10:15:23 -08003958 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003959 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003960 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3961 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003962 std::string value;
3963 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3964 EXPECT_EQ(audio_value1, value);
3965 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3966 EXPECT_EQ(video_value1, value);
3967
Steve Anton6fe1fba2018-12-11 10:15:23 -08003968 std::unique_ptr<SessionDescription> answer =
3969 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003970 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003971 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3972 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003973 // Use the parameters from the local codecs.
3974 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3975 EXPECT_EQ(audio_value2, value);
3976 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3977 EXPECT_EQ(video_value2, value);
3978}
3979
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003980// Test that matching packetization-mode is part of the criteria for matching
3981// H264 codecs (in addition to profile-level-id). Previously, this was not the
3982// case, so the first H264 codec with the same profile-level-id would match and
3983// the payload type in the answer would be incorrect.
3984// This is a regression test for bugs.webrtc.org/8808
3985TEST_F(MediaSessionDescriptionFactoryTest,
3986 H264MatchCriteriaIncludesPacketizationMode) {
3987 // Create two H264 codecs with the same profile level ID and different
3988 // packetization modes.
3989 VideoCodec h264_pm0(96, "H264");
3990 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3991 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3992 VideoCodec h264_pm1(97, "H264");
3993 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3994 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3995
3996 // Offerer will send both codecs, answerer should choose the one with matching
3997 // packetization mode (and not the first one it sees).
3998 f1_.set_video_codecs({h264_pm0, h264_pm1});
3999 f2_.set_video_codecs({h264_pm1});
4000
4001 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004002 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4003 RtpTransceiverDirection::kSendRecv, kActive,
4004 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004005
Steve Anton6fe1fba2018-12-11 10:15:23 -08004006 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004007 ASSERT_TRUE(offer);
4008
Steve Anton6fe1fba2018-12-11 10:15:23 -08004009 std::unique_ptr<SessionDescription> answer =
4010 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004011 ASSERT_TRUE(answer);
4012
4013 // Answer should have one negotiated codec with packetization-mode=1 using the
4014 // offered payload type.
4015 ASSERT_EQ(1u, answer->contents().size());
4016 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4017 ASSERT_EQ(1u, answer_vcd->codecs().size());
4018 auto answer_codec = answer_vcd->codecs()[0];
4019 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4020}
4021
zhihuangcf5b37c2016-05-05 11:44:35 -07004022class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4023 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004024 MediaProtocolTest()
4025 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004026 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4027 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004028 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
4029 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004030 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4031 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004032 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
4033 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
4034 f1_.set_secure(SEC_ENABLED);
4035 f2_.set_secure(SEC_ENABLED);
4036 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004037 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004038 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004039 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004040 tdf1_.set_secure(SEC_ENABLED);
4041 tdf2_.set_secure(SEC_ENABLED);
4042 }
4043
4044 protected:
4045 MediaSessionDescriptionFactory f1_;
4046 MediaSessionDescriptionFactory f2_;
4047 TransportDescriptionFactory tdf1_;
4048 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004049 UniqueRandomIdGenerator ssrc_generator1;
4050 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004051};
4052
4053TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4054 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004055 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004056 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004057 ASSERT_TRUE(offer.get() != nullptr);
4058 // Set the protocol for all the contents.
4059 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004060 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004061 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004062 std::unique_ptr<SessionDescription> answer =
4063 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004064 const ContentInfo* ac = answer->GetContentByName("audio");
4065 const ContentInfo* vc = answer->GetContentByName("video");
4066 ASSERT_TRUE(ac != nullptr);
4067 ASSERT_TRUE(vc != nullptr);
4068 EXPECT_FALSE(ac->rejected); // the offer is accepted
4069 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004070 const AudioContentDescription* acd = ac->media_description()->as_audio();
4071 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004072 EXPECT_EQ(GetParam(), acd->protocol());
4073 EXPECT_EQ(GetParam(), vcd->protocol());
4074}
4075
4076INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
4077 MediaProtocolTest,
4078 ::testing::ValuesIn(kMediaProtocols));
4079INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
4080 MediaProtocolTest,
4081 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004082
4083TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4084 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004085 UniqueRandomIdGenerator ssrc_generator;
4086 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004087 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4088 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4089
4090 // The merged list of codecs should contain any send codecs that are also
4091 // nominally in the recieve codecs list. Payload types should be picked from
4092 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4093 // (set to 1). This equals what happens when the send codecs are used in an
4094 // offer and the receive codecs are used in the following answer.
4095 const std::vector<AudioCodec> sendrecv_codecs =
4096 MAKE_VECTOR(kAudioCodecsAnswer);
4097 const std::vector<AudioCodec> no_codecs;
4098
4099 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4100 << "Please don't change shared test data!";
4101 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4102 << "Please don't change shared test data!";
4103 // Alter iLBC send codec to have zero channels, to test that that is handled
4104 // properly.
4105 send_codecs[1].channels = 0;
4106
4107 // Alther iLBC receive codec to be lowercase, to test that case conversions
4108 // are handled properly.
4109 recv_codecs[2].name = "ilbc";
4110
4111 // Test proper merge
4112 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004113 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4114 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4115 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004116
4117 // Test empty send codecs list
4118 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004119 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4120 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4121 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004122
4123 // Test empty recv codecs list
4124 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004125 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4126 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4127 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004128
4129 // Test all empty codec lists
4130 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004131 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4132 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4133 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004134}
4135
Amit Hilbuch77938e62018-12-21 09:23:38 -08004136// Checks that the RID extensions are added to the video RTP header extensions.
4137// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4138// not very well defined, as calling set() and immediately get() will yield
4139// an object that is not semantically equivalent to the set object.
4140TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4141 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004142 UniqueRandomIdGenerator ssrc_generator;
4143 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004144 sf.set_is_unified_plan(true);
4145 cricket::RtpHeaderExtensions extensions;
4146 sf.set_video_rtp_header_extensions(extensions);
4147 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4148 // Check to see that RID extensions were added to the extension list
4149 EXPECT_GE(result.size(), 2u);
4150 auto rid_extension = std::find_if(
4151 result.begin(), result.end(), [](const RtpExtension& extension) {
4152 return extension.uri == webrtc::RtpExtension::kRidUri;
4153 });
4154 EXPECT_NE(rid_extension, extensions.end());
4155 auto repaired_rid_extension = std::find_if(
4156 result.begin(), result.end(), [](const RtpExtension& extension) {
4157 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
4158 });
4159 EXPECT_NE(repaired_rid_extension, extensions.end());
4160}
4161
4162// Checks that the RID extensions are added to the audio RTP header extensions.
4163// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4164// not very well defined, as calling set() and immediately get() will yield
4165// an object that is not semantically equivalent to the set object.
4166TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4167 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004168 UniqueRandomIdGenerator ssrc_generator;
4169 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004170 sf.set_is_unified_plan(true);
4171 cricket::RtpHeaderExtensions extensions;
4172 sf.set_audio_rtp_header_extensions(extensions);
4173 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4174 // Check to see that RID extensions were added to the extension list
4175 EXPECT_GE(result.size(), 2u);
4176 auto rid_extension = std::find_if(
4177 result.begin(), result.end(), [](const RtpExtension& extension) {
4178 return extension.uri == webrtc::RtpExtension::kRidUri;
4179 });
4180 EXPECT_NE(rid_extension, extensions.end());
4181 auto repaired_rid_extension = std::find_if(
4182 result.begin(), result.end(), [](const RtpExtension& extension) {
4183 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
4184 });
4185 EXPECT_NE(repaired_rid_extension, extensions.end());
4186}
4187
ossu075af922016-06-14 03:29:38 -07004188namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004189// Compare the two vectors of codecs ignoring the payload type.
4190template <class Codec>
4191bool CodecsMatch(const std::vector<Codec>& codecs1,
4192 const std::vector<Codec>& codecs2) {
4193 if (codecs1.size() != codecs2.size()) {
4194 return false;
4195 }
4196
4197 for (size_t i = 0; i < codecs1.size(); ++i) {
4198 if (!codecs1[i].Matches(codecs2[i])) {
4199 return false;
4200 }
4201 }
4202 return true;
4203}
4204
Steve Anton4e70a722017-11-28 14:57:10 -08004205void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004206 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004207 UniqueRandomIdGenerator ssrc_generator;
4208 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004209 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4210 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4211 const std::vector<AudioCodec> sendrecv_codecs =
4212 MAKE_VECTOR(kAudioCodecsAnswer);
4213 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004214
4215 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004216 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4217 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004218
Steve Anton4e70a722017-11-28 14:57:10 -08004219 if (direction == RtpTransceiverDirection::kSendRecv ||
4220 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004221 AttachSenderToMediaDescriptionOptions(
4222 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004223 }
ossu075af922016-06-14 03:29:38 -07004224
Steve Anton6fe1fba2018-12-11 10:15:23 -08004225 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004226 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004227 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004228
4229 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004230 // that the codecs put in are right. This happens when we neither want to
4231 // send nor receive audio. The checks are still in place if at some point
4232 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004233 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004234 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004235 // sendrecv and inactive should both present lists as if the channel was
4236 // to be used for sending and receiving. Inactive essentially means it
4237 // might eventually be used anything, but we don't know more at this
4238 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004239 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004240 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004241 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004242 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004243 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004244 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004245 }
4246 }
4247}
4248
4249static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004250 AudioCodec(0, "codec0", 16000, -1, 1),
4251 AudioCodec(1, "codec1", 8000, 13300, 1),
4252 AudioCodec(2, "codec2", 8000, 64000, 1),
4253 AudioCodec(3, "codec3", 8000, 64000, 1),
4254 AudioCodec(4, "codec4", 8000, 0, 2),
4255 AudioCodec(5, "codec5", 32000, 0, 1),
4256 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004257
zhihuang1c378ed2017-08-17 14:10:50 -07004258/* The codecs groups below are chosen as per the matrix below. The objective
4259 * is to have different sets of codecs in the inputs, to get unique sets of
4260 * codecs after negotiation, depending on offer and answer communication
4261 * directions. One-way directions in the offer should either result in the
4262 * opposite direction in the answer, or an inactive answer. Regardless, the
4263 * choice of codecs should be as if the answer contained the opposite
4264 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004265 *
4266 * | Offer | Answer | Result
4267 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4268 * 0 | x - - | - x - | x - - - -
4269 * 1 | x x x | - x - | x - - x -
4270 * 2 | - x - | x - - | - x - - -
4271 * 3 | x x x | x - - | - x x - -
4272 * 4 | - x - | x x x | - x - - -
4273 * 5 | x - - | x x x | x - - - -
4274 * 6 | x x x | x x x | x x x x x
4275 */
4276// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004277static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4278static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004279// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4280// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004281static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4282static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004283// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004284static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4285static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4286static const int kResultSendrecv_SendCodecs[] = {3, 6};
4287static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4288static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004289
4290template <typename T, int IDXS>
4291std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4292 std::vector<T> out;
4293 out.reserve(IDXS);
4294 for (int idx : indices)
4295 out.push_back(array[idx]);
4296
4297 return out;
4298}
4299
Steve Anton4e70a722017-11-28 14:57:10 -08004300void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4301 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004302 bool add_legacy_stream) {
4303 TransportDescriptionFactory offer_tdf;
4304 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004305 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4306 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4307 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004308 offer_factory.set_audio_codecs(
4309 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4310 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4311 answer_factory.set_audio_codecs(
4312 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4313 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4314
ossu075af922016-06-14 03:29:38 -07004315 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004316 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4317 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004318
Steve Anton4e70a722017-11-28 14:57:10 -08004319 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004320 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4321 kAudioTrack1, {kMediaStream1}, 1,
4322 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004323 }
4324
Steve Anton6fe1fba2018-12-11 10:15:23 -08004325 std::unique_ptr<SessionDescription> offer =
4326 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004327 ASSERT_TRUE(offer.get() != NULL);
4328
4329 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004330 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4331 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004332
Steve Anton4e70a722017-11-28 14:57:10 -08004333 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004334 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4335 kAudioTrack1, {kMediaStream1}, 1,
4336 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004337 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004338 std::unique_ptr<SessionDescription> answer =
4339 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004340 const ContentInfo* ac = answer->GetContentByName("audio");
4341
zhihuang1c378ed2017-08-17 14:10:50 -07004342 // If the factory didn't add any audio content to the answer, we cannot
4343 // check that the codecs put in are right. This happens when we neither want
4344 // to send nor receive audio. The checks are still in place if at some point
4345 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004346 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004347 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4348 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004349
ossu075af922016-06-14 03:29:38 -07004350 std::vector<AudioCodec> target_codecs;
4351 // For offers with sendrecv or inactive, we should never reply with more
4352 // codecs than offered, with these codec sets.
4353 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004354 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004355 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4356 kResultSendrecv_SendrecvCodecs);
4357 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004358 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004359 target_codecs =
4360 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004361 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004362 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004363 target_codecs =
4364 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004365 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004366 case RtpTransceiverDirection::kSendRecv:
4367 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004368 target_codecs =
4369 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004370 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004371 target_codecs =
4372 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004373 } else {
4374 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4375 kResultSendrecv_SendrecvCodecs);
4376 }
4377 break;
4378 }
4379
zhihuang1c378ed2017-08-17 14:10:50 -07004380 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004381 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004382 bool first = true;
4383 os << "{";
4384 for (const auto& c : codecs) {
4385 os << (first ? " " : ", ") << c.id;
4386 first = false;
4387 }
4388 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004389 return os.Release();
ossu075af922016-06-14 03:29:38 -07004390 };
4391
4392 EXPECT_TRUE(acd->codecs() == target_codecs)
4393 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004394 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4395 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004396 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004397 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4398 << "; got: "
4399 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004400 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004401 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004402 << "Only inactive offers are allowed to not generate any audio "
4403 "content";
ossu075af922016-06-14 03:29:38 -07004404 }
4405}
brandtr03d5fb12016-11-22 03:37:59 -08004406
4407} // namespace
ossu075af922016-06-14 03:29:38 -07004408
4409class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004410 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004411
4412TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004413 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004414}
4415
4416INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
4417 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004418 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4419 RtpTransceiverDirection::kRecvOnly,
4420 RtpTransceiverDirection::kSendRecv,
4421 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004422
4423class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004424 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4425 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004426 bool>> {};
ossu075af922016-06-14 03:29:38 -07004427
4428TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004429 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4430 ::testing::get<1>(GetParam()),
4431 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004432}
4433
zhihuang1c378ed2017-08-17 14:10:50 -07004434INSTANTIATE_TEST_CASE_P(
4435 MediaSessionDescriptionFactoryTest,
4436 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004437 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4438 RtpTransceiverDirection::kRecvOnly,
4439 RtpTransceiverDirection::kSendRecv,
4440 RtpTransceiverDirection::kInactive),
4441 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4442 RtpTransceiverDirection::kRecvOnly,
4443 RtpTransceiverDirection::kSendRecv,
4444 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004445 ::testing::Bool()));