blob: b0a85bb8d8969dedb20355c3d765865216858a1f [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
kwiberg31022942016-03-11 14:18:21 -080011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <string>
13#include <vector>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "media/base/codec.h"
16#include "media/base/testutils.h"
17#include "p2p/base/p2pconstants.h"
18#include "p2p/base/transportdescription.h"
19#include "p2p/base/transportinfo.h"
20#include "pc/mediasession.h"
Steve Anton1d03a752017-11-27 14:30:09 -080021#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "pc/srtpfilter.h"
23#include "rtc_base/checks.h"
24#include "rtc_base/fakesslidentity.h"
25#include "rtc_base/gunit.h"
26#include "rtc_base/messagedigest.h"
27#include "rtc_base/ssladapter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000028
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000030 ASSERT_EQ(s, cd->cryptos().size()); \
31 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032
33typedef std::vector<cricket::Candidate> Candidates;
34
35using cricket::MediaContentDescription;
36using cricket::MediaSessionDescriptionFactory;
zhihuang1c378ed2017-08-17 14:10:50 -070037using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038using cricket::MediaSessionOptions;
39using cricket::MediaType;
40using cricket::SessionDescription;
41using cricket::SsrcGroup;
42using cricket::StreamParams;
43using cricket::StreamParamsVec;
44using cricket::TransportDescription;
45using cricket::TransportDescriptionFactory;
46using cricket::TransportInfo;
47using cricket::ContentInfo;
48using cricket::CryptoParamsVec;
49using cricket::AudioContentDescription;
50using cricket::VideoContentDescription;
51using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080052using cricket::GetFirstAudioContent;
53using cricket::GetFirstVideoContent;
54using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055using cricket::GetFirstAudioContentDescription;
56using cricket::GetFirstVideoContentDescription;
57using cricket::GetFirstDataContentDescription;
58using cricket::kAutoBandwidth;
59using cricket::AudioCodec;
60using cricket::VideoCodec;
61using cricket::DataCodec;
62using cricket::NS_JINGLE_RTP;
63using cricket::MEDIA_TYPE_AUDIO;
64using cricket::MEDIA_TYPE_VIDEO;
65using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066using cricket::SEC_DISABLED;
67using cricket::SEC_ENABLED;
68using cricket::SEC_REQUIRED;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070069using rtc::CS_AES_CM_128_HMAC_SHA1_32;
70using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070071using rtc::CS_AEAD_AES_128_GCM;
72using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070073using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080074using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075
76static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070077 AudioCodec(103, "ISAC", 16000, -1, 1),
78 AudioCodec(102, "iLBC", 8000, 13300, 1),
79 AudioCodec(0, "PCMU", 8000, 64000, 1),
80 AudioCodec(8, "PCMA", 8000, 64000, 1),
81 AudioCodec(117, "red", 8000, 0, 1),
82 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083
84static const AudioCodec kAudioCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070085 AudioCodec(126, "speex", 16000, 22000, 1),
86 AudioCodec(0, "PCMU", 8000, 64000, 1),
87 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088};
89
90static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070091 AudioCodec(102, "iLBC", 8000, 13300, 1),
92 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093};
94
perkj26752742016-10-24 01:21:16 -070095static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
96 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097
zhihuang1c378ed2017-08-17 14:10:50 -070098static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
99 VideoCodec(96, "H264-SVC")};
100
perkj26752742016-10-24 01:21:16 -0700101static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
102 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
perkj26752742016-10-24 01:21:16 -0700104static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105
deadbeef67cf2c12016-04-13 10:07:16 -0700106static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
107 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108
deadbeef67cf2c12016-04-13 10:07:16 -0700109static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
110 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
deadbeef67cf2c12016-04-13 10:07:16 -0700112static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
113 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114
isheriff6f8d6862016-05-26 11:24:55 -0700115static const RtpExtension kAudioRtpExtension1[] = {
116 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
117 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118};
119
jbauch5869f502017-06-29 12:31:36 -0700120static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
121 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
122 RtpExtension("http://google.com/testing/audio_something", 10),
123 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
124};
125
isheriff6f8d6862016-05-26 11:24:55 -0700126static const RtpExtension kAudioRtpExtension2[] = {
127 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
128 RtpExtension("http://google.com/testing/audio_something_else", 8),
129 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130};
131
isheriff6f8d6862016-05-26 11:24:55 -0700132static const RtpExtension kAudioRtpExtension3[] = {
133 RtpExtension("http://google.com/testing/audio_something", 2),
134 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700135};
136
jbauch5869f502017-06-29 12:31:36 -0700137static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
138 RtpExtension("http://google.com/testing/audio_something", 2),
139 // Use RTP extension that supports encryption.
140 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
141};
142
143static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
144 RtpExtension("http://google.com/testing/audio_something", 2),
145 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
146 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
147};
148
isheriff6f8d6862016-05-26 11:24:55 -0700149static const RtpExtension kAudioRtpExtensionAnswer[] = {
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151};
152
jbauch5869f502017-06-29 12:31:36 -0700153static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
154 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
155};
156
isheriff6f8d6862016-05-26 11:24:55 -0700157static const RtpExtension kVideoRtpExtension1[] = {
158 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
159 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160};
161
jbauch5869f502017-06-29 12:31:36 -0700162static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
163 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
164 RtpExtension("http://google.com/testing/video_something", 13),
165 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
166};
167
isheriff6f8d6862016-05-26 11:24:55 -0700168static const RtpExtension kVideoRtpExtension2[] = {
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
170 RtpExtension("http://google.com/testing/video_something_else", 14),
171 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000172};
173
isheriff6f8d6862016-05-26 11:24:55 -0700174static const RtpExtension kVideoRtpExtension3[] = {
175 RtpExtension("http://google.com/testing/video_something", 4),
176 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700177};
178
jbauch5869f502017-06-29 12:31:36 -0700179static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 // Use RTP extension that supports encryption.
182 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
183};
184
isheriff6f8d6862016-05-26 11:24:55 -0700185static const RtpExtension kVideoRtpExtensionAnswer[] = {
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187};
188
jbauch5869f502017-06-29 12:31:36 -0700189static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
191};
192
Peter Boström0c4e06b2015-10-07 12:23:21 +0200193static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
194static const uint32_t kSimSsrc[] = {10, 20, 30};
195static const uint32_t kFec1Ssrc[] = {10, 11};
196static const uint32_t kFec2Ssrc[] = {20, 21};
197static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198
199static const char kMediaStream1[] = "stream_1";
200static const char kMediaStream2[] = "stream_2";
201static const char kVideoTrack1[] = "video_1";
202static const char kVideoTrack2[] = "video_2";
203static const char kAudioTrack1[] = "audio_1";
204static const char kAudioTrack2[] = "audio_2";
205static const char kAudioTrack3[] = "audio_3";
206static const char kDataTrack1[] = "data_1";
207static const char kDataTrack2[] = "data_2";
208static const char kDataTrack3[] = "data_3";
209
zhihuangcf5b37c2016-05-05 11:44:35 -0700210static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
211 "RTP/SAVPF"};
212static const char* kMediaProtocolsDtls[] = {
213 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
214 "UDP/TLS/RTP/SAVP"};
215
zhihuang1c378ed2017-08-17 14:10:50 -0700216// These constants are used to make the code using "AddMediaSection" more
217// readable.
218static constexpr bool kStopped = true;
219static constexpr bool kActive = false;
220
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000221static bool IsMediaContentOfType(const ContentInfo* content,
222 MediaType media_type) {
223 const MediaContentDescription* mdesc =
224 static_cast<const MediaContentDescription*>(content->description);
225 return mdesc && mdesc->type() == media_type;
226}
227
Steve Anton4e70a722017-11-28 14:57:10 -0800228static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000229 cricket::MediaContentDescription* desc =
230 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
231 return desc->direction();
232}
233
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000234static void AddRtxCodec(const VideoCodec& rtx_codec,
235 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800236 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000237 codecs->push_back(rtx_codec);
238}
239
240template <class T>
241static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
242 std::vector<std::string> codec_names;
243 for (const auto& codec : codecs) {
244 codec_names.push_back(codec.name);
245 }
246 return codec_names;
247}
248
zhihuang1c378ed2017-08-17 14:10:50 -0700249// This is used for test only. MIDs are not the identification of the
250// MediaDescriptionOptions since some end points may not support MID and the SDP
251// may not contain 'mid'.
252std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
253 const std::string& mid,
254 MediaSessionOptions* opts) {
255 return std::find_if(
256 opts->media_description_options.begin(),
257 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700258 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
259}
260
261std::vector<MediaDescriptionOptions>::const_iterator
262FindFirstMediaDescriptionByMid(const std::string& mid,
263 const MediaSessionOptions& opts) {
264 return std::find_if(
265 opts.media_description_options.begin(),
266 opts.media_description_options.end(),
267 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700268}
269
270// Add a media section to the |session_options|.
271static void AddMediaSection(MediaType type,
272 const std::string& mid,
Steve Anton4e70a722017-11-28 14:57:10 -0800273 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700274 bool stopped,
275 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800276 opts->media_description_options.push_back(
277 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700278}
279
Steve Anton4e70a722017-11-28 14:57:10 -0800280static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700281 MediaSessionOptions* opts) {
282 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
283 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
284}
285
286static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800287 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700288 MediaSessionOptions* opts) {
289 opts->data_channel_type = dct;
290 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
291}
292
Steve Anton8ffb9c32017-08-31 15:45:38 -0700293static void AttachSenderToMediaSection(
294 const std::string& mid,
295 MediaType type,
296 const std::string& track_id,
297 const std::vector<std::string>& stream_ids,
298 int num_sim_layer,
299 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700300 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
301 switch (type) {
302 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700303 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700304 break;
305 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700306 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700307 break;
308 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700309 RTC_CHECK(stream_ids.size() == 1U);
310 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700311 break;
312 default:
313 RTC_NOTREACHED();
314 }
315}
316
317static void DetachSenderFromMediaSection(const std::string& mid,
318 const std::string& track_id,
319 MediaSessionOptions* session_options) {
320 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
321 auto sender_it = it->sender_options.begin();
322 for (; sender_it != it->sender_options.end(); ++sender_it) {
323 if (sender_it->track_id == track_id) {
324 it->sender_options.erase(sender_it);
325 return;
326 }
327 }
328 RTC_NOTREACHED();
329}
330
331// Helper function used to create a default MediaSessionOptions for Plan B SDP.
332// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
333static MediaSessionOptions CreatePlanBMediaSessionOptions() {
334 MediaSessionOptions session_options;
Steve Anton4e70a722017-11-28 14:57:10 -0800335 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
336 kActive, &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700337 return session_options;
338}
339
340// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
341// was designed for Plan B SDP, where only one audio "m=" section and one video
342// "m=" section could be generated, and ordering couldn't be controlled. Many of
343// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000344class MediaSessionDescriptionFactoryTest : public testing::Test {
345 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700346 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700347 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
348 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
350 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700351 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
352 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000353 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
354 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200355 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700356 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200357 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700358 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000359 }
360
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000361 // Create a video StreamParamsVec object with:
362 // - one video stream with 3 simulcast streams and FEC,
363 StreamParamsVec CreateComplexVideoStreamParamsVec() {
364 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
365 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
366 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
367 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
368
369 std::vector<SsrcGroup> ssrc_groups;
370 ssrc_groups.push_back(sim_group);
371 ssrc_groups.push_back(fec_group1);
372 ssrc_groups.push_back(fec_group2);
373 ssrc_groups.push_back(fec_group3);
374
375 StreamParams simulcast_params;
376 simulcast_params.id = kVideoTrack1;
377 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
378 simulcast_params.ssrc_groups = ssrc_groups;
379 simulcast_params.cname = "Video_SIM_FEC";
380 simulcast_params.sync_label = kMediaStream1;
381
382 StreamParamsVec video_streams;
383 video_streams.push_back(simulcast_params);
384
385 return video_streams;
386 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387
388 bool CompareCryptoParams(const CryptoParamsVec& c1,
389 const CryptoParamsVec& c2) {
390 if (c1.size() != c2.size())
391 return false;
392 for (size_t i = 0; i < c1.size(); ++i)
393 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
394 c1[i].key_params != c2[i].key_params ||
395 c1[i].session_params != c2[i].session_params)
396 return false;
397 return true;
398 }
399
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700400 // Returns true if the transport info contains "renomination" as an
401 // ICE option.
402 bool GetIceRenomination(const TransportInfo* transport_info) {
403 const std::vector<std::string>& ice_options =
404 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700405 auto iter =
406 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700407 return iter != ice_options.end();
408 }
409
zhihuang1c378ed2017-08-17 14:10:50 -0700410 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700411 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000412 bool has_current_desc) {
413 const std::string current_audio_ufrag = "current_audio_ufrag";
414 const std::string current_audio_pwd = "current_audio_pwd";
415 const std::string current_video_ufrag = "current_video_ufrag";
416 const std::string current_video_pwd = "current_video_pwd";
417 const std::string current_data_ufrag = "current_data_ufrag";
418 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800419 std::unique_ptr<SessionDescription> current_desc;
420 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 if (has_current_desc) {
422 current_desc.reset(new SessionDescription());
423 EXPECT_TRUE(current_desc->AddTransportInfo(
424 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700425 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000426 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 EXPECT_TRUE(current_desc->AddTransportInfo(
428 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700429 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000430 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431 EXPECT_TRUE(current_desc->AddTransportInfo(
432 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700433 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000434 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 }
436 if (offer) {
437 desc.reset(f1_.CreateOffer(options, current_desc.get()));
438 } else {
kwiberg31022942016-03-11 14:18:21 -0800439 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440 offer.reset(f1_.CreateOffer(options, NULL));
441 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
442 }
443 ASSERT_TRUE(desc.get() != NULL);
444 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000445 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 EXPECT_TRUE(ti_audio != NULL);
447 if (has_current_desc) {
448 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
449 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
450 } else {
451 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
452 ti_audio->description.ice_ufrag.size());
453 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
454 ti_audio->description.ice_pwd.size());
455 }
zhihuang1c378ed2017-08-17 14:10:50 -0700456 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700457 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700458 EXPECT_EQ(
459 media_desc_options_it->transport_options.enable_ice_renomination,
460 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461
462 } else {
463 EXPECT_TRUE(ti_audio == NULL);
464 }
465 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000466 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000467 EXPECT_TRUE(ti_video != NULL);
468 if (options.bundle_enabled) {
469 EXPECT_EQ(ti_audio->description.ice_ufrag,
470 ti_video->description.ice_ufrag);
471 EXPECT_EQ(ti_audio->description.ice_pwd,
472 ti_video->description.ice_pwd);
473 } else {
474 if (has_current_desc) {
475 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
476 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
477 } else {
478 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
479 ti_video->description.ice_ufrag.size());
480 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
481 ti_video->description.ice_pwd.size());
482 }
483 }
zhihuang1c378ed2017-08-17 14:10:50 -0700484 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700485 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700486 EXPECT_EQ(
487 media_desc_options_it->transport_options.enable_ice_renomination,
488 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000489 } else {
490 EXPECT_TRUE(ti_video == NULL);
491 }
492 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
493 if (options.has_data()) {
494 EXPECT_TRUE(ti_data != NULL);
495 if (options.bundle_enabled) {
496 EXPECT_EQ(ti_audio->description.ice_ufrag,
497 ti_data->description.ice_ufrag);
498 EXPECT_EQ(ti_audio->description.ice_pwd,
499 ti_data->description.ice_pwd);
500 } else {
501 if (has_current_desc) {
502 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
503 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
504 } else {
505 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
506 ti_data->description.ice_ufrag.size());
507 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
508 ti_data->description.ice_pwd.size());
509 }
510 }
zhihuang1c378ed2017-08-17 14:10:50 -0700511 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700512 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700513 EXPECT_EQ(
514 media_desc_options_it->transport_options.enable_ice_renomination,
515 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700516
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 } else {
518 EXPECT_TRUE(ti_video == NULL);
519 }
520 }
521
522 void TestCryptoWithBundle(bool offer) {
523 f1_.set_secure(SEC_ENABLED);
524 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800525 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
526 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
527 &options);
kwiberg31022942016-03-11 14:18:21 -0800528 std::unique_ptr<SessionDescription> ref_desc;
529 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 if (offer) {
531 options.bundle_enabled = false;
532 ref_desc.reset(f1_.CreateOffer(options, NULL));
533 options.bundle_enabled = true;
534 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
535 } else {
536 options.bundle_enabled = true;
537 ref_desc.reset(f1_.CreateOffer(options, NULL));
538 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
539 }
540 ASSERT_TRUE(desc.get() != NULL);
541 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000542 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 desc.get()->GetContentDescriptionByName("audio"));
544 ASSERT_TRUE(audio_media_desc != NULL);
545 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000546 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 desc.get()->GetContentDescriptionByName("video"));
548 ASSERT_TRUE(video_media_desc != NULL);
549 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
550 video_media_desc->cryptos()));
551 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
552 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
553 audio_media_desc->cryptos()[0].cipher_suite);
554
555 // Verify the selected crypto is one from the reference audio
556 // media content.
557 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000558 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 ref_desc.get()->GetContentDescriptionByName("audio"));
560 bool found = false;
561 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
562 if (ref_audio_media_desc->cryptos()[i].Matches(
563 audio_media_desc->cryptos()[0])) {
564 found = true;
565 break;
566 }
567 }
568 EXPECT_TRUE(found);
569 }
570
571 // This test that the audio and video media direction is set to
572 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700573 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800575 RtpTransceiverDirection direction_in_offer,
576 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700577 MediaSessionOptions offer_opts;
578 AddAudioVideoSections(direction_in_offer, &offer_opts);
579
580 std::unique_ptr<SessionDescription> offer(
581 f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700583 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700585 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587
zhihuang1c378ed2017-08-17 14:10:50 -0700588 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800589 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -0800590 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700591 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 const AudioContentDescription* acd_answer =
593 GetFirstAudioContentDescription(answer.get());
594 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
595 const VideoContentDescription* vcd_answer =
596 GetFirstVideoContentDescription(answer.get());
597 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
598 }
599
600 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
601 const cricket::ContentDescription* description = content->description;
nissec8ee8822017-01-18 07:20:55 -0800602 RTC_CHECK(description != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000604 static_cast<const cricket::AudioContentDescription*>(description);
nissec8ee8822017-01-18 07:20:55 -0800605 RTC_CHECK(audio_content_desc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
607 if (audio_content_desc->codecs()[i].name == "CN")
608 return false;
609 }
610 return true;
611 }
612
jbauchcb560652016-08-04 05:20:32 -0700613 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
614 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800615 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
jbauchcb560652016-08-04 05:20:32 -0700616 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700617
jbauchcb560652016-08-04 05:20:32 -0700618 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800619 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
jbauchcb560652016-08-04 05:20:32 -0700620 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700621
jbauchcb560652016-08-04 05:20:32 -0700622 f1_.set_secure(SEC_ENABLED);
623 f2_.set_secure(SEC_ENABLED);
624 std::unique_ptr<SessionDescription> offer(
625 f1_.CreateOffer(offer_opts, NULL));
626 ASSERT_TRUE(offer.get() != NULL);
627 std::unique_ptr<SessionDescription> answer(
628 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
629 const ContentInfo* ac = answer->GetContentByName("audio");
630 const ContentInfo* vc = answer->GetContentByName("video");
631 ASSERT_TRUE(ac != NULL);
632 ASSERT_TRUE(vc != NULL);
633 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
634 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
635 const AudioContentDescription* acd =
636 static_cast<const AudioContentDescription*>(ac->description);
637 const VideoContentDescription* vcd =
638 static_cast<const VideoContentDescription*>(vc->description);
639 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
640 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
641 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700642 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700643 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
644 if (gcm_offer && gcm_answer) {
645 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
646 } else {
647 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
648 }
649 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
650 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700651 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700652 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
653 if (gcm_offer && gcm_answer) {
654 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
655 } else {
656 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
657 }
658 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
659 }
660
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 protected:
662 MediaSessionDescriptionFactory f1_;
663 MediaSessionDescriptionFactory f2_;
664 TransportDescriptionFactory tdf1_;
665 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666};
667
668// Create a typical audio offer, and ensure it matches what we expect.
669TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
670 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800671 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700672 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 ASSERT_TRUE(offer.get() != NULL);
674 const ContentInfo* ac = offer->GetContentByName("audio");
675 const ContentInfo* vc = offer->GetContentByName("video");
676 ASSERT_TRUE(ac != NULL);
677 ASSERT_TRUE(vc == NULL);
678 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
679 const AudioContentDescription* acd =
680 static_cast<const AudioContentDescription*>(ac->description);
681 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700682 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700683 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
685 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
686 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
687 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
688}
689
690// Create a typical video offer, and ensure it matches what we expect.
691TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
692 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800693 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800695 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696 ASSERT_TRUE(offer.get() != NULL);
697 const ContentInfo* ac = offer->GetContentByName("audio");
698 const ContentInfo* vc = offer->GetContentByName("video");
699 ASSERT_TRUE(ac != NULL);
700 ASSERT_TRUE(vc != NULL);
701 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
702 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
703 const AudioContentDescription* acd =
704 static_cast<const AudioContentDescription*>(ac->description);
705 const VideoContentDescription* vcd =
706 static_cast<const VideoContentDescription*>(vc->description);
707 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700708 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700709 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
711 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
712 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
713 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
714 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
715 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700716 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000717 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
718 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
719 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
720 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
721}
722
723// Test creating an offer with bundle where the Codecs have the same dynamic
724// RTP playlod type. The test verifies that the offer don't contain the
725// duplicate RTP payload types.
726TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
727 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700728 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
730 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
731 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
732
733 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800734 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
735 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800737 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 const VideoContentDescription* vcd =
739 GetFirstVideoContentDescription(offer.get());
740 const AudioContentDescription* acd =
741 GetFirstAudioContentDescription(offer.get());
742 const DataContentDescription* dcd =
743 GetFirstDataContentDescription(offer.get());
744 ASSERT_TRUE(NULL != vcd);
745 ASSERT_TRUE(NULL != acd);
746 ASSERT_TRUE(NULL != dcd);
747 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
748 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
749 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
750 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
751 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
752 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
753}
754
zhihuang1c378ed2017-08-17 14:10:50 -0700755// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000756// after an audio only session has been negotiated.
757TEST_F(MediaSessionDescriptionFactoryTest,
758 TestCreateUpdatedVideoOfferWithBundle) {
759 f1_.set_secure(SEC_ENABLED);
760 f2_.set_secure(SEC_ENABLED);
761 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800762 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
763 kActive, &opts);
764 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kInactive,
765 kStopped, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766 opts.data_channel_type = cricket::DCT_NONE;
767 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800768 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
769 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 f2_.CreateAnswer(offer.get(), opts, NULL));
771
772 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800773 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
774 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
775 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000776 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800777 std::unique_ptr<SessionDescription> updated_offer(
778 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000779
780 const AudioContentDescription* acd =
781 GetFirstAudioContentDescription(updated_offer.get());
782 const VideoContentDescription* vcd =
783 GetFirstVideoContentDescription(updated_offer.get());
784 const DataContentDescription* dcd =
785 GetFirstDataContentDescription(updated_offer.get());
786 EXPECT_TRUE(NULL != vcd);
787 EXPECT_TRUE(NULL != acd);
788 EXPECT_TRUE(NULL != dcd);
789
790 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
791 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
792 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
793 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
794 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
795 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
796}
deadbeef44f08192015-12-15 16:20:09 -0800797
wu@webrtc.org78187522013-10-07 23:32:02 +0000798// Create a RTP data offer, and ensure it matches what we expect.
799TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800801 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
802 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000803 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800804 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 ASSERT_TRUE(offer.get() != NULL);
806 const ContentInfo* ac = offer->GetContentByName("audio");
807 const ContentInfo* dc = offer->GetContentByName("data");
808 ASSERT_TRUE(ac != NULL);
809 ASSERT_TRUE(dc != NULL);
810 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
811 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
812 const AudioContentDescription* acd =
813 static_cast<const AudioContentDescription*>(ac->description);
814 const DataContentDescription* dcd =
815 static_cast<const DataContentDescription*>(dc->description);
816 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700817 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700818 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
820 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
821 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
822 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
823 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
824 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700825 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826 EXPECT_EQ(cricket::kDataMaxBandwidth,
827 dcd->bandwidth()); // default bandwidth (auto)
828 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
829 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
830 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
831}
832
wu@webrtc.org78187522013-10-07 23:32:02 +0000833// Create an SCTP data offer with bundle without error.
834TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
835 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000836 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800837 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000838 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800839 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000840 EXPECT_TRUE(offer.get() != NULL);
841 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
842}
843
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000844// Test creating an sctp data channel from an already generated offer.
845TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
846 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000847 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800848 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000849 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800850 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000851 ASSERT_TRUE(offer1.get() != NULL);
852 const ContentInfo* data = offer1->GetContentByName("data");
853 ASSERT_TRUE(data != NULL);
854 const MediaContentDescription* mdesc =
855 static_cast<const MediaContentDescription*>(data->description);
856 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
857
858 // Now set data_channel_type to 'none' (default) and make sure that the
859 // datachannel type that gets generated from the previous offer, is of the
860 // same type.
861 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800862 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000863 f1_.CreateOffer(opts, offer1.get()));
864 data = offer2->GetContentByName("data");
865 ASSERT_TRUE(data != NULL);
866 mdesc = static_cast<const MediaContentDescription*>(data->description);
867 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
868}
869
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870// Create an audio, video offer without legacy StreamParams.
871TEST_F(MediaSessionDescriptionFactoryTest,
872 TestCreateOfferWithoutLegacyStreams) {
873 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800874 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -0800875 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876 ASSERT_TRUE(offer.get() != NULL);
877 const ContentInfo* ac = offer->GetContentByName("audio");
878 const ContentInfo* vc = offer->GetContentByName("video");
879 ASSERT_TRUE(ac != NULL);
880 ASSERT_TRUE(vc != NULL);
881 const AudioContentDescription* acd =
882 static_cast<const AudioContentDescription*>(ac->description);
883 const VideoContentDescription* vcd =
884 static_cast<const VideoContentDescription*>(vc->description);
885
886 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
887 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
888}
889
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000890// Creates an audio+video sendonly offer.
891TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700892 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800893 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700894 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700895 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700896 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700897 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000898
zhihuang1c378ed2017-08-17 14:10:50 -0700899 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000900 ASSERT_TRUE(offer.get() != NULL);
901 EXPECT_EQ(2u, offer->contents().size());
902 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
903 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
904
Steve Anton4e70a722017-11-28 14:57:10 -0800905 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
906 GetMediaDirection(&offer->contents()[0]));
907 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
908 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000909}
910
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000911// Verifies that the order of the media contents in the current
912// SessionDescription is preserved in the new SessionDescription.
913TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
914 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800915 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000916
kwiberg31022942016-03-11 14:18:21 -0800917 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000918 ASSERT_TRUE(offer1.get() != NULL);
919 EXPECT_EQ(1u, offer1->contents().size());
920 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
921
Steve Anton4e70a722017-11-28 14:57:10 -0800922 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
923 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800924 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000925 f1_.CreateOffer(opts, offer1.get()));
926 ASSERT_TRUE(offer2.get() != NULL);
927 EXPECT_EQ(2u, offer2->contents().size());
928 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
929 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
930
Steve Anton4e70a722017-11-28 14:57:10 -0800931 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
932 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800933 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000934 f1_.CreateOffer(opts, offer2.get()));
935 ASSERT_TRUE(offer3.get() != NULL);
936 EXPECT_EQ(3u, offer3->contents().size());
937 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
938 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
939 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000940}
941
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000942// Create a typical audio answer, and ensure it matches what we expect.
943TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
944 f1_.set_secure(SEC_ENABLED);
945 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800946 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700947 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800949 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700950 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951 const ContentInfo* ac = answer->GetContentByName("audio");
952 const ContentInfo* vc = answer->GetContentByName("video");
953 ASSERT_TRUE(ac != NULL);
954 ASSERT_TRUE(vc == NULL);
955 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
956 const AudioContentDescription* acd =
957 static_cast<const AudioContentDescription*>(ac->description);
958 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
959 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700960 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000961 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
962 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
963 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
964 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
965}
966
jbauchcb560652016-08-04 05:20:32 -0700967// Create a typical audio answer with GCM ciphers enabled, and ensure it
968// matches what we expect.
969TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
970 f1_.set_secure(SEC_ENABLED);
971 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700972 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
973 opts.crypto_options.enable_gcm_crypto_suites = true;
974 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700975 ASSERT_TRUE(offer.get() != NULL);
976 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700977 f2_.CreateAnswer(offer.get(), opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700978 const ContentInfo* ac = answer->GetContentByName("audio");
979 const ContentInfo* vc = answer->GetContentByName("video");
980 ASSERT_TRUE(ac != NULL);
981 ASSERT_TRUE(vc == NULL);
982 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
983 const AudioContentDescription* acd =
984 static_cast<const AudioContentDescription*>(ac->description);
985 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
986 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700987 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700988 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
989 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
990 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
991 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
992}
993
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000994// Create a typical video answer, and ensure it matches what we expect.
995TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
996 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800997 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 f1_.set_secure(SEC_ENABLED);
999 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001000 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001001 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001002 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 f2_.CreateAnswer(offer.get(), opts, NULL));
1004 const ContentInfo* ac = answer->GetContentByName("audio");
1005 const ContentInfo* vc = answer->GetContentByName("video");
1006 ASSERT_TRUE(ac != NULL);
1007 ASSERT_TRUE(vc != NULL);
1008 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1009 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1010 const AudioContentDescription* acd =
1011 static_cast<const AudioContentDescription*>(ac->description);
1012 const VideoContentDescription* vcd =
1013 static_cast<const VideoContentDescription*>(vc->description);
1014 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1015 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1016 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001017 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1019 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1020 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1021 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001022 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001023 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
1024 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1025 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
1026}
1027
jbauchcb560652016-08-04 05:20:32 -07001028// Create a typical video answer with GCM ciphers enabled, and ensure it
1029// matches what we expect.
1030TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1031 TestVideoGcmCipher(true, true);
1032}
1033
1034// Create a typical video answer with GCM ciphers enabled for the offer only,
1035// and ensure it matches what we expect.
1036TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1037 TestVideoGcmCipher(true, false);
1038}
1039
1040// Create a typical video answer with GCM ciphers enabled for the answer only,
1041// and ensure it matches what we expect.
1042TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1043 TestVideoGcmCipher(false, true);
1044}
1045
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001046TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001047 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001048 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 f1_.set_secure(SEC_ENABLED);
1050 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001051 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001052 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001053 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001054 f2_.CreateAnswer(offer.get(), opts, NULL));
1055 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001056 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001057 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001058 ASSERT_TRUE(dc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -08001060 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001061 const AudioContentDescription* acd =
1062 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -08001063 const DataContentDescription* dcd =
1064 static_cast<const DataContentDescription*>(dc->description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001065 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1066 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1067 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001068 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001069 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1070 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
zstein4b2e0822017-02-17 19:48:38 -08001071 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1072 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001073 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001074 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1075 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1076 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001077}
1078
jbauchcb560652016-08-04 05:20:32 -07001079TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001080 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001081 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
jbauchcb560652016-08-04 05:20:32 -07001082 opts.crypto_options.enable_gcm_crypto_suites = true;
1083 f1_.set_secure(SEC_ENABLED);
1084 f2_.set_secure(SEC_ENABLED);
1085 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1086 ASSERT_TRUE(offer.get() != NULL);
1087 std::unique_ptr<SessionDescription> answer(
1088 f2_.CreateAnswer(offer.get(), opts, NULL));
1089 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001090 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001091 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001092 ASSERT_TRUE(dc != NULL);
jbauchcb560652016-08-04 05:20:32 -07001093 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -08001094 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
jbauchcb560652016-08-04 05:20:32 -07001095 const AudioContentDescription* acd =
1096 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -08001097 const DataContentDescription* dcd =
1098 static_cast<const DataContentDescription*>(dc->description);
jbauchcb560652016-08-04 05:20:32 -07001099 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1100 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1101 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001102 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001103 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1104 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
zstein4b2e0822017-02-17 19:48:38 -08001105 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1106 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001107 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001108 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1109 ASSERT_CRYPTO(dcd, 1U, CS_AEAD_AES_256_GCM);
1110 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
1111}
1112
1113// The use_sctpmap flag should be set in a DataContentDescription by default.
1114// The answer's use_sctpmap flag should match the offer's.
1115TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1116 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001117 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001118 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1119 ASSERT_TRUE(offer.get() != NULL);
1120 ContentInfo* dc_offer = offer->GetContentByName("data");
1121 ASSERT_TRUE(dc_offer != NULL);
1122 DataContentDescription* dcd_offer =
1123 static_cast<DataContentDescription*>(dc_offer->description);
1124 EXPECT_TRUE(dcd_offer->use_sctpmap());
1125
1126 std::unique_ptr<SessionDescription> answer(
1127 f2_.CreateAnswer(offer.get(), opts, NULL));
1128 const ContentInfo* dc_answer = answer->GetContentByName("data");
1129 ASSERT_TRUE(dc_answer != NULL);
1130 const DataContentDescription* dcd_answer =
1131 static_cast<const DataContentDescription*>(dc_answer->description);
1132 EXPECT_TRUE(dcd_answer->use_sctpmap());
1133}
1134
1135// The answer's use_sctpmap flag should match the offer's.
1136TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1137 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001138 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001139 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1140 ASSERT_TRUE(offer.get() != NULL);
1141 ContentInfo* dc_offer = offer->GetContentByName("data");
1142 ASSERT_TRUE(dc_offer != NULL);
1143 DataContentDescription* dcd_offer =
1144 static_cast<DataContentDescription*>(dc_offer->description);
1145 dcd_offer->set_use_sctpmap(false);
1146
1147 std::unique_ptr<SessionDescription> answer(
1148 f2_.CreateAnswer(offer.get(), opts, NULL));
1149 const ContentInfo* dc_answer = answer->GetContentByName("data");
1150 ASSERT_TRUE(dc_answer != NULL);
1151 const DataContentDescription* dcd_answer =
1152 static_cast<const DataContentDescription*>(dc_answer->description);
1153 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001154}
1155
deadbeef8b7e9ad2017-05-25 09:38:55 -07001156// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1157// and "TCP/DTLS/SCTP" offers.
1158TEST_F(MediaSessionDescriptionFactoryTest,
1159 TestCreateDataAnswerToDifferentOfferedProtos) {
1160 // Need to enable DTLS offer/answer generation (disabled by default in this
1161 // test).
1162 f1_.set_secure(SEC_ENABLED);
1163 f2_.set_secure(SEC_ENABLED);
1164 tdf1_.set_secure(SEC_ENABLED);
1165 tdf2_.set_secure(SEC_ENABLED);
1166
1167 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001168 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001169 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1170 ASSERT_TRUE(offer.get() != nullptr);
1171 ContentInfo* dc_offer = offer->GetContentByName("data");
1172 ASSERT_TRUE(dc_offer != nullptr);
1173 DataContentDescription* dcd_offer =
1174 static_cast<DataContentDescription*>(dc_offer->description);
1175
1176 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1177 "TCP/DTLS/SCTP"};
1178 for (const std::string& proto : protos) {
1179 dcd_offer->set_protocol(proto);
1180 std::unique_ptr<SessionDescription> answer(
1181 f2_.CreateAnswer(offer.get(), opts, nullptr));
1182 const ContentInfo* dc_answer = answer->GetContentByName("data");
1183 ASSERT_TRUE(dc_answer != nullptr);
1184 const DataContentDescription* dcd_answer =
1185 static_cast<const DataContentDescription*>(dc_answer->description);
1186 EXPECT_FALSE(dc_answer->rejected);
1187 EXPECT_EQ(proto, dcd_answer->protocol());
1188 }
1189}
1190
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001191// Verifies that the order of the media contents in the offer is preserved in
1192// the answer.
1193TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1194 MediaSessionOptions opts;
1195
1196 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001197 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001198 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001199 ASSERT_TRUE(offer1.get() != NULL);
1200
1201 // Appends audio to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001202 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1203 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001204 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001205 f1_.CreateOffer(opts, offer1.get()));
1206 ASSERT_TRUE(offer2.get() != NULL);
1207
1208 // Appends video to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001209 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1210 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001211 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001212 f1_.CreateOffer(opts, offer2.get()));
1213 ASSERT_TRUE(offer3.get() != NULL);
1214
kwiberg31022942016-03-11 14:18:21 -08001215 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001216 f2_.CreateAnswer(offer3.get(), opts, NULL));
1217 ASSERT_TRUE(answer.get() != NULL);
1218 EXPECT_EQ(3u, answer->contents().size());
1219 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1220 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1221 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1222}
1223
ossu075af922016-06-14 03:29:38 -07001224// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1225// answerer settings.
1226
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227// This test that the media direction is set to send/receive in an answer if
1228// the offer is send receive.
1229TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001230 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1231 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001232}
1233
1234// This test that the media direction is set to receive only in an answer if
1235// the offer is send only.
1236TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001237 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1238 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239}
1240
1241// This test that the media direction is set to send only in an answer if
1242// the offer is recv only.
1243TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001244 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1245 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246}
1247
1248// This test that the media direction is set to inactive in an answer if
1249// the offer is inactive.
1250TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001251 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1252 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253}
1254
1255// Test that a data content with an unknown protocol is rejected in an answer.
1256TEST_F(MediaSessionDescriptionFactoryTest,
1257 CreateDataAnswerToOfferWithUnknownProtocol) {
1258 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001259 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 f1_.set_secure(SEC_ENABLED);
1261 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001262 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001263 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 ASSERT_TRUE(dc_offer != NULL);
1265 DataContentDescription* dcd_offer =
1266 static_cast<DataContentDescription*>(dc_offer->description);
1267 ASSERT_TRUE(dcd_offer != NULL);
1268 std::string protocol = "a weird unknown protocol";
1269 dcd_offer->set_protocol(protocol);
1270
kwiberg31022942016-03-11 14:18:21 -08001271 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272 f2_.CreateAnswer(offer.get(), opts, NULL));
1273
1274 const ContentInfo* dc_answer = answer->GetContentByName("data");
1275 ASSERT_TRUE(dc_answer != NULL);
1276 EXPECT_TRUE(dc_answer->rejected);
1277 const DataContentDescription* dcd_answer =
1278 static_cast<const DataContentDescription*>(dc_answer->description);
1279 ASSERT_TRUE(dcd_answer != NULL);
1280 EXPECT_EQ(protocol, dcd_answer->protocol());
1281}
1282
1283// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1284TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001285 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286 f1_.set_secure(SEC_DISABLED);
1287 f2_.set_secure(SEC_DISABLED);
1288 tdf1_.set_secure(SEC_DISABLED);
1289 tdf2_.set_secure(SEC_DISABLED);
1290
kwiberg31022942016-03-11 14:18:21 -08001291 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292 const AudioContentDescription* offer_acd =
1293 GetFirstAudioContentDescription(offer.get());
1294 ASSERT_TRUE(offer_acd != NULL);
1295 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1296
kwiberg31022942016-03-11 14:18:21 -08001297 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 f2_.CreateAnswer(offer.get(), opts, NULL));
1299
1300 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1301 ASSERT_TRUE(ac_answer != NULL);
1302 EXPECT_FALSE(ac_answer->rejected);
1303
1304 const AudioContentDescription* answer_acd =
1305 GetFirstAudioContentDescription(answer.get());
1306 ASSERT_TRUE(answer_acd != NULL);
1307 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1308}
1309
1310// Create a video offer and answer and ensure the RTP header extensions
1311// matches what we expect.
1312TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1313 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001314 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001315 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1316 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1317 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1318 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1319
kwiberg31022942016-03-11 14:18:21 -08001320 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001321 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001322 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323 f2_.CreateAnswer(offer.get(), opts, NULL));
1324
1325 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1326 GetFirstAudioContentDescription(
1327 offer.get())->rtp_header_extensions());
1328 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1329 GetFirstVideoContentDescription(
1330 offer.get())->rtp_header_extensions());
1331 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1332 GetFirstAudioContentDescription(
1333 answer.get())->rtp_header_extensions());
1334 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1335 GetFirstVideoContentDescription(
1336 answer.get())->rtp_header_extensions());
1337}
1338
jbauch5869f502017-06-29 12:31:36 -07001339TEST_F(MediaSessionDescriptionFactoryTest,
1340 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
1341 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001342 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001343
1344 f1_.set_enable_encrypted_rtp_header_extensions(true);
1345 f2_.set_enable_encrypted_rtp_header_extensions(true);
1346
1347 f1_.set_audio_rtp_header_extensions(
1348 MAKE_VECTOR(kAudioRtpExtension1));
1349 f1_.set_video_rtp_header_extensions(
1350 MAKE_VECTOR(kVideoRtpExtension1));
1351 f2_.set_audio_rtp_header_extensions(
1352 MAKE_VECTOR(kAudioRtpExtension2));
1353 f2_.set_video_rtp_header_extensions(
1354 MAKE_VECTOR(kVideoRtpExtension2));
1355
1356 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1357 ASSERT_TRUE(offer.get() != NULL);
1358 std::unique_ptr<SessionDescription> answer(
1359 f2_.CreateAnswer(offer.get(), opts, NULL));
1360
1361 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1362 GetFirstAudioContentDescription(
1363 offer.get())->rtp_header_extensions());
1364 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1365 GetFirstVideoContentDescription(
1366 offer.get())->rtp_header_extensions());
1367 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1368 GetFirstAudioContentDescription(
1369 answer.get())->rtp_header_extensions());
1370 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1371 GetFirstVideoContentDescription(
1372 answer.get())->rtp_header_extensions());
1373}
1374
1375TEST_F(MediaSessionDescriptionFactoryTest,
1376 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
1377 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001378 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001379
1380 f1_.set_enable_encrypted_rtp_header_extensions(true);
1381
1382 f1_.set_audio_rtp_header_extensions(
1383 MAKE_VECTOR(kAudioRtpExtension1));
1384 f1_.set_video_rtp_header_extensions(
1385 MAKE_VECTOR(kVideoRtpExtension1));
1386 f2_.set_audio_rtp_header_extensions(
1387 MAKE_VECTOR(kAudioRtpExtension2));
1388 f2_.set_video_rtp_header_extensions(
1389 MAKE_VECTOR(kVideoRtpExtension2));
1390
1391 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1392 ASSERT_TRUE(offer.get() != NULL);
1393 std::unique_ptr<SessionDescription> answer(
1394 f2_.CreateAnswer(offer.get(), opts, NULL));
1395
1396 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1397 GetFirstAudioContentDescription(
1398 offer.get())->rtp_header_extensions());
1399 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1400 GetFirstVideoContentDescription(
1401 offer.get())->rtp_header_extensions());
1402 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1403 GetFirstAudioContentDescription(
1404 answer.get())->rtp_header_extensions());
1405 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1406 GetFirstVideoContentDescription(
1407 answer.get())->rtp_header_extensions());
1408}
1409
1410TEST_F(MediaSessionDescriptionFactoryTest,
1411 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
1412 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001413 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001414
1415 f2_.set_enable_encrypted_rtp_header_extensions(true);
1416
1417 f1_.set_audio_rtp_header_extensions(
1418 MAKE_VECTOR(kAudioRtpExtension1));
1419 f1_.set_video_rtp_header_extensions(
1420 MAKE_VECTOR(kVideoRtpExtension1));
1421 f2_.set_audio_rtp_header_extensions(
1422 MAKE_VECTOR(kAudioRtpExtension2));
1423 f2_.set_video_rtp_header_extensions(
1424 MAKE_VECTOR(kVideoRtpExtension2));
1425
1426 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1427 ASSERT_TRUE(offer.get() != NULL);
1428 std::unique_ptr<SessionDescription> answer(
1429 f2_.CreateAnswer(offer.get(), opts, NULL));
1430
1431 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1432 GetFirstAudioContentDescription(
1433 offer.get())->rtp_header_extensions());
1434 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1435 GetFirstVideoContentDescription(
1436 offer.get())->rtp_header_extensions());
1437 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1438 GetFirstAudioContentDescription(
1439 answer.get())->rtp_header_extensions());
1440 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1441 GetFirstVideoContentDescription(
1442 answer.get())->rtp_header_extensions());
1443}
1444
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001445// Create an audio, video, data answer without legacy StreamParams.
1446TEST_F(MediaSessionDescriptionFactoryTest,
1447 TestCreateAnswerWithoutLegacyStreams) {
1448 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001449 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1450 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001451 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001452 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001453 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001454 f2_.CreateAnswer(offer.get(), opts, NULL));
1455 const ContentInfo* ac = answer->GetContentByName("audio");
1456 const ContentInfo* vc = answer->GetContentByName("video");
1457 const ContentInfo* dc = answer->GetContentByName("data");
1458 ASSERT_TRUE(ac != NULL);
1459 ASSERT_TRUE(vc != NULL);
1460 const AudioContentDescription* acd =
1461 static_cast<const AudioContentDescription*>(ac->description);
1462 const VideoContentDescription* vcd =
1463 static_cast<const VideoContentDescription*>(vc->description);
1464 const DataContentDescription* dcd =
1465 static_cast<const DataContentDescription*>(dc->description);
1466
1467 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1468 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1469 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1470}
1471
1472TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1473 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001474 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1475 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001476 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001477 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001478 ASSERT_TRUE(offer.get() != NULL);
1479 const ContentInfo* ac = offer->GetContentByName("audio");
1480 const ContentInfo* vc = offer->GetContentByName("video");
1481 const ContentInfo* dc = offer->GetContentByName("data");
1482 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1483 static_cast<const AudioContentDescription*>(ac->description));
1484 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1485 static_cast<const VideoContentDescription*>(vc->description));
1486 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1487 static_cast<const DataContentDescription*>(dc->description));
1488
1489 EXPECT_FALSE(acd->partial()); // default is false.
1490 acd->set_partial(true);
1491 EXPECT_TRUE(acd->partial());
1492 acd->set_partial(false);
1493 EXPECT_FALSE(acd->partial());
1494
1495 EXPECT_FALSE(vcd->partial()); // default is false.
1496 vcd->set_partial(true);
1497 EXPECT_TRUE(vcd->partial());
1498 vcd->set_partial(false);
1499 EXPECT_FALSE(vcd->partial());
1500
1501 EXPECT_FALSE(dcd->partial()); // default is false.
1502 dcd->set_partial(true);
1503 EXPECT_TRUE(dcd->partial());
1504 dcd->set_partial(false);
1505 EXPECT_FALSE(dcd->partial());
1506}
1507
1508// Create a typical video answer, and ensure it matches what we expect.
1509TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1510 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001511 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1512 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1513 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001514
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001515 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001516 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1517 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1518 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001519
kwiberg31022942016-03-11 14:18:21 -08001520 std::unique_ptr<SessionDescription> offer;
1521 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001522
1523 offer_opts.rtcp_mux_enabled = true;
1524 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001525 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1526 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1527 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1528 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1529 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1530 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1531 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1532 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1533 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1534 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1535 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1536 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1537 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1538 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1539
1540 offer_opts.rtcp_mux_enabled = true;
1541 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001542 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1543 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1544 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1545 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1546 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1547 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1548 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1549 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1550 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1551 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1552 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1553 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1554 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1555 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1556
1557 offer_opts.rtcp_mux_enabled = false;
1558 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001559 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1560 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1561 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1562 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1563 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1564 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1565 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1566 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1567 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1568 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1569 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1570 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1571 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1572 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1573
1574 offer_opts.rtcp_mux_enabled = false;
1575 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001576 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1577 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1578 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1579 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1580 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1581 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1582 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1583 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1584 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1585 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1586 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1587 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1588 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1589 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1590}
1591
1592// Create an audio-only answer to a video offer.
1593TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1594 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001595 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1596 kActive, &opts);
1597 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1598 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001599 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001600 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001601
1602 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001603 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001604 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605 const ContentInfo* ac = answer->GetContentByName("audio");
1606 const ContentInfo* vc = answer->GetContentByName("video");
1607 ASSERT_TRUE(ac != NULL);
1608 ASSERT_TRUE(vc != NULL);
1609 ASSERT_TRUE(vc->description != NULL);
1610 EXPECT_TRUE(vc->rejected);
1611}
1612
1613// Create an audio-only answer to an offer with data.
1614TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001615 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001616 opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001617 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1618 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001619 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001621
1622 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001623 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001624 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001625 const ContentInfo* ac = answer->GetContentByName("audio");
1626 const ContentInfo* dc = answer->GetContentByName("data");
1627 ASSERT_TRUE(ac != NULL);
1628 ASSERT_TRUE(dc != NULL);
1629 ASSERT_TRUE(dc->description != NULL);
1630 EXPECT_TRUE(dc->rejected);
1631}
1632
1633// Create an answer that rejects the contents which are rejected in the offer.
1634TEST_F(MediaSessionDescriptionFactoryTest,
1635 CreateAnswerToOfferWithRejectedMedia) {
1636 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001637 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1638 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001639 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001640 ASSERT_TRUE(offer.get() != NULL);
1641 ContentInfo* ac = offer->GetContentByName("audio");
1642 ContentInfo* vc = offer->GetContentByName("video");
1643 ContentInfo* dc = offer->GetContentByName("data");
1644 ASSERT_TRUE(ac != NULL);
1645 ASSERT_TRUE(vc != NULL);
1646 ASSERT_TRUE(dc != NULL);
1647 ac->rejected = true;
1648 vc->rejected = true;
1649 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001650 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001651 f2_.CreateAnswer(offer.get(), opts, NULL));
1652 ac = answer->GetContentByName("audio");
1653 vc = answer->GetContentByName("video");
1654 dc = answer->GetContentByName("data");
1655 ASSERT_TRUE(ac != NULL);
1656 ASSERT_TRUE(vc != NULL);
1657 ASSERT_TRUE(dc != NULL);
1658 EXPECT_TRUE(ac->rejected);
1659 EXPECT_TRUE(vc->rejected);
1660 EXPECT_TRUE(dc->rejected);
1661}
1662
1663// Create an audio and video offer with:
1664// - one video track
1665// - two audio tracks
1666// - two data tracks
1667// and ensure it matches what we expect. Also updates the initial offer by
1668// adding a new video track and replaces one of the audio tracks.
1669TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1670 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001671 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001672 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001673 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001674 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001675 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001676 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001677 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001678
Steve Anton4e70a722017-11-28 14:57:10 -08001679 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001680 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001681 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001682 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001683 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001684
1685 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001686 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001687
1688 ASSERT_TRUE(offer.get() != NULL);
1689 const ContentInfo* ac = offer->GetContentByName("audio");
1690 const ContentInfo* vc = offer->GetContentByName("video");
1691 const ContentInfo* dc = offer->GetContentByName("data");
1692 ASSERT_TRUE(ac != NULL);
1693 ASSERT_TRUE(vc != NULL);
1694 ASSERT_TRUE(dc != NULL);
1695 const AudioContentDescription* acd =
1696 static_cast<const AudioContentDescription*>(ac->description);
1697 const VideoContentDescription* vcd =
1698 static_cast<const VideoContentDescription*>(vc->description);
1699 const DataContentDescription* dcd =
1700 static_cast<const DataContentDescription*>(dc->description);
1701 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001702 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001703
1704 const StreamParamsVec& audio_streams = acd->streams();
1705 ASSERT_EQ(2U, audio_streams.size());
1706 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1707 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1708 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1709 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1710 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1711 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1712 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1713
1714 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1715 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1716 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1717
1718 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1719 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1720 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1721
1722 const StreamParamsVec& video_streams = vcd->streams();
1723 ASSERT_EQ(1U, video_streams.size());
1724 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1725 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1726 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1727 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1728
1729 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1730 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1731 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1732
1733 const StreamParamsVec& data_streams = dcd->streams();
1734 ASSERT_EQ(2U, data_streams.size());
1735 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1736 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1737 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1738 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1739 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1740 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1741 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1742
1743 EXPECT_EQ(cricket::kDataMaxBandwidth,
1744 dcd->bandwidth()); // default bandwidth (auto)
1745 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1746 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1747
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001748 // Update the offer. Add a new video track that is not synched to the
1749 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001750 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001751 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001752 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1753 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001754 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001755 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1756 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001757 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001758 std::unique_ptr<SessionDescription> updated_offer(
1759 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001760
1761 ASSERT_TRUE(updated_offer.get() != NULL);
1762 ac = updated_offer->GetContentByName("audio");
1763 vc = updated_offer->GetContentByName("video");
1764 dc = updated_offer->GetContentByName("data");
1765 ASSERT_TRUE(ac != NULL);
1766 ASSERT_TRUE(vc != NULL);
1767 ASSERT_TRUE(dc != NULL);
1768 const AudioContentDescription* updated_acd =
1769 static_cast<const AudioContentDescription*>(ac->description);
1770 const VideoContentDescription* updated_vcd =
1771 static_cast<const VideoContentDescription*>(vc->description);
1772 const DataContentDescription* updated_dcd =
1773 static_cast<const DataContentDescription*>(dc->description);
1774
1775 EXPECT_EQ(acd->type(), updated_acd->type());
1776 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1777 EXPECT_EQ(vcd->type(), updated_vcd->type());
1778 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1779 EXPECT_EQ(dcd->type(), updated_dcd->type());
1780 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1781 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1782 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1783 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1784 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1785 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1786 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1787
1788 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1789 ASSERT_EQ(2U, updated_audio_streams.size());
1790 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1791 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1792 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1793 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1794 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1795
1796 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1797 ASSERT_EQ(2U, updated_video_streams.size());
1798 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1799 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001800 // All the media streams in one PeerConnection share one RTCP CNAME.
1801 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001802
1803 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1804 ASSERT_EQ(2U, updated_data_streams.size());
1805 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1806 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1807 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1808 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1809 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001810 // The stream correctly got the CNAME from the MediaSessionOptions.
1811 // The Expected RTCP CNAME is the default one as we are using the default
1812 // MediaSessionOptions.
1813 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001814}
1815
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001816// Create an offer with simulcast video stream.
1817TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1818 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001819 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1820 kActive, &opts);
1821 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1822 kActive, &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001823 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001824 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001825 {kMediaStream1}, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001826 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001827
1828 ASSERT_TRUE(offer.get() != NULL);
1829 const ContentInfo* vc = offer->GetContentByName("video");
1830 ASSERT_TRUE(vc != NULL);
1831 const VideoContentDescription* vcd =
1832 static_cast<const VideoContentDescription*>(vc->description);
1833
1834 const StreamParamsVec& video_streams = vcd->streams();
1835 ASSERT_EQ(1U, video_streams.size());
1836 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1837 const SsrcGroup* sim_ssrc_group =
1838 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1839 ASSERT_TRUE(sim_ssrc_group != NULL);
1840 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1841}
1842
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001843// Create an audio and video answer to a standard video offer with:
1844// - one video track
1845// - two audio tracks
1846// - two data tracks
1847// and ensure it matches what we expect. Also updates the initial answer by
1848// adding a new video track and removes one of the audio tracks.
1849TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1850 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001851 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1852 kActive, &offer_opts);
1853 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1854 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001855 offer_opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001856 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1857 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001858 f1_.set_secure(SEC_ENABLED);
1859 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001860 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001861
zhihuang1c378ed2017-08-17 14:10:50 -07001862 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001863 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
1864 kActive, &answer_opts);
1865 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1866 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001867 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001868 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001869 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001870 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001871 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001872 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001873
Steve Anton4e70a722017-11-28 14:57:10 -08001874 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
1875 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001876 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001877 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001878 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001879 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001880 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001881
kwiberg31022942016-03-11 14:18:21 -08001882 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001883 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884
1885 ASSERT_TRUE(answer.get() != NULL);
1886 const ContentInfo* ac = answer->GetContentByName("audio");
1887 const ContentInfo* vc = answer->GetContentByName("video");
1888 const ContentInfo* dc = answer->GetContentByName("data");
1889 ASSERT_TRUE(ac != NULL);
1890 ASSERT_TRUE(vc != NULL);
1891 ASSERT_TRUE(dc != NULL);
1892 const AudioContentDescription* acd =
1893 static_cast<const AudioContentDescription*>(ac->description);
1894 const VideoContentDescription* vcd =
1895 static_cast<const VideoContentDescription*>(vc->description);
1896 const DataContentDescription* dcd =
1897 static_cast<const DataContentDescription*>(dc->description);
1898 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1899 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1900 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1901
1902 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1903 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1904
1905 const StreamParamsVec& audio_streams = acd->streams();
1906 ASSERT_EQ(2U, audio_streams.size());
1907 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1908 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1909 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1910 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1911 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1912 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1913 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1914
1915 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1916 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1917
1918 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1919 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1920
1921 const StreamParamsVec& video_streams = vcd->streams();
1922 ASSERT_EQ(1U, video_streams.size());
1923 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1924 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1925 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1926 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1927
1928 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1929 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1930
1931 const StreamParamsVec& data_streams = dcd->streams();
1932 ASSERT_EQ(2U, data_streams.size());
1933 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1934 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1935 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1936 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1937 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1938 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1939 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1940
1941 EXPECT_EQ(cricket::kDataMaxBandwidth,
1942 dcd->bandwidth()); // default bandwidth (auto)
1943 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1944
1945 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001946 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001947 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001948 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001949 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1950 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001951 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001952 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953
1954 ASSERT_TRUE(updated_answer.get() != NULL);
1955 ac = updated_answer->GetContentByName("audio");
1956 vc = updated_answer->GetContentByName("video");
1957 dc = updated_answer->GetContentByName("data");
1958 ASSERT_TRUE(ac != NULL);
1959 ASSERT_TRUE(vc != NULL);
1960 ASSERT_TRUE(dc != NULL);
1961 const AudioContentDescription* updated_acd =
1962 static_cast<const AudioContentDescription*>(ac->description);
1963 const VideoContentDescription* updated_vcd =
1964 static_cast<const VideoContentDescription*>(vc->description);
1965 const DataContentDescription* updated_dcd =
1966 static_cast<const DataContentDescription*>(dc->description);
1967
1968 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1969 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1970 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1971 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1972 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1973 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1974
1975 EXPECT_EQ(acd->type(), updated_acd->type());
1976 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1977 EXPECT_EQ(vcd->type(), updated_vcd->type());
1978 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1979 EXPECT_EQ(dcd->type(), updated_dcd->type());
1980 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1981
1982 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1983 ASSERT_EQ(1U, updated_audio_streams.size());
1984 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1985
1986 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1987 ASSERT_EQ(2U, updated_video_streams.size());
1988 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1989 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001990 // All media streams in one PeerConnection share one CNAME.
1991 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001992
1993 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1994 ASSERT_EQ(1U, updated_data_streams.size());
1995 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1996}
1997
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001998// Create an updated offer after creating an answer to the original offer and
1999// verify that the codecs that were part of the original answer are not changed
2000// in the updated offer.
2001TEST_F(MediaSessionDescriptionFactoryTest,
2002 RespondentCreatesOfferAfterCreatingAnswer) {
2003 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002004 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002005
kwiberg31022942016-03-11 14:18:21 -08002006 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2007 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008 f2_.CreateAnswer(offer.get(), opts, NULL));
2009
2010 const AudioContentDescription* acd =
2011 GetFirstAudioContentDescription(answer.get());
2012 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2013
2014 const VideoContentDescription* vcd =
2015 GetFirstVideoContentDescription(answer.get());
2016 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
2017
kwiberg31022942016-03-11 14:18:21 -08002018 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002019 f2_.CreateOffer(opts, answer.get()));
2020
2021 // The expected audio codecs are the common audio codecs from the first
2022 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2023 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002024 // TODO(wu): |updated_offer| should not include the codec
2025 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002026 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002027 kAudioCodecsAnswer[0],
2028 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002029 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002030 };
2031
2032 // The expected video codecs are the common video codecs from the first
2033 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2034 // preference order.
2035 const VideoCodec kUpdatedVideoCodecOffer[] = {
2036 kVideoCodecsAnswer[0],
2037 kVideoCodecs2[1],
2038 };
2039
2040 const AudioContentDescription* updated_acd =
2041 GetFirstAudioContentDescription(updated_offer.get());
2042 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
2043
2044 const VideoContentDescription* updated_vcd =
2045 GetFirstVideoContentDescription(updated_offer.get());
2046 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
2047}
2048
2049// Create an updated offer after creating an answer to the original offer and
2050// verify that the codecs that were part of the original answer are not changed
2051// in the updated offer. In this test Rtx is enabled.
2052TEST_F(MediaSessionDescriptionFactoryTest,
2053 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2054 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002055 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2056 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002057 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002059 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002060 f1_.set_video_codecs(f1_codecs);
2061
2062 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002063 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002064 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 f2_.set_video_codecs(f2_codecs);
2066
kwiberg31022942016-03-11 14:18:21 -08002067 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002068 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002069 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002070 f2_.CreateAnswer(offer.get(), opts, NULL));
2071
2072 const VideoContentDescription* vcd =
2073 GetFirstVideoContentDescription(answer.get());
2074
2075 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002076 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2077 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002078
2079 EXPECT_EQ(expected_codecs, vcd->codecs());
2080
deadbeef67cf2c12016-04-13 10:07:16 -07002081 // Now, make sure we get same result (except for the order) if |f2_| creates
2082 // an updated offer even though the default payload types between |f1_| and
2083 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002084 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002085 f2_.CreateOffer(opts, answer.get()));
2086 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002087 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002088 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2089
2090 const VideoContentDescription* updated_vcd =
2091 GetFirstVideoContentDescription(updated_answer.get());
2092
2093 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2094}
2095
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002096// Regression test for:
2097// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2098// Existing codecs should always appear before new codecs in re-offers. But
2099// under a specific set of circumstances, the existing RTX codec was ending up
2100// added to the end of the list.
2101TEST_F(MediaSessionDescriptionFactoryTest,
2102 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2103 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002104 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2105 kActive, &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002106 // We specifically choose different preferred payload types for VP8 to
2107 // trigger the issue.
2108 cricket::VideoCodec vp8_offerer(100, "VP8");
2109 cricket::VideoCodec vp8_offerer_rtx =
2110 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2111 cricket::VideoCodec vp8_answerer(110, "VP8");
2112 cricket::VideoCodec vp8_answerer_rtx =
2113 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2114 cricket::VideoCodec vp9(120, "VP9");
2115 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2116
2117 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2118 // We also specifically cause the answerer to prefer VP9, such that if it
2119 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2120 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2121 vp8_answerer_rtx};
2122
2123 f1_.set_video_codecs(f1_codecs);
2124 f2_.set_video_codecs(f2_codecs);
2125 std::vector<AudioCodec> audio_codecs;
2126 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2127 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2128
2129 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
2130 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2131 ASSERT_TRUE(offer.get() != NULL);
2132 std::unique_ptr<SessionDescription> answer(
2133 f2_.CreateAnswer(offer.get(), opts, NULL));
2134
2135 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2136 // But if the bug is triggered, RTX for VP8 ends up last.
2137 std::unique_ptr<SessionDescription> updated_offer(
2138 f2_.CreateOffer(opts, answer.get()));
2139
2140 const VideoContentDescription* vcd =
2141 GetFirstVideoContentDescription(updated_offer.get());
2142 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2143 ASSERT_EQ(4u, codecs.size());
2144 EXPECT_EQ(vp8_offerer, codecs[0]);
2145 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2146 EXPECT_EQ(vp9, codecs[2]);
2147 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002148}
2149
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002150// Create an updated offer that adds video after creating an audio only answer
2151// to the original offer. This test verifies that if a video codec and the RTX
2152// codec have the same default payload type as an audio codec that is already in
2153// use, the added codecs payload types are changed.
2154TEST_F(MediaSessionDescriptionFactoryTest,
2155 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2156 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002157 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002158 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002159 f1_.set_video_codecs(f1_codecs);
2160
2161 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002162 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2163 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164
kwiberg31022942016-03-11 14:18:21 -08002165 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2166 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002167 f2_.CreateAnswer(offer.get(), opts, NULL));
2168
2169 const AudioContentDescription* acd =
2170 GetFirstAudioContentDescription(answer.get());
2171 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2172
2173 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2174 // reference be the same as an audio codec that was negotiated in the
2175 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002176 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002177 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178
2179 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2180 int used_pl_type = acd->codecs()[0].id;
2181 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002182 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002183 f2_.set_video_codecs(f2_codecs);
2184
kwiberg31022942016-03-11 14:18:21 -08002185 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002186 f2_.CreateOffer(opts, answer.get()));
2187 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002188 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002189 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2190
2191 const AudioContentDescription* updated_acd =
2192 GetFirstAudioContentDescription(answer.get());
2193 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2194
2195 const VideoContentDescription* updated_vcd =
2196 GetFirstVideoContentDescription(updated_answer.get());
2197
2198 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002199 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002200 int new_h264_pl_type = updated_vcd->codecs()[0].id;
2201 EXPECT_NE(used_pl_type, new_h264_pl_type);
2202 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002203 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002204 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2205 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2206}
2207
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002208// Create an updated offer with RTX after creating an answer to an offer
2209// without RTX, and with different default payload types.
2210// Verify that the added RTX codec references the correct payload type.
2211TEST_F(MediaSessionDescriptionFactoryTest,
2212 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2213 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002214 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002215
2216 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2217 // This creates rtx for H264 with the payload type |f2_| uses.
2218 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2219 f2_.set_video_codecs(f2_codecs);
2220
kwiberg31022942016-03-11 14:18:21 -08002221 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002222 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002223 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002224 f2_.CreateAnswer(offer.get(), opts, nullptr));
2225
2226 const VideoContentDescription* vcd =
2227 GetFirstVideoContentDescription(answer.get());
2228
2229 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2230 EXPECT_EQ(expected_codecs, vcd->codecs());
2231
2232 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2233 // updated offer, even though the default payload types are different from
2234 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002235 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002236 f2_.CreateOffer(opts, answer.get()));
2237 ASSERT_TRUE(updated_offer);
2238
2239 const VideoContentDescription* updated_vcd =
2240 GetFirstVideoContentDescription(updated_offer.get());
2241
2242 // New offer should attempt to add H263, and RTX for H264.
2243 expected_codecs.push_back(kVideoCodecs2[1]);
2244 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2245 &expected_codecs);
2246 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2247}
2248
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002249// Test that RTX is ignored when there is no associated payload type parameter.
2250TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2251 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002252 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2253 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002254 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002255 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002256 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002257 f1_.set_video_codecs(f1_codecs);
2258
2259 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002260 // This creates RTX for H264 with the payload type |f2_| uses.
2261 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002262 f2_.set_video_codecs(f2_codecs);
2263
kwiberg31022942016-03-11 14:18:21 -08002264 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002265 ASSERT_TRUE(offer.get() != NULL);
2266 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2267 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2268 // is possible to test that that RTX is dropped when
2269 // kCodecParamAssociatedPayloadType is missing in the offer.
2270 VideoContentDescription* desc =
2271 static_cast<cricket::VideoContentDescription*>(
2272 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2273 ASSERT_TRUE(desc != NULL);
2274 std::vector<VideoCodec> codecs = desc->codecs();
2275 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
2276 iter != codecs.end(); ++iter) {
2277 if (iter->name.find(cricket::kRtxCodecName) == 0) {
2278 iter->params.clear();
2279 }
2280 }
2281 desc->set_codecs(codecs);
2282
kwiberg31022942016-03-11 14:18:21 -08002283 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002284 f2_.CreateAnswer(offer.get(), opts, NULL));
2285
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002286 std::vector<std::string> codec_names =
2287 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2288 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2289 cricket::kRtxCodecName));
2290}
2291
2292// Test that RTX will be filtered out in the answer if its associated payload
2293// type doesn't match the local value.
2294TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2295 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002296 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2297 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002298 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2299 // This creates RTX for H264 in sender.
2300 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2301 f1_.set_video_codecs(f1_codecs);
2302
2303 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2304 // This creates RTX for H263 in receiver.
2305 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2306 f2_.set_video_codecs(f2_codecs);
2307
kwiberg31022942016-03-11 14:18:21 -08002308 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002309 ASSERT_TRUE(offer.get() != NULL);
2310 // Associated payload type doesn't match, therefore, RTX codec is removed in
2311 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002312 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002313 f2_.CreateAnswer(offer.get(), opts, NULL));
2314
2315 std::vector<std::string> codec_names =
2316 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2317 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2318 cricket::kRtxCodecName));
2319}
2320
2321// Test that when multiple RTX codecs are offered, only the matched RTX codec
2322// is added in the answer, and the unsupported RTX codec is filtered out.
2323TEST_F(MediaSessionDescriptionFactoryTest,
2324 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2325 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002326 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2327 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002328 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2329 // This creates RTX for H264-SVC in sender.
2330 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2331 f1_.set_video_codecs(f1_codecs);
2332
2333 // This creates RTX for H264 in sender.
2334 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2335 f1_.set_video_codecs(f1_codecs);
2336
2337 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2338 // This creates RTX for H264 in receiver.
2339 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2340 f2_.set_video_codecs(f2_codecs);
2341
2342 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2343 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002344 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002345 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002346 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002347 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002348 const VideoContentDescription* vcd =
2349 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002350 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2351 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2352 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002353
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002354 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002355}
2356
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002357// Test that after one RTX codec has been negotiated, a new offer can attempt
2358// to add another.
2359TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2360 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002361 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2362 kActive, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002363 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2364 // This creates RTX for H264 for the offerer.
2365 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2366 f1_.set_video_codecs(f1_codecs);
2367
kwiberg31022942016-03-11 14:18:21 -08002368 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002369 ASSERT_TRUE(offer);
2370 const VideoContentDescription* vcd =
2371 GetFirstVideoContentDescription(offer.get());
2372
2373 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2374 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2375 &expected_codecs);
2376 EXPECT_EQ(expected_codecs, vcd->codecs());
2377
2378 // Now, attempt to add RTX for H264-SVC.
2379 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2380 f1_.set_video_codecs(f1_codecs);
2381
kwiberg31022942016-03-11 14:18:21 -08002382 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002383 f1_.CreateOffer(opts, offer.get()));
2384 ASSERT_TRUE(updated_offer);
2385 vcd = GetFirstVideoContentDescription(updated_offer.get());
2386
2387 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2388 &expected_codecs);
2389 EXPECT_EQ(expected_codecs, vcd->codecs());
2390}
2391
Noah Richards2e7a0982015-05-18 14:02:54 -07002392// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2393// generated for each simulcast ssrc and correctly grouped.
2394TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2395 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002396 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2397 kActive, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002398 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002399 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002400 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002401
2402 // Use a single real codec, and then add RTX for it.
2403 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002404 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002405 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2406 f1_.set_video_codecs(f1_codecs);
2407
2408 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2409 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002410 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002411 ASSERT_TRUE(offer.get() != NULL);
2412 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2413 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2414 ASSERT_TRUE(desc != NULL);
2415 EXPECT_TRUE(desc->multistream());
2416 const StreamParamsVec& streams = desc->streams();
2417 // Single stream.
2418 ASSERT_EQ(1u, streams.size());
2419 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2420 EXPECT_EQ(6u, streams[0].ssrcs.size());
2421 // And should have a SIM group for the simulcast.
2422 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2423 // And a FID group for RTX.
2424 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002425 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002426 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2427 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002428 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002429 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2430 EXPECT_EQ(3u, fid_ssrcs.size());
2431}
2432
brandtr03d5fb12016-11-22 03:37:59 -08002433// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2434// together with a FEC-FR grouping.
2435TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2436 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002437 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2438 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002439 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002440 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002441 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002442
2443 // Use a single real codec, and then add FlexFEC for it.
2444 std::vector<VideoCodec> f1_codecs;
2445 f1_codecs.push_back(VideoCodec(97, "H264"));
2446 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2447 f1_.set_video_codecs(f1_codecs);
2448
2449 // Ensure that the offer has a single FlexFEC ssrc and that
2450 // there is no FEC-FR ssrc + grouping for each.
2451 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2452 ASSERT_TRUE(offer.get() != nullptr);
2453 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2454 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2455 ASSERT_TRUE(desc != nullptr);
2456 EXPECT_TRUE(desc->multistream());
2457 const StreamParamsVec& streams = desc->streams();
2458 // Single stream.
2459 ASSERT_EQ(1u, streams.size());
2460 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2461 EXPECT_EQ(2u, streams[0].ssrcs.size());
2462 // And should have a FEC-FR group for FlexFEC.
2463 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2464 std::vector<uint32_t> primary_ssrcs;
2465 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2466 ASSERT_EQ(1u, primary_ssrcs.size());
2467 uint32_t flexfec_ssrc;
2468 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2469 EXPECT_NE(flexfec_ssrc, 0u);
2470}
2471
2472// Test that FlexFEC is disabled for simulcast.
2473// TODO(brandtr): Remove this test when we support simulcast, either through
2474// multiple FlexfecSenders, or through multistream protection.
2475TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2476 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002477 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2478 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002479 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002480 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002481 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002482
2483 // Use a single real codec, and then add FlexFEC for it.
2484 std::vector<VideoCodec> f1_codecs;
2485 f1_codecs.push_back(VideoCodec(97, "H264"));
2486 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2487 f1_.set_video_codecs(f1_codecs);
2488
2489 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2490 // there is no FEC-FR ssrc + grouping for each.
2491 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2492 ASSERT_TRUE(offer.get() != nullptr);
2493 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2494 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2495 ASSERT_TRUE(desc != nullptr);
2496 EXPECT_FALSE(desc->multistream());
2497 const StreamParamsVec& streams = desc->streams();
2498 // Single stream.
2499 ASSERT_EQ(1u, streams.size());
2500 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2501 EXPECT_EQ(3u, streams[0].ssrcs.size());
2502 // And should have a SIM group for the simulcast.
2503 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2504 // And not a FEC-FR group for FlexFEC.
2505 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2506 std::vector<uint32_t> primary_ssrcs;
2507 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2508 EXPECT_EQ(3u, primary_ssrcs.size());
2509 for (uint32_t primary_ssrc : primary_ssrcs) {
2510 uint32_t flexfec_ssrc;
2511 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2512 }
2513}
2514
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002515// Create an updated offer after creating an answer to the original offer and
2516// verify that the RTP header extensions that were part of the original answer
2517// are not changed in the updated offer.
2518TEST_F(MediaSessionDescriptionFactoryTest,
2519 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2520 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002521 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002522
2523 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2524 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2525 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2526 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2527
kwiberg31022942016-03-11 14:18:21 -08002528 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2529 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530 f2_.CreateAnswer(offer.get(), opts, NULL));
2531
2532 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2533 GetFirstAudioContentDescription(
2534 answer.get())->rtp_header_extensions());
2535 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2536 GetFirstVideoContentDescription(
2537 answer.get())->rtp_header_extensions());
2538
kwiberg31022942016-03-11 14:18:21 -08002539 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002540 f2_.CreateOffer(opts, answer.get()));
2541
2542 // The expected RTP header extensions in the new offer are the resulting
2543 // extensions from the first offer/answer exchange plus the extensions only
2544 // |f2_| offer.
2545 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002546 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002547 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2548 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2549 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002550 };
2551
2552 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002553 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002554 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2555 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2556 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002557 };
2558
2559 const AudioContentDescription* updated_acd =
2560 GetFirstAudioContentDescription(updated_offer.get());
2561 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2562 updated_acd->rtp_header_extensions());
2563
2564 const VideoContentDescription* updated_vcd =
2565 GetFirstVideoContentDescription(updated_offer.get());
2566 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2567 updated_vcd->rtp_header_extensions());
2568}
2569
deadbeefa5b273a2015-08-20 17:30:13 -07002570// Verify that if the same RTP extension URI is used for audio and video, the
2571// same ID is used. Also verify that the ID isn't changed when creating an
2572// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002573TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002574 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002575 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002576
2577 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2578 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2579
kwiberg31022942016-03-11 14:18:21 -08002580 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002581
2582 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2583 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002584 const RtpExtension kExpectedVideoRtpExtension[] = {
2585 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002586 };
2587
2588 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2589 GetFirstAudioContentDescription(
2590 offer.get())->rtp_header_extensions());
2591 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2592 GetFirstVideoContentDescription(
2593 offer.get())->rtp_header_extensions());
2594
2595 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002596 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002597 f1_.CreateOffer(opts, offer.get()));
2598
2599 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2600 GetFirstAudioContentDescription(
2601 updated_offer.get())->rtp_header_extensions());
2602 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2603 GetFirstVideoContentDescription(
2604 updated_offer.get())->rtp_header_extensions());
2605}
2606
jbauch5869f502017-06-29 12:31:36 -07002607// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2608TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2609 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002610 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002611
2612 f1_.set_enable_encrypted_rtp_header_extensions(true);
2613 f2_.set_enable_encrypted_rtp_header_extensions(true);
2614
2615 f1_.set_audio_rtp_header_extensions(
2616 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2617 f1_.set_video_rtp_header_extensions(
2618 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2619
2620 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2621
2622 // The extensions that are shared between audio and video should use the same
2623 // id.
2624 const RtpExtension kExpectedVideoRtpExtension[] = {
2625 kVideoRtpExtension3ForEncryption[0],
2626 kAudioRtpExtension3ForEncryptionOffer[1],
2627 kAudioRtpExtension3ForEncryptionOffer[2],
2628 };
2629
2630 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2631 GetFirstAudioContentDescription(
2632 offer.get())->rtp_header_extensions());
2633 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2634 GetFirstVideoContentDescription(
2635 offer.get())->rtp_header_extensions());
2636
2637 // Nothing should change when creating a new offer
2638 std::unique_ptr<SessionDescription> updated_offer(
2639 f1_.CreateOffer(opts, offer.get()));
2640
2641 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2642 GetFirstAudioContentDescription(
2643 updated_offer.get())->rtp_header_extensions());
2644 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2645 GetFirstVideoContentDescription(
2646 updated_offer.get())->rtp_header_extensions());
2647}
2648
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002649TEST(MediaSessionDescription, CopySessionDescription) {
2650 SessionDescription source;
2651 cricket::ContentGroup group(cricket::CN_AUDIO);
2652 source.AddGroup(group);
2653 AudioContentDescription* acd(new AudioContentDescription());
2654 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2655 acd->AddLegacyStream(1);
2656 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2657 VideoContentDescription* vcd(new VideoContentDescription());
2658 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2659 vcd->AddLegacyStream(2);
2660 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2661
kwiberg31022942016-03-11 14:18:21 -08002662 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002663 ASSERT_TRUE(copy.get() != NULL);
2664 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2665 const ContentInfo* ac = copy->GetContentByName("audio");
2666 const ContentInfo* vc = copy->GetContentByName("video");
2667 ASSERT_TRUE(ac != NULL);
2668 ASSERT_TRUE(vc != NULL);
2669 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2670 const AudioContentDescription* acd_copy =
2671 static_cast<const AudioContentDescription*>(ac->description);
2672 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2673 EXPECT_EQ(1u, acd->first_ssrc());
2674
2675 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2676 const VideoContentDescription* vcd_copy =
2677 static_cast<const VideoContentDescription*>(vc->description);
2678 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2679 EXPECT_EQ(2u, vcd->first_ssrc());
2680}
2681
2682// The below TestTransportInfoXXX tests create different offers/answers, and
2683// ensure the TransportInfo in the SessionDescription matches what we expect.
2684TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2685 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002686 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2687 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002688 TestTransportInfo(true, options, false);
2689}
2690
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002691TEST_F(MediaSessionDescriptionFactoryTest,
2692 TestTransportInfoOfferIceRenomination) {
2693 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002694 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2695 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002696 options.media_description_options[0]
2697 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002698 TestTransportInfo(true, options, false);
2699}
2700
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002701TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2702 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002703 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2704 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002705 TestTransportInfo(true, options, true);
2706}
2707
2708TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2709 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002710 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2711 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2712 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713 TestTransportInfo(true, options, false);
2714}
2715
2716TEST_F(MediaSessionDescriptionFactoryTest,
2717 TestTransportInfoOfferMultimediaCurrent) {
2718 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002719 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2720 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2721 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002722 TestTransportInfo(true, options, true);
2723}
2724
2725TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2726 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002727 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2728 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2729 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730 options.bundle_enabled = true;
2731 TestTransportInfo(true, options, false);
2732}
2733
2734TEST_F(MediaSessionDescriptionFactoryTest,
2735 TestTransportInfoOfferBundleCurrent) {
2736 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002737 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2738 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2739 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002740 options.bundle_enabled = true;
2741 TestTransportInfo(true, options, true);
2742}
2743
2744TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2745 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002746 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2747 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002748 TestTransportInfo(false, options, false);
2749}
2750
2751TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002752 TestTransportInfoAnswerIceRenomination) {
2753 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002754 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2755 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002756 options.media_description_options[0]
2757 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002758 TestTransportInfo(false, options, false);
2759}
2760
2761TEST_F(MediaSessionDescriptionFactoryTest,
2762 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002763 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002764 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2765 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002766 TestTransportInfo(false, options, true);
2767}
2768
2769TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2770 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002771 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2772 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2773 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002774 TestTransportInfo(false, options, false);
2775}
2776
2777TEST_F(MediaSessionDescriptionFactoryTest,
2778 TestTransportInfoAnswerMultimediaCurrent) {
2779 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002780 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2781 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2782 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783 TestTransportInfo(false, options, true);
2784}
2785
2786TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2787 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002788 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2789 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2790 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002791 options.bundle_enabled = true;
2792 TestTransportInfo(false, options, false);
2793}
2794
2795TEST_F(MediaSessionDescriptionFactoryTest,
2796 TestTransportInfoAnswerBundleCurrent) {
2797 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002798 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2799 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2800 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002801 options.bundle_enabled = true;
2802 TestTransportInfo(false, options, true);
2803}
2804
2805// Create an offer with bundle enabled and verify the crypto parameters are
2806// the common set of the available cryptos.
2807TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2808 TestCryptoWithBundle(true);
2809}
2810
2811// Create an answer with bundle enabled and verify the crypto parameters are
2812// the common set of the available cryptos.
2813TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2814 TestCryptoWithBundle(false);
2815}
2816
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002817// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2818// DTLS is not enabled locally.
2819TEST_F(MediaSessionDescriptionFactoryTest,
2820 TestOfferDtlsSavpfWithoutDtlsFailed) {
2821 f1_.set_secure(SEC_ENABLED);
2822 f2_.set_secure(SEC_ENABLED);
2823 tdf1_.set_secure(SEC_DISABLED);
2824 tdf2_.set_secure(SEC_DISABLED);
2825
kwiberg31022942016-03-11 14:18:21 -08002826 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002827 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002828 ASSERT_TRUE(offer.get() != NULL);
2829 ContentInfo* offer_content = offer->GetContentByName("audio");
2830 ASSERT_TRUE(offer_content != NULL);
2831 AudioContentDescription* offer_audio_desc =
2832 static_cast<AudioContentDescription*>(offer_content->description);
2833 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2834
kwiberg31022942016-03-11 14:18:21 -08002835 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002836 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002837 ASSERT_TRUE(answer != NULL);
2838 ContentInfo* answer_content = answer->GetContentByName("audio");
2839 ASSERT_TRUE(answer_content != NULL);
2840
2841 ASSERT_TRUE(answer_content->rejected);
2842}
2843
2844// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2845// UDP/TLS/RTP/SAVPF.
2846TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2847 f1_.set_secure(SEC_ENABLED);
2848 f2_.set_secure(SEC_ENABLED);
2849 tdf1_.set_secure(SEC_ENABLED);
2850 tdf2_.set_secure(SEC_ENABLED);
2851
kwiberg31022942016-03-11 14:18:21 -08002852 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002853 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002854 ASSERT_TRUE(offer.get() != NULL);
2855 ContentInfo* offer_content = offer->GetContentByName("audio");
2856 ASSERT_TRUE(offer_content != NULL);
2857 AudioContentDescription* offer_audio_desc =
2858 static_cast<AudioContentDescription*>(offer_content->description);
2859 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2860
kwiberg31022942016-03-11 14:18:21 -08002861 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002862 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002863 ASSERT_TRUE(answer != NULL);
2864
2865 const ContentInfo* answer_content = answer->GetContentByName("audio");
2866 ASSERT_TRUE(answer_content != NULL);
2867 ASSERT_FALSE(answer_content->rejected);
2868
2869 const AudioContentDescription* answer_audio_desc =
2870 static_cast<const AudioContentDescription*>(answer_content->description);
2871 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2872 answer_audio_desc->protocol());
2873}
2874
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002875// Test that we include both SDES and DTLS in the offer, but only include SDES
2876// in the answer if DTLS isn't negotiated.
2877TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2878 f1_.set_secure(SEC_ENABLED);
2879 f2_.set_secure(SEC_ENABLED);
2880 tdf1_.set_secure(SEC_ENABLED);
2881 tdf2_.set_secure(SEC_DISABLED);
2882 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002883 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002884 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002885 const cricket::MediaContentDescription* audio_media_desc;
2886 const cricket::MediaContentDescription* video_media_desc;
2887 const cricket::TransportDescription* audio_trans_desc;
2888 const cricket::TransportDescription* video_trans_desc;
2889
2890 // Generate an offer with SDES and DTLS support.
2891 offer.reset(f1_.CreateOffer(options, NULL));
2892 ASSERT_TRUE(offer.get() != NULL);
2893
2894 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2895 offer->GetContentDescriptionByName("audio"));
2896 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002897 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002898 offer->GetContentDescriptionByName("video"));
2899 ASSERT_TRUE(video_media_desc != NULL);
2900 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2901 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2902
2903 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2904 ASSERT_TRUE(audio_trans_desc != NULL);
2905 video_trans_desc = offer->GetTransportDescriptionByName("video");
2906 ASSERT_TRUE(video_trans_desc != NULL);
2907 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2908 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2909
2910 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2911 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2912 ASSERT_TRUE(answer.get() != NULL);
2913
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002914 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002915 answer->GetContentDescriptionByName("audio"));
2916 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002917 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002918 answer->GetContentDescriptionByName("video"));
2919 ASSERT_TRUE(video_media_desc != NULL);
2920 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2921 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2922
2923 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2924 ASSERT_TRUE(audio_trans_desc != NULL);
2925 video_trans_desc = answer->GetTransportDescriptionByName("video");
2926 ASSERT_TRUE(video_trans_desc != NULL);
2927 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2928 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2929
2930 // Enable DTLS; the answer should now only have DTLS support.
2931 tdf2_.set_secure(SEC_ENABLED);
2932 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2933 ASSERT_TRUE(answer.get() != NULL);
2934
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002935 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002936 answer->GetContentDescriptionByName("audio"));
2937 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002938 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002939 answer->GetContentDescriptionByName("video"));
2940 ASSERT_TRUE(video_media_desc != NULL);
2941 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2942 EXPECT_TRUE(video_media_desc->cryptos().empty());
2943 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2944 audio_media_desc->protocol());
2945 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2946 video_media_desc->protocol());
2947
2948 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2949 ASSERT_TRUE(audio_trans_desc != NULL);
2950 video_trans_desc = answer->GetTransportDescriptionByName("video");
2951 ASSERT_TRUE(video_trans_desc != NULL);
2952 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2953 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002954
2955 // Try creating offer again. DTLS enabled now, crypto's should be empty
2956 // in new offer.
2957 offer.reset(f1_.CreateOffer(options, offer.get()));
2958 ASSERT_TRUE(offer.get() != NULL);
2959 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2960 offer->GetContentDescriptionByName("audio"));
2961 ASSERT_TRUE(audio_media_desc != NULL);
2962 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2963 offer->GetContentDescriptionByName("video"));
2964 ASSERT_TRUE(video_media_desc != NULL);
2965 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2966 EXPECT_TRUE(video_media_desc->cryptos().empty());
2967
2968 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2969 ASSERT_TRUE(audio_trans_desc != NULL);
2970 video_trans_desc = offer->GetTransportDescriptionByName("video");
2971 ASSERT_TRUE(video_trans_desc != NULL);
2972 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2973 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974}
2975
2976// Test that an answer can't be created if cryptos are required but the offer is
2977// unsecure.
2978TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002979 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980 f1_.set_secure(SEC_DISABLED);
2981 tdf1_.set_secure(SEC_DISABLED);
2982 f2_.set_secure(SEC_REQUIRED);
2983 tdf1_.set_secure(SEC_ENABLED);
2984
kwiberg31022942016-03-11 14:18:21 -08002985 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002986 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002987 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002988 f2_.CreateAnswer(offer.get(), options, NULL));
2989 EXPECT_TRUE(answer.get() == NULL);
2990}
2991
2992// Test that we accept a DTLS offer without SDES and create an appropriate
2993// answer.
2994TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2995 f1_.set_secure(SEC_DISABLED);
2996 f2_.set_secure(SEC_ENABLED);
2997 tdf1_.set_secure(SEC_ENABLED);
2998 tdf2_.set_secure(SEC_ENABLED);
2999 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003000 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3001 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3002 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003003
kwiberg31022942016-03-11 14:18:21 -08003004 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003005
3006 // Generate an offer with DTLS but without SDES.
3007 offer.reset(f1_.CreateOffer(options, NULL));
3008 ASSERT_TRUE(offer.get() != NULL);
3009
3010 const AudioContentDescription* audio_offer =
3011 GetFirstAudioContentDescription(offer.get());
3012 ASSERT_TRUE(audio_offer->cryptos().empty());
3013 const VideoContentDescription* video_offer =
3014 GetFirstVideoContentDescription(offer.get());
3015 ASSERT_TRUE(video_offer->cryptos().empty());
3016 const DataContentDescription* data_offer =
3017 GetFirstDataContentDescription(offer.get());
3018 ASSERT_TRUE(data_offer->cryptos().empty());
3019
3020 const cricket::TransportDescription* audio_offer_trans_desc =
3021 offer->GetTransportDescriptionByName("audio");
3022 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3023 const cricket::TransportDescription* video_offer_trans_desc =
3024 offer->GetTransportDescriptionByName("video");
3025 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3026 const cricket::TransportDescription* data_offer_trans_desc =
3027 offer->GetTransportDescriptionByName("data");
3028 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3029
3030 // Generate an answer with DTLS.
3031 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
3032 ASSERT_TRUE(answer.get() != NULL);
3033
3034 const cricket::TransportDescription* audio_answer_trans_desc =
3035 answer->GetTransportDescriptionByName("audio");
3036 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3037 const cricket::TransportDescription* video_answer_trans_desc =
3038 answer->GetTransportDescriptionByName("video");
3039 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3040 const cricket::TransportDescription* data_answer_trans_desc =
3041 answer->GetTransportDescriptionByName("data");
3042 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3043}
3044
3045// Verifies if vad_enabled option is set to false, CN codecs are not present in
3046// offer or answer.
3047TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3048 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003049 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003050 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003051 ASSERT_TRUE(offer.get() != NULL);
3052 const ContentInfo* audio_content = offer->GetContentByName("audio");
3053 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3054
3055 options.vad_enabled = false;
3056 offer.reset(f1_.CreateOffer(options, NULL));
3057 ASSERT_TRUE(offer.get() != NULL);
3058 audio_content = offer->GetContentByName("audio");
3059 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08003060 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003061 f1_.CreateAnswer(offer.get(), options, NULL));
3062 ASSERT_TRUE(answer.get() != NULL);
3063 audio_content = answer->GetContentByName("audio");
3064 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3065}
deadbeef44f08192015-12-15 16:20:09 -08003066
zhihuang1c378ed2017-08-17 14:10:50 -07003067// Test that the generated MIDs match the existing offer.
3068TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003069 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003070 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
3071 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
3072 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
3073 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08003074 opts.data_channel_type = cricket::DCT_SCTP;
Steve Anton4e70a722017-11-28 14:57:10 -08003075 AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
3076 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003077 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08003078 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08003079 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003080 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003081
deadbeef44f08192015-12-15 16:20:09 -08003082 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3083 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3084 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3085 ASSERT_TRUE(audio_content != nullptr);
3086 ASSERT_TRUE(video_content != nullptr);
3087 ASSERT_TRUE(data_content != nullptr);
3088 EXPECT_EQ("audio_modified", audio_content->name);
3089 EXPECT_EQ("video_modified", video_content->name);
3090 EXPECT_EQ("data_modified", data_content->name);
3091}
zhihuangcf5b37c2016-05-05 11:44:35 -07003092
zhihuang1c378ed2017-08-17 14:10:50 -07003093// The following tests verify that the unified plan SDP is supported.
3094// Test that we can create an offer with multiple media sections of same media
3095// type.
3096TEST_F(MediaSessionDescriptionFactoryTest,
3097 CreateOfferWithMultipleAVMediaSections) {
3098 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003099 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3100 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003101 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003102 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003103
Steve Anton4e70a722017-11-28 14:57:10 -08003104 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3105 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003106 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003107 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003108
Steve Anton4e70a722017-11-28 14:57:10 -08003109 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3110 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003111 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003112 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003113
Steve Anton4e70a722017-11-28 14:57:10 -08003114 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3115 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003116 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003117 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003118 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3119 ASSERT_TRUE(offer);
3120
3121 ASSERT_EQ(4u, offer->contents().size());
3122 EXPECT_FALSE(offer->contents()[0].rejected);
3123 const AudioContentDescription* acd =
3124 static_cast<const AudioContentDescription*>(
3125 offer->contents()[0].description);
3126 ASSERT_EQ(1u, acd->streams().size());
3127 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003128 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003129
3130 EXPECT_FALSE(offer->contents()[1].rejected);
3131 const VideoContentDescription* vcd =
3132 static_cast<const VideoContentDescription*>(
3133 offer->contents()[1].description);
3134 ASSERT_EQ(1u, vcd->streams().size());
3135 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003136 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003137
3138 EXPECT_FALSE(offer->contents()[2].rejected);
3139 acd = static_cast<const AudioContentDescription*>(
3140 offer->contents()[2].description);
3141 ASSERT_EQ(1u, acd->streams().size());
3142 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003143 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003144
3145 EXPECT_FALSE(offer->contents()[3].rejected);
3146 vcd = static_cast<const VideoContentDescription*>(
3147 offer->contents()[3].description);
3148 ASSERT_EQ(1u, vcd->streams().size());
3149 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003150 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003151}
3152
3153// Test that we can create an answer with multiple media sections of same media
3154// type.
3155TEST_F(MediaSessionDescriptionFactoryTest,
3156 CreateAnswerWithMultipleAVMediaSections) {
3157 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003158 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3159 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003160 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003161 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003162
Steve Anton4e70a722017-11-28 14:57:10 -08003163 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3164 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003165 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003166 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003167
Steve Anton4e70a722017-11-28 14:57:10 -08003168 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3169 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003170 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003171 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003172
Steve Anton4e70a722017-11-28 14:57:10 -08003173 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3174 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003175 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003176 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003177
3178 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3179 ASSERT_TRUE(offer);
3180 std::unique_ptr<SessionDescription> answer(
3181 f2_.CreateAnswer(offer.get(), opts, nullptr));
3182
3183 ASSERT_EQ(4u, answer->contents().size());
3184 EXPECT_FALSE(answer->contents()[0].rejected);
3185 const AudioContentDescription* acd =
3186 static_cast<const AudioContentDescription*>(
3187 answer->contents()[0].description);
3188 ASSERT_EQ(1u, acd->streams().size());
3189 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003190 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003191
3192 EXPECT_FALSE(answer->contents()[1].rejected);
3193 const VideoContentDescription* vcd =
3194 static_cast<const VideoContentDescription*>(
3195 answer->contents()[1].description);
3196 ASSERT_EQ(1u, vcd->streams().size());
3197 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003198 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003199
3200 EXPECT_FALSE(answer->contents()[2].rejected);
3201 acd = static_cast<const AudioContentDescription*>(
3202 answer->contents()[2].description);
3203 ASSERT_EQ(1u, acd->streams().size());
3204 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003205 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003206
3207 EXPECT_FALSE(answer->contents()[3].rejected);
3208 vcd = static_cast<const VideoContentDescription*>(
3209 answer->contents()[3].description);
3210 ASSERT_EQ(1u, vcd->streams().size());
3211 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003212 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003213}
3214
3215// Test that the media section will be rejected in offer if the corresponding
3216// MediaDescriptionOptions is stopped by the offerer.
3217TEST_F(MediaSessionDescriptionFactoryTest,
3218 CreateOfferWithMediaSectionStoppedByOfferer) {
3219 // Create an offer with two audio sections and one of them is stopped.
3220 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003221 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3222 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3223 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3224 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003225 std::unique_ptr<SessionDescription> offer(
3226 f1_.CreateOffer(offer_opts, nullptr));
3227 ASSERT_TRUE(offer);
3228 ASSERT_EQ(2u, offer->contents().size());
3229 EXPECT_FALSE(offer->contents()[0].rejected);
3230 EXPECT_TRUE(offer->contents()[1].rejected);
3231}
3232
3233// Test that the media section will be rejected in answer if the corresponding
3234// MediaDescriptionOptions is stopped by the offerer.
3235TEST_F(MediaSessionDescriptionFactoryTest,
3236 CreateAnswerWithMediaSectionStoppedByOfferer) {
3237 // Create an offer with two audio sections and one of them is stopped.
3238 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003239 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3240 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3241 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3242 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003243 std::unique_ptr<SessionDescription> offer(
3244 f1_.CreateOffer(offer_opts, nullptr));
3245 ASSERT_TRUE(offer);
3246 ASSERT_EQ(2u, offer->contents().size());
3247 EXPECT_FALSE(offer->contents()[0].rejected);
3248 EXPECT_TRUE(offer->contents()[1].rejected);
3249
3250 // Create an answer based on the offer.
3251 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003252 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3253 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3254 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3255 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003256 std::unique_ptr<SessionDescription> answer(
3257 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3258 ASSERT_EQ(2u, answer->contents().size());
3259 EXPECT_FALSE(answer->contents()[0].rejected);
3260 EXPECT_TRUE(answer->contents()[1].rejected);
3261}
3262
3263// Test that the media section will be rejected in answer if the corresponding
3264// MediaDescriptionOptions is stopped by the answerer.
3265TEST_F(MediaSessionDescriptionFactoryTest,
3266 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3267 // Create an offer with two audio sections.
3268 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003269 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3270 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3271 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3272 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003273 std::unique_ptr<SessionDescription> offer(
3274 f1_.CreateOffer(offer_opts, nullptr));
3275 ASSERT_TRUE(offer);
3276 ASSERT_EQ(2u, offer->contents().size());
3277 ASSERT_FALSE(offer->contents()[0].rejected);
3278 ASSERT_FALSE(offer->contents()[1].rejected);
3279
3280 // The answerer rejects one of the audio sections.
3281 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003282 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3283 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3284 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3285 RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003286 std::unique_ptr<SessionDescription> answer(
3287 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3288 ASSERT_EQ(2u, answer->contents().size());
3289 EXPECT_FALSE(answer->contents()[0].rejected);
3290 EXPECT_TRUE(answer->contents()[1].rejected);
3291}
3292
3293// Test the generated media sections has the same order of the
3294// corresponding MediaDescriptionOptions.
3295TEST_F(MediaSessionDescriptionFactoryTest,
3296 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3297 MediaSessionOptions opts;
3298 // This tests put video section first because normally audio comes first by
3299 // default.
Steve Anton4e70a722017-11-28 14:57:10 -08003300 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3301 kActive, &opts);
3302 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3303 kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003304 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3305
3306 ASSERT_TRUE(offer);
3307 ASSERT_EQ(2u, offer->contents().size());
3308 EXPECT_EQ("video", offer->contents()[0].name);
3309 EXPECT_EQ("audio", offer->contents()[1].name);
3310}
3311
3312// Test that different media sections using the same codec have same payload
3313// type.
3314TEST_F(MediaSessionDescriptionFactoryTest,
3315 PayloadTypesSharedByMediaSectionsOfSameType) {
3316 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003317 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3318 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3319 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3320 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003321 // Create an offer with two video sections using same codecs.
3322 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3323 ASSERT_TRUE(offer);
3324 ASSERT_EQ(2u, offer->contents().size());
3325 const VideoContentDescription* vcd1 =
3326 static_cast<const VideoContentDescription*>(
3327 offer->contents()[0].description);
3328 const VideoContentDescription* vcd2 =
3329 static_cast<const VideoContentDescription*>(
3330 offer->contents()[1].description);
3331 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3332 ASSERT_EQ(2u, vcd1->codecs().size());
3333 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3334 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3335 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3336 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3337
3338 // Create answer and negotiate the codecs.
3339 std::unique_ptr<SessionDescription> answer(
3340 f2_.CreateAnswer(offer.get(), opts, nullptr));
3341 ASSERT_TRUE(answer);
3342 ASSERT_EQ(2u, answer->contents().size());
3343 vcd1 = static_cast<const VideoContentDescription*>(
3344 answer->contents()[0].description);
3345 vcd2 = static_cast<const VideoContentDescription*>(
3346 answer->contents()[1].description);
3347 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3348 ASSERT_EQ(1u, vcd1->codecs().size());
3349 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3350 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3351}
3352
3353// Test that the codec preference order per media section is respected in
3354// subsequent offer.
3355TEST_F(MediaSessionDescriptionFactoryTest,
3356 CreateOfferRespectsCodecPreferenceOrder) {
3357 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003358 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3359 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3360 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3361 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003362 // Create an offer with two video sections using same codecs.
3363 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3364 ASSERT_TRUE(offer);
3365 ASSERT_EQ(2u, offer->contents().size());
3366 VideoContentDescription* vcd1 =
3367 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3368 const VideoContentDescription* vcd2 =
3369 static_cast<const VideoContentDescription*>(
3370 offer->contents()[1].description);
3371 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3372 EXPECT_EQ(video_codecs, vcd1->codecs());
3373 EXPECT_EQ(video_codecs, vcd2->codecs());
3374
3375 // Change the codec preference of the first video section and create a
3376 // follow-up offer.
3377 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3378 vcd1->set_codecs(video_codecs_reverse);
3379 std::unique_ptr<SessionDescription> updated_offer(
3380 f1_.CreateOffer(opts, offer.get()));
3381 vcd1 = static_cast<VideoContentDescription*>(
3382 updated_offer->contents()[0].description);
3383 vcd2 = static_cast<const VideoContentDescription*>(
3384 updated_offer->contents()[1].description);
3385 // The video codec preference order should be respected.
3386 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3387 EXPECT_EQ(video_codecs, vcd2->codecs());
3388}
3389
3390// Test that the codec preference order per media section is respected in
3391// the answer.
3392TEST_F(MediaSessionDescriptionFactoryTest,
3393 CreateAnswerRespectsCodecPreferenceOrder) {
3394 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003395 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3396 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3397 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3398 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003399 // Create an offer with two video sections using same codecs.
3400 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3401 ASSERT_TRUE(offer);
3402 ASSERT_EQ(2u, offer->contents().size());
3403 VideoContentDescription* vcd1 =
3404 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3405 const VideoContentDescription* vcd2 =
3406 static_cast<const VideoContentDescription*>(
3407 offer->contents()[1].description);
3408 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3409 EXPECT_EQ(video_codecs, vcd1->codecs());
3410 EXPECT_EQ(video_codecs, vcd2->codecs());
3411
3412 // Change the codec preference of the first video section and create an
3413 // answer.
3414 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3415 vcd1->set_codecs(video_codecs_reverse);
3416 std::unique_ptr<SessionDescription> answer(
3417 f1_.CreateAnswer(offer.get(), opts, nullptr));
3418 vcd1 =
3419 static_cast<VideoContentDescription*>(answer->contents()[0].description);
3420 vcd2 = static_cast<const VideoContentDescription*>(
3421 answer->contents()[1].description);
3422 // The video codec preference order should be respected.
3423 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3424 EXPECT_EQ(video_codecs, vcd2->codecs());
3425}
3426
Zhi Huang6f367472017-11-22 13:20:02 -08003427// Test that when creating an answer, the codecs use local parameters instead of
3428// the remote ones.
3429TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3430 const std::string audio_param_name = "audio_param";
3431 const std::string audio_value1 = "audio_v1";
3432 const std::string audio_value2 = "audio_v2";
3433 const std::string video_param_name = "video_param";
3434 const std::string video_value1 = "video_v1";
3435 const std::string video_value2 = "video_v2";
3436
3437 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3438 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3439 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3440 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3441
3442 // Set the parameters for codecs.
3443 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3444 video_codecs1[0].SetParam(video_param_name, video_value1);
3445 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3446 video_codecs2[0].SetParam(video_param_name, video_value2);
3447
3448 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3449 f1_.set_video_codecs(video_codecs1);
3450 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3451 f2_.set_video_codecs(video_codecs2);
3452
3453 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003454 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3455 kActive, &opts);
3456 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3457 kActive, &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003458
3459 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3460 ASSERT_TRUE(offer);
3461 auto offer_acd =
3462 static_cast<AudioContentDescription*>(offer->contents()[0].description);
3463 auto offer_vcd =
3464 static_cast<VideoContentDescription*>(offer->contents()[1].description);
3465 std::string value;
3466 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3467 EXPECT_EQ(audio_value1, value);
3468 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3469 EXPECT_EQ(video_value1, value);
3470
3471 std::unique_ptr<SessionDescription> answer(
3472 f2_.CreateAnswer(offer.get(), opts, nullptr));
3473 ASSERT_TRUE(answer);
3474 auto answer_acd =
3475 static_cast<AudioContentDescription*>(answer->contents()[0].description);
3476 auto answer_vcd =
3477 static_cast<VideoContentDescription*>(answer->contents()[1].description);
3478 // Use the parameters from the local codecs.
3479 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3480 EXPECT_EQ(audio_value2, value);
3481 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3482 EXPECT_EQ(video_value2, value);
3483}
3484
zhihuangcf5b37c2016-05-05 11:44:35 -07003485class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3486 public:
3487 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003488 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3489 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003490 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3491 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003492 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3493 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003494 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3495 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3496 f1_.set_secure(SEC_ENABLED);
3497 f2_.set_secure(SEC_ENABLED);
3498 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003499 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003500 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003501 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003502 tdf1_.set_secure(SEC_ENABLED);
3503 tdf2_.set_secure(SEC_ENABLED);
3504 }
3505
3506 protected:
3507 MediaSessionDescriptionFactory f1_;
3508 MediaSessionDescriptionFactory f2_;
3509 TransportDescriptionFactory tdf1_;
3510 TransportDescriptionFactory tdf2_;
3511};
3512
3513TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3514 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003515 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003516 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3517 ASSERT_TRUE(offer.get() != nullptr);
3518 // Set the protocol for all the contents.
3519 for (auto content : offer.get()->contents()) {
3520 static_cast<MediaContentDescription*>(content.description)
3521 ->set_protocol(GetParam());
3522 }
3523 std::unique_ptr<SessionDescription> answer(
3524 f2_.CreateAnswer(offer.get(), opts, nullptr));
3525 const ContentInfo* ac = answer->GetContentByName("audio");
3526 const ContentInfo* vc = answer->GetContentByName("video");
3527 ASSERT_TRUE(ac != nullptr);
3528 ASSERT_TRUE(vc != nullptr);
3529 EXPECT_FALSE(ac->rejected); // the offer is accepted
3530 EXPECT_FALSE(vc->rejected);
3531 const AudioContentDescription* acd =
3532 static_cast<const AudioContentDescription*>(ac->description);
3533 const VideoContentDescription* vcd =
3534 static_cast<const VideoContentDescription*>(vc->description);
3535 EXPECT_EQ(GetParam(), acd->protocol());
3536 EXPECT_EQ(GetParam(), vcd->protocol());
3537}
3538
3539INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3540 MediaProtocolTest,
3541 ::testing::ValuesIn(kMediaProtocols));
3542INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3543 MediaProtocolTest,
3544 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003545
3546TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3547 TransportDescriptionFactory tdf;
3548 MediaSessionDescriptionFactory sf(&tdf);
3549 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3550 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3551
3552 // The merged list of codecs should contain any send codecs that are also
3553 // nominally in the recieve codecs list. Payload types should be picked from
3554 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3555 // (set to 1). This equals what happens when the send codecs are used in an
3556 // offer and the receive codecs are used in the following answer.
3557 const std::vector<AudioCodec> sendrecv_codecs =
3558 MAKE_VECTOR(kAudioCodecsAnswer);
3559 const std::vector<AudioCodec> no_codecs;
3560
3561 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3562 << "Please don't change shared test data!";
3563 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3564 << "Please don't change shared test data!";
3565 // Alter iLBC send codec to have zero channels, to test that that is handled
3566 // properly.
3567 send_codecs[1].channels = 0;
3568
3569 // Alther iLBC receive codec to be lowercase, to test that case conversions
3570 // are handled properly.
3571 recv_codecs[2].name = "ilbc";
3572
3573 // Test proper merge
3574 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003575 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3576 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3577 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003578
3579 // Test empty send codecs list
3580 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003581 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3582 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3583 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003584
3585 // Test empty recv codecs list
3586 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003587 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3588 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3589 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003590
3591 // Test all empty codec lists
3592 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003593 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3594 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3595 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003596}
3597
3598namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003599// Compare the two vectors of codecs ignoring the payload type.
3600template <class Codec>
3601bool CodecsMatch(const std::vector<Codec>& codecs1,
3602 const std::vector<Codec>& codecs2) {
3603 if (codecs1.size() != codecs2.size()) {
3604 return false;
3605 }
3606
3607 for (size_t i = 0; i < codecs1.size(); ++i) {
3608 if (!codecs1[i].Matches(codecs2[i])) {
3609 return false;
3610 }
3611 }
3612 return true;
3613}
3614
Steve Anton4e70a722017-11-28 14:57:10 -08003615void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07003616 TransportDescriptionFactory tdf;
3617 MediaSessionDescriptionFactory sf(&tdf);
3618 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3619 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3620 const std::vector<AudioCodec> sendrecv_codecs =
3621 MAKE_VECTOR(kAudioCodecsAnswer);
3622 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003623
3624 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003625 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3626
Steve Anton4e70a722017-11-28 14:57:10 -08003627 if (direction == RtpTransceiverDirection::kSendRecv ||
3628 direction == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003629 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003630 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003631 }
ossu075af922016-06-14 03:29:38 -07003632
3633 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3634 ASSERT_TRUE(offer.get() != NULL);
3635 const ContentInfo* ac = offer->GetContentByName("audio");
3636
3637 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003638 // that the codecs put in are right. This happens when we neither want to
3639 // send nor receive audio. The checks are still in place if at some point
3640 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003641 if (ac) {
3642 AudioContentDescription* acd =
3643 static_cast<AudioContentDescription*>(ac->description);
zhihuang1c378ed2017-08-17 14:10:50 -07003644 // sendrecv and inactive should both present lists as if the channel was
3645 // to be used for sending and receiving. Inactive essentially means it
3646 // might eventually be used anything, but we don't know more at this
3647 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08003648 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003649 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08003650 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003651 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003652 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003653 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003654 }
3655 }
3656}
3657
3658static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003659 AudioCodec(0, "codec0", 16000, -1, 1),
3660 AudioCodec(1, "codec1", 8000, 13300, 1),
3661 AudioCodec(2, "codec2", 8000, 64000, 1),
3662 AudioCodec(3, "codec3", 8000, 64000, 1),
3663 AudioCodec(4, "codec4", 8000, 0, 2),
3664 AudioCodec(5, "codec5", 32000, 0, 1),
3665 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003666
zhihuang1c378ed2017-08-17 14:10:50 -07003667/* The codecs groups below are chosen as per the matrix below. The objective
3668 * is to have different sets of codecs in the inputs, to get unique sets of
3669 * codecs after negotiation, depending on offer and answer communication
3670 * directions. One-way directions in the offer should either result in the
3671 * opposite direction in the answer, or an inactive answer. Regardless, the
3672 * choice of codecs should be as if the answer contained the opposite
3673 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003674 *
3675 * | Offer | Answer | Result
3676 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3677 * 0 | x - - | - x - | x - - - -
3678 * 1 | x x x | - x - | x - - x -
3679 * 2 | - x - | x - - | - x - - -
3680 * 3 | x x x | x - - | - x x - -
3681 * 4 | - x - | x x x | - x - - -
3682 * 5 | x - - | x x x | x - - - -
3683 * 6 | x x x | x x x | x x x x x
3684 */
3685// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003686static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3687static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003688// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3689// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003690static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3691static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003692// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003693static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3694static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3695static const int kResultSendrecv_SendCodecs[] = {3, 6};
3696static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3697static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003698
3699template <typename T, int IDXS>
3700std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3701 std::vector<T> out;
3702 out.reserve(IDXS);
3703 for (int idx : indices)
3704 out.push_back(array[idx]);
3705
3706 return out;
3707}
3708
Steve Anton4e70a722017-11-28 14:57:10 -08003709void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
3710 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07003711 bool add_legacy_stream) {
3712 TransportDescriptionFactory offer_tdf;
3713 TransportDescriptionFactory answer_tdf;
3714 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3715 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3716 offer_factory.set_audio_codecs(
3717 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3718 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3719 answer_factory.set_audio_codecs(
3720 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3721 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3722
ossu075af922016-06-14 03:29:38 -07003723 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003724 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3725 &offer_opts);
3726
Steve Anton4e70a722017-11-28 14:57:10 -08003727 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003728 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003729 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003730 }
3731
3732 std::unique_ptr<SessionDescription> offer(
3733 offer_factory.CreateOffer(offer_opts, NULL));
3734 ASSERT_TRUE(offer.get() != NULL);
3735
3736 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003737 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3738 &answer_opts);
3739
Steve Anton4e70a722017-11-28 14:57:10 -08003740 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003741 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003742 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003743 }
3744 std::unique_ptr<SessionDescription> answer(
3745 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3746 const ContentInfo* ac = answer->GetContentByName("audio");
3747
zhihuang1c378ed2017-08-17 14:10:50 -07003748 // If the factory didn't add any audio content to the answer, we cannot
3749 // check that the codecs put in are right. This happens when we neither want
3750 // to send nor receive audio. The checks are still in place if at some point
3751 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003752 if (ac) {
3753 const AudioContentDescription* acd =
3754 static_cast<const AudioContentDescription*>(ac->description);
3755 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
3756
ossu075af922016-06-14 03:29:38 -07003757 std::vector<AudioCodec> target_codecs;
3758 // For offers with sendrecv or inactive, we should never reply with more
3759 // codecs than offered, with these codec sets.
3760 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08003761 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07003762 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3763 kResultSendrecv_SendrecvCodecs);
3764 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003765 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003766 target_codecs =
3767 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003768 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003769 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003770 target_codecs =
3771 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003772 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003773 case RtpTransceiverDirection::kSendRecv:
3774 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003775 target_codecs =
3776 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08003777 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003778 target_codecs =
3779 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003780 } else {
3781 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3782 kResultSendrecv_SendrecvCodecs);
3783 }
3784 break;
3785 }
3786
zhihuang1c378ed2017-08-17 14:10:50 -07003787 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
ossu075af922016-06-14 03:29:38 -07003788 std::stringstream os;
3789 bool first = true;
3790 os << "{";
3791 for (const auto& c : codecs) {
3792 os << (first ? " " : ", ") << c.id;
3793 first = false;
3794 }
3795 os << " }";
3796 return os.str();
3797 };
3798
3799 EXPECT_TRUE(acd->codecs() == target_codecs)
3800 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08003801 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
3802 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07003803 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08003804 << webrtc::RtpTransceiverDirectionToString(answer_direction)
3805 << "; got: "
3806 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07003807 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08003808 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07003809 << "Only inactive offers are allowed to not generate any audio "
3810 "content";
ossu075af922016-06-14 03:29:38 -07003811 }
3812}
brandtr03d5fb12016-11-22 03:37:59 -08003813
3814} // namespace
ossu075af922016-06-14 03:29:38 -07003815
3816class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08003817 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07003818
3819TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003820 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003821}
3822
3823INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3824 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003825 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3826 RtpTransceiverDirection::kRecvOnly,
3827 RtpTransceiverDirection::kSendRecv,
3828 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07003829
3830class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08003831 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
3832 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003833 bool>> {};
ossu075af922016-06-14 03:29:38 -07003834
3835TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003836 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3837 ::testing::get<1>(GetParam()),
3838 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003839}
3840
zhihuang1c378ed2017-08-17 14:10:50 -07003841INSTANTIATE_TEST_CASE_P(
3842 MediaSessionDescriptionFactoryTest,
3843 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003844 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
3845 RtpTransceiverDirection::kRecvOnly,
3846 RtpTransceiverDirection::kSendRecv,
3847 RtpTransceiverDirection::kInactive),
3848 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3849 RtpTransceiverDirection::kRecvOnly,
3850 RtpTransceiverDirection::kSendRecv,
3851 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07003852 ::testing::Bool()));