2013-07-10 00:45:36 +00:00
|
|
|
/*
|
2016-02-10 07:54:43 -08:00
|
|
|
* Copyright 2011 The WebRTC project authors. All Rights Reserved.
|
2013-07-10 00:45:36 +00:00
|
|
|
*
|
2016-02-10 07:54:43 -08:00
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
2013-07-10 00:45:36 +00:00
|
|
|
*/
|
|
|
|
|
|
2018-11-28 16:47:49 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2019-07-05 19:08:33 +02:00
|
|
|
|
2018-11-28 16:47:49 +01:00
|
|
|
#include <cstdint>
|
|
|
|
|
#include <map>
|
2016-04-27 06:47:29 -07:00
|
|
|
#include <memory>
|
2022-02-23 13:44:59 +00:00
|
|
|
#include <sstream>
|
2013-07-10 00:45:36 +00:00
|
|
|
#include <string>
|
2018-11-28 16:47:49 +01:00
|
|
|
#include <utility>
|
2013-07-10 00:45:36 +00:00
|
|
|
#include <vector>
|
|
|
|
|
|
2019-01-28 17:25:26 -08:00
|
|
|
#include "absl/algorithm/container.h"
|
Add x-mt line to the offer.
We already support decoding of the x-mt line. This change adds the
a=x-mt line to the SDP offer. This is not a backward compatible change
for media transport (because of the changes in pre-shared key handling)
1) if media transport is enabled, and SDES is enabled, generate the
media transport offer.
2) if media transport generated the offer, add that offer to the x-mt
line.
3) in order to create media transport, require an x-mt line (backward incompatible).
The way it works is that
1) PeerConnection, on the offerer, asks jsep transport for the
configuration of the media transport.
2) Tentative media transport is created in JsepTransportController when
that happens.
3) SessionDescription will include configuration from this tentative
media transport.
4) When the LocalDescription is set on the offerer, the tentative media
transport is promoted to the real media transport.
Caveats:
- now we really only support MaxBundle. In the previous implementations,
two media transports were briefly created in some tests, and the second
one was destroyed shortly after instantiation.
- we, for now, enforce SDES. In the future, whether SDES is used will be
refactored out of the peer connection.
In the future (on the callee) we should ignore 'is_media_transport' setting. If
Offer contains x-mt, media transport should be used (if the factory is
present). However, we need to decide how to negotiate media transport
for data channels vs data transport for media (x-mt line at this point
doesn't differentiate the two, so we still need to use app setting).
This change also removes the negotation of pre-shared key from the
a=crypto line. Instead, media transport will have its own, 256bit key.
Such key should be transported in the x-mt line. This makes the code
much simpler, and simplifies the dependency / a=crypto lines parsing.
Also, adds a proper test for the connection re-offer (on both sides: callee and caller).
Before, it was possible that media transport could get recreated, based on the offer.
The tests we had didn't test this scenario, and the loopback media factory didn't allow for such test.
This change adds counts to that loopback media factory, and asserts that only 1 media transport is created, even
when there is a re-offer.
Bug: webrtc:9719
Change-Id: Ibd8739af90e914da40ab412454bba8e1529f5a01
Reviewed-on: https://webrtc-review.googlesource.com/c/125040
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26933}
2019-03-01 11:14:05 -08:00
|
|
|
#include "absl/memory/memory.h"
|
2019-02-14 15:13:09 -08:00
|
|
|
#include "absl/strings/str_replace.h"
|
2022-02-23 13:44:59 +00:00
|
|
|
#include "absl/strings/string_view.h"
|
|
|
|
|
#include "absl/types/optional.h"
|
2018-11-28 16:47:49 +01:00
|
|
|
#include "api/array_view.h"
|
2021-11-04 13:52:31 +00:00
|
|
|
#include "api/crypto_params.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "api/jsep_session_description.h"
|
|
|
|
|
#include "api/media_types.h"
|
|
|
|
|
#include "api/rtp_parameters.h"
|
2022-02-23 13:44:59 +00:00
|
|
|
#include "api/rtp_transceiver_direction.h"
|
2018-11-28 16:47:49 +01:00
|
|
|
#include "media/base/codec.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "media/base/media_constants.h"
|
2022-02-23 13:44:59 +00:00
|
|
|
#include "media/base/rid_description.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "media/base/stream_params.h"
|
|
|
|
|
#include "p2p/base/p2p_constants.h"
|
2017-11-28 15:46:08 +01:00
|
|
|
#include "p2p/base/port.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "p2p/base/transport_description.h"
|
|
|
|
|
#include "p2p/base/transport_info.h"
|
2022-02-23 13:44:59 +00:00
|
|
|
#include "pc/media_protocol_names.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "pc/media_session.h"
|
|
|
|
|
#include "pc/session_description.h"
|
2022-02-23 13:44:59 +00:00
|
|
|
#include "pc/simulcast_description.h"
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "rtc_base/checks.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "rtc_base/message_digest.h"
|
|
|
|
|
#include "rtc_base/socket_address.h"
|
|
|
|
|
#include "rtc_base/ssl_fingerprint.h"
|
|
|
|
|
#include "rtc_base/string_encode.h"
|
2018-12-18 15:55:30 -08:00
|
|
|
#include "test/gmock.h"
|
2018-11-28 16:47:49 +01:00
|
|
|
#include "test/gtest.h"
|
2017-09-15 09:04:28 +02:00
|
|
|
|
2017-01-23 04:56:25 -08:00
|
|
|
#ifdef WEBRTC_ANDROID
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "pc/test/android_test_initializer.h"
|
2017-01-23 04:56:25 -08:00
|
|
|
#endif
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "pc/webrtc_sdp.h"
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
using cricket::AudioCodec;
|
|
|
|
|
using cricket::AudioContentDescription;
|
|
|
|
|
using cricket::Candidate;
|
2018-12-18 15:55:30 -08:00
|
|
|
using cricket::ContentGroup;
|
2013-07-10 00:45:36 +00:00
|
|
|
using cricket::ContentInfo;
|
2021-11-04 13:52:31 +00:00
|
|
|
using cricket::CryptoParams;
|
2013-07-10 00:45:36 +00:00
|
|
|
using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
|
|
|
|
|
using cricket::ICE_CANDIDATE_COMPONENT_RTP;
|
|
|
|
|
using cricket::kFecSsrcGroupSemantics;
|
|
|
|
|
using cricket::LOCAL_PORT_TYPE;
|
2017-12-20 16:34:00 -08:00
|
|
|
using cricket::MediaProtocolType;
|
2018-12-18 15:55:30 -08:00
|
|
|
using cricket::RELAY_PORT_TYPE;
|
2018-12-11 15:30:11 -08:00
|
|
|
using cricket::RidDescription;
|
|
|
|
|
using cricket::RidDirection;
|
2019-05-13 13:36:16 +02:00
|
|
|
using cricket::SctpDataContentDescription;
|
2018-12-18 15:55:30 -08:00
|
|
|
using cricket::SessionDescription;
|
2018-12-03 11:35:05 -08:00
|
|
|
using cricket::SimulcastDescription;
|
|
|
|
|
using cricket::SimulcastLayer;
|
2013-07-10 00:45:36 +00:00
|
|
|
using cricket::StreamParams;
|
|
|
|
|
using cricket::STUN_PORT_TYPE;
|
|
|
|
|
using cricket::TransportDescription;
|
|
|
|
|
using cricket::TransportInfo;
|
|
|
|
|
using cricket::VideoCodec;
|
|
|
|
|
using cricket::VideoContentDescription;
|
2018-12-18 15:55:30 -08:00
|
|
|
using ::testing::ElementsAre;
|
|
|
|
|
using ::testing::Field;
|
2013-07-10 00:45:36 +00:00
|
|
|
using webrtc::IceCandidateCollection;
|
|
|
|
|
using webrtc::IceCandidateInterface;
|
|
|
|
|
using webrtc::JsepIceCandidate;
|
|
|
|
|
using webrtc::JsepSessionDescription;
|
2016-05-26 11:24:55 -07:00
|
|
|
using webrtc::RtpExtension;
|
2017-11-28 14:57:10 -08:00
|
|
|
using webrtc::RtpTransceiverDirection;
|
2013-07-10 00:45:36 +00:00
|
|
|
using webrtc::SdpParseError;
|
2017-12-07 10:27:41 -08:00
|
|
|
using webrtc::SdpType;
|
2013-07-10 00:45:36 +00:00
|
|
|
using webrtc::SessionDescriptionInterface;
|
|
|
|
|
|
|
|
|
|
typedef std::vector<AudioCodec> AudioCodecs;
|
|
|
|
|
typedef std::vector<Candidate> Candidates;
|
|
|
|
|
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
static const uint32_t kDefaultSctpPort = 5000;
|
2017-02-17 19:48:38 -08:00
|
|
|
static const uint16_t kUnusualSctpPort = 9556;
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kSessionTime[] = "t=0 0\r\n";
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
static const uint32_t kCandidatePriority = 2130706432U; // pref = 1.0
|
2015-12-28 15:17:14 -08:00
|
|
|
static const char kAttributeIceUfragVoice[] = "a=ice-ufrag:ufrag_voice\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kAttributeIcePwdVoice[] = "a=ice-pwd:pwd_voice\r\n";
|
2015-12-28 15:17:14 -08:00
|
|
|
static const char kAttributeIceUfragVideo[] = "a=ice-ufrag:ufrag_video\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kAttributeIcePwdVideo[] = "a=ice-pwd:pwd_video\r\n";
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
static const uint32_t kCandidateGeneration = 2;
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kCandidateFoundation1[] = "a0+B/1";
|
|
|
|
|
static const char kCandidateFoundation2[] = "a0+B/2";
|
|
|
|
|
static const char kCandidateFoundation3[] = "a0+B/3";
|
|
|
|
|
static const char kCandidateFoundation4[] = "a0+B/4";
|
|
|
|
|
static const char kAttributeCryptoVoice[] =
|
|
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n";
|
|
|
|
|
static const char kAttributeCryptoVideo[] =
|
|
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n";
|
|
|
|
|
static const char kFingerprint[] =
|
|
|
|
|
"a=fingerprint:sha-1 "
|
|
|
|
|
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n";
|
2018-10-10 22:33:20 +02:00
|
|
|
static const char kExtmapAllowMixed[] = "a=extmap-allow-mixed\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
static const int kExtmapId = 1;
|
|
|
|
|
static const char kExtmapUri[] = "http://example.com/082005/ext.htm#ttime";
|
|
|
|
|
static const char kExtmap[] =
|
|
|
|
|
"a=extmap:1 http://example.com/082005/ext.htm#ttime\r\n";
|
|
|
|
|
static const char kExtmapWithDirectionAndAttribute[] =
|
|
|
|
|
"a=extmap:1/sendrecv http://example.com/082005/ext.htm#ttime a1 a2\r\n";
|
2017-06-29 12:31:36 -07:00
|
|
|
static const char kExtmapWithDirectionAndAttributeEncrypted[] =
|
|
|
|
|
"a=extmap:1/sendrecv urn:ietf:params:rtp-hdrext:encrypt "
|
|
|
|
|
"http://example.com/082005/ext.htm#ttime a1 a2\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
static const uint8_t kIdentityDigest[] = {
|
|
|
|
|
0x4A, 0xAD, 0xB9, 0xB1, 0x3F, 0x82, 0x18, 0x3B, 0x54, 0x02,
|
|
|
|
|
0x12, 0xDF, 0x3E, 0x5D, 0x49, 0x6B, 0x19, 0xE5, 0x7C, 0xAB};
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2015-02-24 20:19:39 +00:00
|
|
|
static const char kDtlsSctp[] = "DTLS/SCTP";
|
|
|
|
|
static const char kUdpDtlsSctp[] = "UDP/DTLS/SCTP";
|
|
|
|
|
static const char kTcpDtlsSctp[] = "TCP/DTLS/SCTP";
|
2015-02-24 20:19:35 +00:00
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
struct CodecParams {
|
|
|
|
|
int max_ptime;
|
|
|
|
|
int ptime;
|
|
|
|
|
int min_ptime;
|
|
|
|
|
int sprop_stereo;
|
|
|
|
|
int stereo;
|
|
|
|
|
int useinband;
|
2013-07-26 19:17:59 +00:00
|
|
|
int maxaveragebitrate;
|
2013-07-10 00:45:36 +00:00
|
|
|
};
|
|
|
|
|
|
2021-11-04 13:52:31 +00:00
|
|
|
// TODO(deadbeef): In these reference strings, use "a=fingerprint" by default
|
|
|
|
|
// instead of "a=crypto", and have an explicit test for adding "a=crypto".
|
|
|
|
|
// Currently it's the other way around.
|
2016-02-16 17:54:10 -08:00
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// Reference sdp string
|
|
|
|
|
static const char kSdpFullString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
2021-01-19 13:06:32 +01:00
|
|
|
"a=extmap-allow-mixed\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=msid-semantic: WMS local_stream_1\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"m=audio 2345 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=rtcp:2347 IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2346 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2348 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=mid:audio_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
2015-12-09 12:37:51 -08:00
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
2015-02-17 12:36:41 +00:00
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=ssrc:1 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 74.125.224.39\r\n"
|
|
|
|
|
"a=rtcp:3456 IN IP4 74.125.224.39\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
|
|
|
|
|
"a=mid:video_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=ssrc-group:FEC 2 3\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=ssrc:2 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
|
|
|
|
|
"a=ssrc:3 cname:stream_1_cname\r\n"
|
2022-04-07 09:54:51 +00:00
|
|
|
"a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// SDP reference string without the candidates.
|
|
|
|
|
static const char kSdpString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
2021-01-19 13:06:32 +01:00
|
|
|
"a=extmap-allow-mixed\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=msid-semantic: WMS local_stream_1\r\n"
|
2014-10-23 23:37:22 +00:00
|
|
|
"m=audio 9 RTP/SAVPF 111 103 104\r\n"
|
2014-11-07 11:22:06 +00:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=mid:audio_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
2015-12-09 12:37:51 -08:00
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
2015-02-17 12:36:41 +00:00
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=ssrc:1 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
|
2014-10-23 23:37:22 +00:00
|
|
|
"m=video 9 RTP/SAVPF 120\r\n"
|
2014-11-07 11:22:06 +00:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
|
|
|
|
|
"a=mid:video_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=ssrc-group:FEC 2 3\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=ssrc:2 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
|
|
|
|
|
"a=ssrc:3 cname:stream_1_cname\r\n"
|
2022-04-07 09:54:51 +00:00
|
|
|
"a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2019-05-13 13:36:16 +02:00
|
|
|
// draft-ietf-mmusic-sctp-sdp-03
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kSdpSctpDataChannelString[] =
|
2019-05-31 10:17:38 +00:00
|
|
|
"m=application 9 UDP/DTLS/SCTP 5000\r\n"
|
2014-11-07 11:22:06 +00:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=ice-ufrag:ufrag_data\r\n"
|
|
|
|
|
"a=ice-pwd:pwd_data\r\n"
|
|
|
|
|
"a=mid:data_content_name\r\n"
|
2013-10-25 21:18:33 +00:00
|
|
|
"a=sctpmap:5000 webrtc-datachannel 1024\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2015-02-24 20:18:48 +00:00
|
|
|
// draft-ietf-mmusic-sctp-sdp-12
|
2019-04-11 10:41:24 +02:00
|
|
|
// Note - this is invalid per draft-ietf-mmusic-sctp-sdp-26,
|
|
|
|
|
// since the separator after "sctp-port" needs to be a colon.
|
2014-09-05 16:31:56 +00:00
|
|
|
static const char kSdpSctpDataChannelStringWithSctpPort[] =
|
2019-05-31 10:17:38 +00:00
|
|
|
"m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
|
2015-02-24 20:19:26 +00:00
|
|
|
"a=sctp-port 5000\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_data\r\n"
|
|
|
|
|
"a=ice-pwd:pwd_data\r\n"
|
|
|
|
|
"a=mid:data_content_name\r\n";
|
|
|
|
|
|
2019-04-11 10:41:24 +02:00
|
|
|
// draft-ietf-mmusic-sctp-sdp-26
|
2015-10-08 10:15:04 -07:00
|
|
|
static const char kSdpSctpDataChannelStringWithSctpColonPort[] =
|
2019-05-31 10:17:38 +00:00
|
|
|
"m=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n"
|
2015-10-08 10:15:04 -07:00
|
|
|
"a=sctp-port:5000\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_data\r\n"
|
|
|
|
|
"a=ice-pwd:pwd_data\r\n"
|
|
|
|
|
"a=mid:data_content_name\r\n";
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kSdpSctpDataChannelWithCandidatesString[] =
|
2019-05-31 10:17:38 +00:00
|
|
|
"m=application 2345 UDP/DTLS/SCTP 5000\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"c=IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2346 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_data\r\n"
|
|
|
|
|
"a=ice-pwd:pwd_data\r\n"
|
|
|
|
|
"a=mid:data_content_name\r\n"
|
2013-10-25 21:18:33 +00:00
|
|
|
"a=sctpmap:5000 webrtc-datachannel 1024\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2014-05-01 18:30:30 +00:00
|
|
|
static const char kSdpConferenceString[] =
|
2014-02-27 17:52:04 +00:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"a=msid-semantic: WMS\r\n"
|
2014-10-23 23:37:22 +00:00
|
|
|
"m=audio 9 RTP/SAVPF 111 103 104\r\n"
|
2014-11-07 11:22:06 +00:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
2014-02-27 17:52:04 +00:00
|
|
|
"a=x-google-flag:conference\r\n"
|
2014-10-23 23:37:22 +00:00
|
|
|
"m=video 9 RTP/SAVPF 120\r\n"
|
2014-11-07 11:22:06 +00:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
2014-02-27 17:52:04 +00:00
|
|
|
"a=x-google-flag:conference\r\n";
|
|
|
|
|
|
2014-08-05 19:19:05 +00:00
|
|
|
static const char kSdpSessionString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"a=msid-semantic: WMS local_stream\r\n";
|
|
|
|
|
|
|
|
|
|
static const char kSdpAudioString[] =
|
2014-10-23 23:37:22 +00:00
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
2014-11-07 11:22:06 +00:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
2014-08-05 19:19:05 +00:00
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=mid:audio_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=ssrc:1 cname:stream_1_cname\r\n"
|
2022-04-07 09:54:51 +00:00
|
|
|
"a=ssrc:1 msid:local_stream audio_track_id_1\r\n";
|
2014-08-05 19:19:05 +00:00
|
|
|
|
|
|
|
|
static const char kSdpVideoString[] =
|
2014-10-23 23:37:22 +00:00
|
|
|
"m=video 9 RTP/SAVPF 120\r\n"
|
2014-11-07 11:22:06 +00:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
2014-08-05 19:19:05 +00:00
|
|
|
"a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
|
|
|
|
|
"a=mid:video_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
"a=ssrc:2 cname:stream_1_cname\r\n"
|
2022-04-07 09:54:51 +00:00
|
|
|
"a=ssrc:2 msid:local_stream video_track_id_1\r\n";
|
2014-08-05 19:19:05 +00:00
|
|
|
|
2016-12-12 18:37:36 -08:00
|
|
|
// Reference sdp string using bundle-only.
|
|
|
|
|
static const char kBundleOnlySdpFullString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
2021-01-19 13:06:32 +01:00
|
|
|
"a=extmap-allow-mixed\r\n"
|
2016-12-12 18:37:36 -08:00
|
|
|
"a=group:BUNDLE audio_content_name video_content_name\r\n"
|
|
|
|
|
"a=msid-semantic: WMS local_stream_1\r\n"
|
|
|
|
|
"m=audio 2345 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=rtcp:2347 IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2346 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2348 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=mid:audio_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2016-12-12 18:37:36 -08:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
|
|
|
|
"a=ssrc:1 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
|
|
|
|
|
"m=video 0 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=bundle-only\r\n"
|
|
|
|
|
"a=mid:video_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2016-12-12 18:37:36 -08:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
"a=ssrc-group:FEC 2 3\r\n"
|
|
|
|
|
"a=ssrc:2 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
|
|
|
|
|
"a=ssrc:3 cname:stream_1_cname\r\n"
|
2022-04-07 09:54:51 +00:00
|
|
|
"a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n";
|
2016-12-12 18:37:36 -08:00
|
|
|
|
2016-02-16 17:54:10 -08:00
|
|
|
// Plan B SDP reference string, with 2 streams, 2 audio tracks and 3 video
|
|
|
|
|
// tracks.
|
|
|
|
|
static const char kPlanBSdpFullString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
2021-01-19 13:06:32 +01:00
|
|
|
"a=extmap-allow-mixed\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=msid-semantic: WMS local_stream_1 local_stream_2\r\n"
|
|
|
|
|
"m=audio 2345 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=rtcp:2347 IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2346 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2348 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=mid:audio_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
|
|
|
|
"a=ssrc:1 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
|
|
|
|
|
"a=ssrc:4 cname:stream_2_cname\r\n"
|
|
|
|
|
"a=ssrc:4 msid:local_stream_2 audio_track_id_2\r\n"
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 74.125.224.39\r\n"
|
|
|
|
|
"a=rtcp:3456 IN IP4 74.125.224.39\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
|
|
|
|
|
"a=mid:video_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
"a=ssrc-group:FEC 2 3\r\n"
|
|
|
|
|
"a=ssrc:2 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:2 msid:local_stream_1 video_track_id_1\r\n"
|
|
|
|
|
"a=ssrc:3 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n"
|
|
|
|
|
"a=ssrc:5 cname:stream_2_cname\r\n"
|
|
|
|
|
"a=ssrc:5 msid:local_stream_2 video_track_id_2\r\n"
|
|
|
|
|
"a=ssrc:6 cname:stream_2_cname\r\n"
|
2022-04-07 09:54:51 +00:00
|
|
|
"a=ssrc:6 msid:local_stream_2 video_track_id_3\r\n";
|
2016-02-16 17:54:10 -08:00
|
|
|
|
2018-04-02 16:31:36 -07:00
|
|
|
// Unified Plan SDP reference string, with 2 streams, 2 audio tracks and 3 video
|
|
|
|
|
// tracks.
|
|
|
|
|
static const char kUnifiedPlanSdpFullString[] =
|
2016-03-09 17:02:30 -08:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
2021-01-19 13:06:32 +01:00
|
|
|
"a=extmap-allow-mixed\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=msid-semantic: WMS local_stream_1\r\n"
|
|
|
|
|
// Audio track 1, stream 1 (with candidates).
|
2016-03-09 17:02:30 -08:00
|
|
|
"m=audio 2345 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=rtcp:2347 IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2346 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2348 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=mid:audio_content_name\r\n"
|
|
|
|
|
"a=msid:local_stream_1 audio_track_id_1\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2016-03-09 17:02:30 -08:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
|
|
|
|
"a=ssrc:1 cname:stream_1_cname\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
// Video track 1, stream 1 (with candidates).
|
2016-03-09 17:02:30 -08:00
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 74.125.224.39\r\n"
|
|
|
|
|
"a=rtcp:3456 IN IP4 74.125.224.39\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
|
|
|
|
|
"a=mid:video_content_name\r\n"
|
|
|
|
|
"a=msid:local_stream_1 video_track_id_1\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2016-03-09 17:02:30 -08:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
"a=ssrc-group:FEC 2 3\r\n"
|
|
|
|
|
"a=ssrc:2 cname:stream_1_cname\r\n"
|
|
|
|
|
"a=ssrc:3 cname:stream_1_cname\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
// Audio track 2, stream 2.
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
|
|
|
|
|
"a=mid:audio_content_name_2\r\n"
|
|
|
|
|
"a=msid:local_stream_2 audio_track_id_2\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
|
|
|
|
"a=ssrc:4 cname:stream_2_cname\r\n"
|
|
|
|
|
// Video track 2, stream 2.
|
|
|
|
|
"m=video 9 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
|
|
|
|
|
"a=mid:video_content_name_2\r\n"
|
|
|
|
|
"a=msid:local_stream_2 video_track_id_2\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
2016-03-09 17:02:30 -08:00
|
|
|
"a=ssrc:5 cname:stream_2_cname\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
// Video track 3, stream 2.
|
|
|
|
|
"m=video 9 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
|
|
|
|
|
"a=mid:video_content_name_3\r\n"
|
|
|
|
|
"a=msid:local_stream_2 video_track_id_3\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
"a=ssrc:6 cname:stream_2_cname\r\n";
|
2016-03-09 17:02:30 -08:00
|
|
|
|
2018-04-02 16:31:36 -07:00
|
|
|
// Unified Plan SDP reference string:
|
|
|
|
|
// - audio track 1 has 1 a=msid lines
|
|
|
|
|
// - audio track 2 has 2 a=msid lines
|
|
|
|
|
// - audio track 3 has 1 a=msid line with the special "-" marker signifying that
|
|
|
|
|
// there are 0 media stream ids.
|
|
|
|
|
// This Unified Plan SDP represents a SDP that signals the msid using both
|
|
|
|
|
// a=msid and a=ssrc msid semantics.
|
|
|
|
|
static const char kUnifiedPlanSdpFullStringWithSpecialMsid[] =
|
2016-02-16 17:54:10 -08:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
2021-01-19 13:06:32 +01:00
|
|
|
"a=extmap-allow-mixed\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=msid-semantic: WMS local_stream_1\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
// Audio track 1, with 1 stream id.
|
2016-02-16 17:54:10 -08:00
|
|
|
"m=audio 2345 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=rtcp:2347 IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2346 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2348 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=mid:audio_content_name\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2018-10-17 10:25:28 -07:00
|
|
|
"a=msid:local_stream_1 audio_track_id_1\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
|
|
|
|
"a=ssrc:1 cname:stream_1_cname\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=ssrc:1 msid:local_stream_1 audio_track_id_1\r\n"
|
|
|
|
|
// Audio track 2, with two stream ids.
|
2016-02-16 17:54:10 -08:00
|
|
|
"m=audio 9 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
|
|
|
|
|
"a=mid:audio_content_name_2\r\n"
|
2018-10-17 10:25:28 -07:00
|
|
|
"a=sendrecv\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=msid:local_stream_1 audio_track_id_2\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=msid:local_stream_2 audio_track_id_2\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=ssrc:4 cname:stream_1_cname\r\n"
|
|
|
|
|
// The support for Plan B msid signaling only includes the
|
|
|
|
|
// first media stream id "local_stream_1."
|
|
|
|
|
"a=ssrc:4 msid:local_stream_1 audio_track_id_2\r\n"
|
|
|
|
|
// Audio track 3, with no stream ids.
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111 103 104\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=ice-ufrag:ufrag_voice_3\r\na=ice-pwd:pwd_voice_3\r\n"
|
|
|
|
|
"a=mid:audio_content_name_3\r\n"
|
2016-02-16 17:54:10 -08:00
|
|
|
"a=sendrecv\r\n"
|
2018-10-17 10:25:28 -07:00
|
|
|
"a=msid:- audio_track_id_3\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2018-04-02 16:31:36 -07:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
2018-10-17 10:25:28 -07:00
|
|
|
"a=ssrc:7 cname:stream_2_cname\r\n"
|
2022-04-07 09:54:51 +00:00
|
|
|
"a=ssrc:7 msid:- audio_track_id_3\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2018-12-11 15:30:11 -08:00
|
|
|
// SDP string for unified plan without SSRCs
|
|
|
|
|
static const char kUnifiedPlanSdpFullStringNoSsrc[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"a=msid-semantic: WMS local_stream_1\r\n"
|
|
|
|
|
// Audio track 1, stream 1 (with candidates).
|
|
|
|
|
"m=audio 2345 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=rtcp:2347 IN IP4 74.125.127.126\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1235 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1238 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1239 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 1 udp 2130706432 74.125.127.126 2345 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2346 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/3 2 udp 2130706432 74.125.127.126 2347 typ srflx "
|
|
|
|
|
"raddr 192.168.1.5 rport 2348 "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=mid:audio_content_name\r\n"
|
|
|
|
|
"a=msid:local_stream_1 audio_track_id_1\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2018-12-11 15:30:11 -08:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
|
|
|
|
// Video track 1, stream 1 (with candidates).
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 74.125.224.39\r\n"
|
|
|
|
|
"a=rtcp:3456 IN IP4 74.125.224.39\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 2 udp 2130706432 192.168.1.5 1236 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1237 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 2 udp 2130706432 ::1 1240 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/2 1 udp 2130706432 ::1 1241 typ host "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/4 2 udp 2130706432 74.125.224.39 3456 typ relay "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=candidate:a0+B/4 1 udp 2130706432 74.125.224.39 3457 typ relay "
|
|
|
|
|
"generation 2\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_video\r\na=ice-pwd:pwd_video\r\n"
|
|
|
|
|
"a=mid:video_content_name\r\n"
|
|
|
|
|
"a=msid:local_stream_1 video_track_id_1\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2018-12-11 15:30:11 -08:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
// Audio track 2, stream 2.
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111 103 104\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice_2\r\na=ice-pwd:pwd_voice_2\r\n"
|
|
|
|
|
"a=mid:audio_content_name_2\r\n"
|
|
|
|
|
"a=msid:local_stream_2 audio_track_id_2\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=rtcp-rsize\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_32 "
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32 "
|
|
|
|
|
"dummy_session_params\r\n"
|
2018-12-11 15:30:11 -08:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
|
|
|
|
// Video track 2, stream 2.
|
|
|
|
|
"m=video 9 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_video_2\r\na=ice-pwd:pwd_video_2\r\n"
|
|
|
|
|
"a=mid:video_content_name_2\r\n"
|
|
|
|
|
"a=msid:local_stream_2 video_track_id_2\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2018-12-11 15:30:11 -08:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
// Video track 3, stream 2.
|
|
|
|
|
"m=video 9 RTP/SAVPF 120\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_video_3\r\na=ice-pwd:pwd_video_3\r\n"
|
|
|
|
|
"a=mid:video_content_name_3\r\n"
|
|
|
|
|
"a=msid:local_stream_2 video_track_id_3\r\n"
|
|
|
|
|
"a=sendrecv\r\n"
|
2021-11-04 13:52:31 +00:00
|
|
|
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32\r\n"
|
2018-12-11 15:30:11 -08:00
|
|
|
"a=rtpmap:120 VP8/90000\r\n";
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// One candidate reference string as per W3c spec.
|
|
|
|
|
// candidate:<blah> not a=candidate:<blah>CRLF
|
|
|
|
|
static const char kRawCandidate[] =
|
|
|
|
|
"candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host generation 2";
|
|
|
|
|
// One candidate reference string.
|
|
|
|
|
static const char kSdpOneCandidate[] =
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n";
|
2014-08-08 23:09:15 +00:00
|
|
|
|
2014-08-08 22:29:20 +00:00
|
|
|
static const char kSdpTcpActiveCandidate[] =
|
|
|
|
|
"candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
|
|
|
|
|
"tcptype active generation 2";
|
|
|
|
|
static const char kSdpTcpPassiveCandidate[] =
|
|
|
|
|
"candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
|
|
|
|
|
"tcptype passive generation 2";
|
|
|
|
|
static const char kSdpTcpSOCandidate[] =
|
|
|
|
|
"candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
|
|
|
|
|
"tcptype so generation 2";
|
|
|
|
|
static const char kSdpTcpInvalidCandidate[] =
|
|
|
|
|
"candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9 typ host "
|
|
|
|
|
"tcptype invalid generation 2";
|
|
|
|
|
|
2014-08-08 23:09:15 +00:00
|
|
|
// One candidate reference string with IPV6 address.
|
|
|
|
|
static const char kRawIPV6Candidate[] =
|
|
|
|
|
"candidate:a0+B/1 1 udp 2130706432 "
|
2017-05-05 12:04:36 -07:00
|
|
|
"abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd 1234 typ host generation 2";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// One candidate reference string.
|
2015-12-16 18:37:23 -08:00
|
|
|
static const char kSdpOneCandidateWithUfragPwd[] =
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host network_name"
|
2015-12-16 18:37:23 -08:00
|
|
|
" eth0 ufrag user_rtp pwd password_rtp generation 2\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2018-08-09 01:16:13 -07:00
|
|
|
static const char kRawHostnameCandidate[] =
|
|
|
|
|
"candidate:a0+B/1 1 udp 2130706432 a.test 1234 typ host generation 2";
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// Session id and version
|
|
|
|
|
static const char kSessionId[] = "18446744069414584320";
|
|
|
|
|
static const char kSessionVersion[] = "18446462598732840960";
|
|
|
|
|
|
2016-02-16 17:54:10 -08:00
|
|
|
// ICE options.
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kIceOption1[] = "iceoption1";
|
|
|
|
|
static const char kIceOption2[] = "iceoption2";
|
|
|
|
|
static const char kIceOption3[] = "iceoption3";
|
|
|
|
|
|
2016-02-16 17:54:10 -08:00
|
|
|
// ICE ufrags/passwords.
|
|
|
|
|
static const char kUfragVoice[] = "ufrag_voice";
|
|
|
|
|
static const char kPwdVoice[] = "pwd_voice";
|
|
|
|
|
static const char kUfragVideo[] = "ufrag_video";
|
|
|
|
|
static const char kPwdVideo[] = "pwd_video";
|
|
|
|
|
static const char kUfragData[] = "ufrag_data";
|
|
|
|
|
static const char kPwdData[] = "pwd_data";
|
|
|
|
|
|
|
|
|
|
// Extra ufrags/passwords for extra unified plan m= sections.
|
|
|
|
|
static const char kUfragVoice2[] = "ufrag_voice_2";
|
|
|
|
|
static const char kPwdVoice2[] = "pwd_voice_2";
|
2018-04-02 16:31:36 -07:00
|
|
|
static const char kUfragVoice3[] = "ufrag_voice_3";
|
|
|
|
|
static const char kPwdVoice3[] = "pwd_voice_3";
|
2016-02-16 17:54:10 -08:00
|
|
|
static const char kUfragVideo2[] = "ufrag_video_2";
|
|
|
|
|
static const char kPwdVideo2[] = "pwd_video_2";
|
|
|
|
|
static const char kUfragVideo3[] = "ufrag_video_3";
|
|
|
|
|
static const char kPwdVideo3[] = "pwd_video_3";
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// Content name
|
|
|
|
|
static const char kAudioContentName[] = "audio_content_name";
|
|
|
|
|
static const char kVideoContentName[] = "video_content_name";
|
|
|
|
|
static const char kDataContentName[] = "data_content_name";
|
|
|
|
|
|
2016-02-16 17:54:10 -08:00
|
|
|
// Extra content names for extra unified plan m= sections.
|
|
|
|
|
static const char kAudioContentName2[] = "audio_content_name_2";
|
2018-04-02 16:31:36 -07:00
|
|
|
static const char kAudioContentName3[] = "audio_content_name_3";
|
2016-02-16 17:54:10 -08:00
|
|
|
static const char kVideoContentName2[] = "video_content_name_2";
|
|
|
|
|
static const char kVideoContentName3[] = "video_content_name_3";
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// MediaStream 1
|
2018-03-02 11:34:10 -08:00
|
|
|
static const char kStreamId1[] = "local_stream_1";
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kStream1Cname[] = "stream_1_cname";
|
|
|
|
|
static const char kAudioTrackId1[] = "audio_track_id_1";
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
static const uint32_t kAudioTrack1Ssrc = 1;
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kVideoTrackId1[] = "video_track_id_1";
|
2016-02-16 17:54:10 -08:00
|
|
|
static const uint32_t kVideoTrack1Ssrc1 = 2;
|
|
|
|
|
static const uint32_t kVideoTrack1Ssrc2 = 3;
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// MediaStream 2
|
2018-03-02 11:34:10 -08:00
|
|
|
static const char kStreamId2[] = "local_stream_2";
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kStream2Cname[] = "stream_2_cname";
|
|
|
|
|
static const char kAudioTrackId2[] = "audio_track_id_2";
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
static const uint32_t kAudioTrack2Ssrc = 4;
|
2016-02-16 17:54:10 -08:00
|
|
|
static const char kVideoTrackId2[] = "video_track_id_2";
|
|
|
|
|
static const uint32_t kVideoTrack2Ssrc = 5;
|
2013-07-10 00:45:36 +00:00
|
|
|
static const char kVideoTrackId3[] = "video_track_id_3";
|
2016-02-16 17:54:10 -08:00
|
|
|
static const uint32_t kVideoTrack3Ssrc = 6;
|
2018-04-02 16:31:36 -07:00
|
|
|
static const char kAudioTrackId3[] = "audio_track_id_3";
|
|
|
|
|
static const uint32_t kAudioTrack3Ssrc = 7;
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Candidate
|
|
|
|
|
static const char kDummyMid[] = "dummy_mid";
|
|
|
|
|
static const int kDummyIndex = 123;
|
|
|
|
|
|
|
|
|
|
// Misc
|
2017-12-07 10:27:41 -08:00
|
|
|
static SdpType kDummyType = SdpType::kOffer;
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Helper functions
|
|
|
|
|
|
|
|
|
|
static bool SdpDeserialize(const std::string& message,
|
|
|
|
|
JsepSessionDescription* jdesc) {
|
|
|
|
|
return webrtc::SdpDeserialize(message, jdesc, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool SdpDeserializeCandidate(const std::string& message,
|
|
|
|
|
JsepIceCandidate* candidate) {
|
|
|
|
|
return webrtc::SdpDeserializeCandidate(message, candidate, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 22:30:23 +02:00
|
|
|
// Add some extra `newlines` to the `message` after `line`.
|
2013-07-10 00:45:36 +00:00
|
|
|
static void InjectAfter(const std::string& line,
|
|
|
|
|
const std::string& newlines,
|
|
|
|
|
std::string* message) {
|
2019-02-14 15:13:09 -08:00
|
|
|
absl::StrReplaceAll({{line, line + newlines}}, message);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Replace(const std::string& line,
|
|
|
|
|
const std::string& newlines,
|
|
|
|
|
std::string* message) {
|
2019-02-14 15:13:09 -08:00
|
|
|
absl::StrReplaceAll({{line, newlines}}, message);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-07-30 22:30:23 +02:00
|
|
|
// Expect a parse failure on the line containing `bad_part` when attempting to
|
|
|
|
|
// parse `bad_sdp`.
|
2014-04-02 23:19:09 +00:00
|
|
|
static void ExpectParseFailure(const std::string& bad_sdp,
|
|
|
|
|
const std::string& bad_part) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription desc(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
SdpParseError error;
|
2014-04-02 23:19:09 +00:00
|
|
|
bool ret = webrtc::SdpDeserialize(bad_sdp, &desc, &error);
|
2021-03-03 07:44:39 +00:00
|
|
|
ASSERT_FALSE(ret);
|
|
|
|
|
EXPECT_NE(std::string::npos, error.line.find(bad_part.c_str()))
|
|
|
|
|
<< "Did not find " << bad_part << " in " << error.line;
|
2014-04-02 23:19:09 +00:00
|
|
|
}
|
|
|
|
|
|
2021-07-30 22:30:23 +02:00
|
|
|
// Expect fail to parse kSdpFullString if replace `good_part` with `bad_part`.
|
2014-04-02 23:19:09 +00:00
|
|
|
static void ExpectParseFailure(const char* good_part, const char* bad_part) {
|
|
|
|
|
std::string bad_sdp = kSdpFullString;
|
|
|
|
|
Replace(good_part, bad_part, &bad_sdp);
|
|
|
|
|
ExpectParseFailure(bad_sdp, bad_part);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 22:30:23 +02:00
|
|
|
// Expect fail to parse kSdpFullString if add `newlines` after `injectpoint`.
|
2014-04-02 23:19:09 +00:00
|
|
|
static void ExpectParseFailureWithNewLines(const std::string& injectpoint,
|
|
|
|
|
const std::string& newlines,
|
|
|
|
|
const std::string& bad_part) {
|
|
|
|
|
std::string bad_sdp = kSdpFullString;
|
|
|
|
|
InjectAfter(injectpoint, newlines, &bad_sdp);
|
|
|
|
|
ExpectParseFailure(bad_sdp, bad_part);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2017-11-28 14:57:10 -08:00
|
|
|
static void ReplaceDirection(RtpTransceiverDirection direction,
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string* message) {
|
|
|
|
|
std::string new_direction;
|
|
|
|
|
switch (direction) {
|
2017-11-28 14:57:10 -08:00
|
|
|
case RtpTransceiverDirection::kInactive:
|
2013-07-10 00:45:36 +00:00
|
|
|
new_direction = "a=inactive";
|
|
|
|
|
break;
|
2017-11-28 14:57:10 -08:00
|
|
|
case RtpTransceiverDirection::kSendOnly:
|
2013-07-10 00:45:36 +00:00
|
|
|
new_direction = "a=sendonly";
|
|
|
|
|
break;
|
2017-11-28 14:57:10 -08:00
|
|
|
case RtpTransceiverDirection::kRecvOnly:
|
2013-07-10 00:45:36 +00:00
|
|
|
new_direction = "a=recvonly";
|
|
|
|
|
break;
|
2017-11-28 14:57:10 -08:00
|
|
|
case RtpTransceiverDirection::kSendRecv:
|
2020-03-11 10:51:13 +01:00
|
|
|
new_direction = "a=sendrecv";
|
|
|
|
|
break;
|
|
|
|
|
case RtpTransceiverDirection::kStopped:
|
2013-07-10 00:45:36 +00:00
|
|
|
default:
|
2021-11-15 16:57:07 +01:00
|
|
|
RTC_DCHECK_NOTREACHED();
|
2013-07-10 00:45:36 +00:00
|
|
|
new_direction = "a=sendrecv";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
Replace("a=sendrecv", new_direction, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ReplaceRejected(bool audio_rejected,
|
|
|
|
|
bool video_rejected,
|
|
|
|
|
std::string* message) {
|
|
|
|
|
if (audio_rejected) {
|
2015-12-28 15:17:14 -08:00
|
|
|
Replace("m=audio 9", "m=audio 0", message);
|
|
|
|
|
Replace(kAttributeIceUfragVoice, "", message);
|
|
|
|
|
Replace(kAttributeIcePwdVoice, "", message);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
if (video_rejected) {
|
2015-12-28 15:17:14 -08:00
|
|
|
Replace("m=video 9", "m=video 0", message);
|
|
|
|
|
Replace(kAttributeIceUfragVideo, "", message);
|
|
|
|
|
Replace(kAttributeIcePwdVideo, "", message);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WebRtcSdpTest
|
|
|
|
|
|
2019-04-09 15:11:12 +02:00
|
|
|
class WebRtcSdpTest : public ::testing::Test {
|
2013-07-10 00:45:36 +00:00
|
|
|
public:
|
2017-12-07 10:27:41 -08:00
|
|
|
WebRtcSdpTest() : jdesc_(kDummyType) {
|
2016-01-08 05:04:57 -08:00
|
|
|
#ifdef WEBRTC_ANDROID
|
|
|
|
|
webrtc::InitializeAndroidObjects();
|
|
|
|
|
#endif
|
2013-07-10 00:45:36 +00:00
|
|
|
// AudioContentDescription
|
|
|
|
|
audio_desc_ = CreateAudioContentDescription();
|
2016-02-16 17:54:10 -08:00
|
|
|
StreamParams audio_stream;
|
|
|
|
|
audio_stream.id = kAudioTrackId1;
|
|
|
|
|
audio_stream.cname = kStream1Cname;
|
2018-03-02 11:34:10 -08:00
|
|
|
audio_stream.set_stream_ids({kStreamId1});
|
2016-02-16 17:54:10 -08:00
|
|
|
audio_stream.ssrcs.push_back(kAudioTrack1Ssrc);
|
|
|
|
|
audio_desc_->AddStream(audio_stream);
|
2017-03-21 11:04:53 -07:00
|
|
|
rtc::SocketAddress audio_addr("74.125.127.126", 2345);
|
|
|
|
|
audio_desc_->set_connection_address(audio_addr);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(audio_desc_));
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// VideoContentDescription
|
2016-02-16 17:54:10 -08:00
|
|
|
video_desc_ = CreateVideoContentDescription();
|
|
|
|
|
StreamParams video_stream;
|
|
|
|
|
video_stream.id = kVideoTrackId1;
|
|
|
|
|
video_stream.cname = kStream1Cname;
|
2018-03-02 11:34:10 -08:00
|
|
|
video_stream.set_stream_ids({kStreamId1});
|
2016-02-16 17:54:10 -08:00
|
|
|
video_stream.ssrcs.push_back(kVideoTrack1Ssrc1);
|
|
|
|
|
video_stream.ssrcs.push_back(kVideoTrack1Ssrc2);
|
|
|
|
|
cricket::SsrcGroup ssrc_group(kFecSsrcGroupSemantics, video_stream.ssrcs);
|
|
|
|
|
video_stream.ssrc_groups.push_back(ssrc_group);
|
|
|
|
|
video_desc_->AddStream(video_stream);
|
2017-03-21 11:04:53 -07:00
|
|
|
rtc::SocketAddress video_addr("74.125.224.39", 3457);
|
|
|
|
|
video_desc_->set_connection_address(video_addr);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(video_desc_));
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// TransportInfo
|
2018-12-18 15:55:30 -08:00
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
|
|
|
|
kAudioContentName, TransportDescription(kUfragVoice, kPwdVoice)));
|
|
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
|
|
|
|
kVideoContentName, TransportDescription(kUfragVideo, kPwdVideo)));
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// v4 host
|
|
|
|
|
int port = 1234;
|
2014-07-29 17:36:52 +00:00
|
|
|
rtc::SocketAddress address("192.168.1.5", port++);
|
2015-01-15 06:53:07 +00:00
|
|
|
Candidate candidate1(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
|
2014-12-16 23:01:31 +00:00
|
|
|
kCandidatePriority, "", "", LOCAL_PORT_TYPE,
|
|
|
|
|
kCandidateGeneration, kCandidateFoundation1);
|
2013-07-10 00:45:36 +00:00
|
|
|
address.SetPort(port++);
|
2015-01-15 06:53:07 +00:00
|
|
|
Candidate candidate2(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
|
2014-12-16 23:01:31 +00:00
|
|
|
kCandidatePriority, "", "", LOCAL_PORT_TYPE,
|
|
|
|
|
kCandidateGeneration, kCandidateFoundation1);
|
2013-07-10 00:45:36 +00:00
|
|
|
address.SetPort(port++);
|
2015-01-15 06:53:07 +00:00
|
|
|
Candidate candidate3(ICE_CANDIDATE_COMPONENT_RTCP, "udp", address,
|
2014-12-16 23:01:31 +00:00
|
|
|
kCandidatePriority, "", "", LOCAL_PORT_TYPE,
|
|
|
|
|
kCandidateGeneration, kCandidateFoundation1);
|
2013-07-10 00:45:36 +00:00
|
|
|
address.SetPort(port++);
|
2015-01-15 06:53:07 +00:00
|
|
|
Candidate candidate4(ICE_CANDIDATE_COMPONENT_RTP, "udp", address,
|
2014-12-16 23:01:31 +00:00
|
|
|
kCandidatePriority, "", "", LOCAL_PORT_TYPE,
|
|
|
|
|
kCandidateGeneration, kCandidateFoundation1);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// v6 host
|
2014-07-29 17:36:52 +00:00
|
|
|
rtc::SocketAddress v6_address("::1", port++);
|
2015-01-15 06:53:07 +00:00
|
|
|
cricket::Candidate candidate5(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
|
|
|
|
|
v6_address, kCandidatePriority, "", "",
|
2014-12-16 23:01:31 +00:00
|
|
|
cricket::LOCAL_PORT_TYPE,
|
|
|
|
|
kCandidateGeneration, kCandidateFoundation2);
|
2013-07-10 00:45:36 +00:00
|
|
|
v6_address.SetPort(port++);
|
2015-01-15 06:53:07 +00:00
|
|
|
cricket::Candidate candidate6(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
|
|
|
|
|
v6_address, kCandidatePriority, "", "",
|
2014-12-16 23:01:31 +00:00
|
|
|
cricket::LOCAL_PORT_TYPE,
|
|
|
|
|
kCandidateGeneration, kCandidateFoundation2);
|
2013-07-10 00:45:36 +00:00
|
|
|
v6_address.SetPort(port++);
|
2015-01-15 06:53:07 +00:00
|
|
|
cricket::Candidate candidate7(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
|
|
|
|
|
v6_address, kCandidatePriority, "", "",
|
2014-12-16 23:01:31 +00:00
|
|
|
cricket::LOCAL_PORT_TYPE,
|
|
|
|
|
kCandidateGeneration, kCandidateFoundation2);
|
2013-07-10 00:45:36 +00:00
|
|
|
v6_address.SetPort(port++);
|
2015-01-15 06:53:07 +00:00
|
|
|
cricket::Candidate candidate8(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
|
|
|
|
|
v6_address, kCandidatePriority, "", "",
|
2014-12-16 23:01:31 +00:00
|
|
|
cricket::LOCAL_PORT_TYPE,
|
|
|
|
|
kCandidateGeneration, kCandidateFoundation2);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// stun
|
|
|
|
|
int port_stun = 2345;
|
2014-07-29 17:36:52 +00:00
|
|
|
rtc::SocketAddress address_stun("74.125.127.126", port_stun++);
|
|
|
|
|
rtc::SocketAddress rel_address_stun("192.168.1.5", port_stun++);
|
2015-01-15 06:53:07 +00:00
|
|
|
cricket::Candidate candidate9(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
|
|
|
|
|
address_stun, kCandidatePriority, "", "",
|
|
|
|
|
STUN_PORT_TYPE, kCandidateGeneration,
|
2014-12-16 23:01:31 +00:00
|
|
|
kCandidateFoundation3);
|
2013-07-10 00:45:36 +00:00
|
|
|
candidate9.set_related_address(rel_address_stun);
|
|
|
|
|
|
|
|
|
|
address_stun.SetPort(port_stun++);
|
|
|
|
|
rel_address_stun.SetPort(port_stun++);
|
2015-01-15 06:53:07 +00:00
|
|
|
cricket::Candidate candidate10(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
|
|
|
|
|
address_stun, kCandidatePriority, "", "",
|
|
|
|
|
STUN_PORT_TYPE, kCandidateGeneration,
|
2014-12-16 23:01:31 +00:00
|
|
|
kCandidateFoundation3);
|
2013-07-10 00:45:36 +00:00
|
|
|
candidate10.set_related_address(rel_address_stun);
|
|
|
|
|
|
|
|
|
|
// relay
|
|
|
|
|
int port_relay = 3456;
|
2014-07-29 17:36:52 +00:00
|
|
|
rtc::SocketAddress address_relay("74.125.224.39", port_relay++);
|
2015-01-15 06:53:07 +00:00
|
|
|
cricket::Candidate candidate11(cricket::ICE_CANDIDATE_COMPONENT_RTCP, "udp",
|
|
|
|
|
address_relay, kCandidatePriority, "", "",
|
|
|
|
|
cricket::RELAY_PORT_TYPE,
|
2014-12-16 23:01:31 +00:00
|
|
|
kCandidateGeneration, kCandidateFoundation4);
|
2013-07-10 00:45:36 +00:00
|
|
|
address_relay.SetPort(port_relay++);
|
2015-01-15 06:53:07 +00:00
|
|
|
cricket::Candidate candidate12(cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp",
|
|
|
|
|
address_relay, kCandidatePriority, "", "",
|
|
|
|
|
RELAY_PORT_TYPE, kCandidateGeneration,
|
2014-12-16 23:01:31 +00:00
|
|
|
kCandidateFoundation4);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// voice
|
|
|
|
|
candidates_.push_back(candidate1);
|
|
|
|
|
candidates_.push_back(candidate2);
|
|
|
|
|
candidates_.push_back(candidate5);
|
|
|
|
|
candidates_.push_back(candidate6);
|
|
|
|
|
candidates_.push_back(candidate9);
|
|
|
|
|
candidates_.push_back(candidate10);
|
|
|
|
|
|
|
|
|
|
// video
|
|
|
|
|
candidates_.push_back(candidate3);
|
|
|
|
|
candidates_.push_back(candidate4);
|
|
|
|
|
candidates_.push_back(candidate7);
|
|
|
|
|
candidates_.push_back(candidate8);
|
|
|
|
|
candidates_.push_back(candidate11);
|
|
|
|
|
candidates_.push_back(candidate12);
|
|
|
|
|
|
|
|
|
|
jcandidate_.reset(
|
|
|
|
|
new JsepIceCandidate(std::string("audio_content_name"), 0, candidate1));
|
|
|
|
|
|
|
|
|
|
// Set up JsepSessionDescription.
|
2019-04-12 07:01:29 +02:00
|
|
|
jdesc_.Initialize(desc_.Clone(), kSessionId, kSessionVersion);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string mline_id;
|
|
|
|
|
int mline_index = 0;
|
|
|
|
|
for (size_t i = 0; i < candidates_.size(); ++i) {
|
|
|
|
|
// In this test, the audio m line index will be 0, and the video m line
|
|
|
|
|
// will be 1.
|
|
|
|
|
bool is_video = (i > 5);
|
|
|
|
|
mline_id = is_video ? "video_content_name" : "audio_content_name";
|
|
|
|
|
mline_index = is_video ? 1 : 0;
|
|
|
|
|
JsepIceCandidate jice(mline_id, mline_index, candidates_.at(i));
|
|
|
|
|
jdesc_.AddCandidate(&jice);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-02 16:31:36 -07:00
|
|
|
void RemoveVideoCandidates() {
|
2016-12-12 18:37:36 -08:00
|
|
|
const IceCandidateCollection* video_candidates_collection =
|
|
|
|
|
jdesc_.candidates(1);
|
|
|
|
|
ASSERT_NE(nullptr, video_candidates_collection);
|
|
|
|
|
std::vector<cricket::Candidate> video_candidates;
|
|
|
|
|
for (size_t i = 0; i < video_candidates_collection->count(); ++i) {
|
|
|
|
|
cricket::Candidate c = video_candidates_collection->at(i)->candidate();
|
|
|
|
|
c.set_transport_name("video_content_name");
|
|
|
|
|
video_candidates.push_back(c);
|
|
|
|
|
}
|
|
|
|
|
jdesc_.RemoveCandidates(video_candidates);
|
2018-04-02 16:31:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Turns the existing reference description into a description using
|
|
|
|
|
// a=bundle-only. This means no transport attributes and a 0 port value on
|
|
|
|
|
// the m= sections not associated with the BUNDLE-tag.
|
|
|
|
|
void MakeBundleOnlyDescription() {
|
|
|
|
|
RemoveVideoCandidates();
|
2016-12-12 18:37:36 -08:00
|
|
|
|
|
|
|
|
// And the rest of the transport attributes.
|
|
|
|
|
desc_.transport_infos()[1].description.ice_ufrag.clear();
|
|
|
|
|
desc_.transport_infos()[1].description.ice_pwd.clear();
|
|
|
|
|
desc_.transport_infos()[1].description.connection_role =
|
|
|
|
|
cricket::CONNECTIONROLE_NONE;
|
|
|
|
|
|
|
|
|
|
// Set bundle-only flag.
|
|
|
|
|
desc_.contents()[1].bundle_only = true;
|
|
|
|
|
|
|
|
|
|
// Add BUNDLE group.
|
|
|
|
|
ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
|
|
|
|
|
group.AddContentName(kAudioContentName);
|
|
|
|
|
group.AddContentName(kVideoContentName);
|
|
|
|
|
desc_.AddGroup(group);
|
|
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2016-12-12 18:37:36 -08:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 17:54:10 -08:00
|
|
|
// Turns the existing reference description into a plan B description,
|
|
|
|
|
// with 2 audio tracks and 3 video tracks.
|
|
|
|
|
void MakePlanBDescription() {
|
2020-02-28 11:54:40 +01:00
|
|
|
audio_desc_ = new AudioContentDescription(*audio_desc_);
|
|
|
|
|
video_desc_ = new VideoContentDescription(*video_desc_);
|
2016-02-16 17:54:10 -08:00
|
|
|
|
|
|
|
|
StreamParams audio_track_2;
|
|
|
|
|
audio_track_2.id = kAudioTrackId2;
|
|
|
|
|
audio_track_2.cname = kStream2Cname;
|
2018-03-02 11:34:10 -08:00
|
|
|
audio_track_2.set_stream_ids({kStreamId2});
|
2016-02-16 17:54:10 -08:00
|
|
|
audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
|
|
|
|
|
audio_desc_->AddStream(audio_track_2);
|
|
|
|
|
|
|
|
|
|
StreamParams video_track_2;
|
|
|
|
|
video_track_2.id = kVideoTrackId2;
|
|
|
|
|
video_track_2.cname = kStream2Cname;
|
2018-03-02 11:34:10 -08:00
|
|
|
video_track_2.set_stream_ids({kStreamId2});
|
2016-02-16 17:54:10 -08:00
|
|
|
video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
|
|
|
|
|
video_desc_->AddStream(video_track_2);
|
|
|
|
|
|
|
|
|
|
StreamParams video_track_3;
|
|
|
|
|
video_track_3.id = kVideoTrackId3;
|
|
|
|
|
video_track_3.cname = kStream2Cname;
|
2018-03-02 11:34:10 -08:00
|
|
|
video_track_3.set_stream_ids({kStreamId2});
|
2016-02-16 17:54:10 -08:00
|
|
|
video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
|
|
|
|
|
video_desc_->AddStream(video_track_3);
|
|
|
|
|
|
|
|
|
|
desc_.RemoveContentByName(kAudioContentName);
|
|
|
|
|
desc_.RemoveContentByName(kVideoContentName);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(audio_desc_));
|
|
|
|
|
desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(video_desc_));
|
2016-02-16 17:54:10 -08:00
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2016-02-16 17:54:10 -08:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Turns the existing reference description into a unified plan description,
|
|
|
|
|
// with 2 audio tracks and 3 video tracks.
|
2018-12-11 15:30:11 -08:00
|
|
|
void MakeUnifiedPlanDescription(bool use_ssrcs = true) {
|
2016-02-16 17:54:10 -08:00
|
|
|
// Audio track 2.
|
|
|
|
|
AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
|
|
|
|
|
StreamParams audio_track_2;
|
|
|
|
|
audio_track_2.id = kAudioTrackId2;
|
2018-03-02 11:34:10 -08:00
|
|
|
audio_track_2.set_stream_ids({kStreamId2});
|
2018-12-11 15:30:11 -08:00
|
|
|
if (use_ssrcs) {
|
|
|
|
|
audio_track_2.cname = kStream2Cname;
|
|
|
|
|
audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
|
|
|
|
|
}
|
2016-02-16 17:54:10 -08:00
|
|
|
audio_desc_2->AddStream(audio_track_2);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(audio_desc_2));
|
2018-12-18 15:55:30 -08:00
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
|
|
|
|
kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2)));
|
2016-02-16 17:54:10 -08:00
|
|
|
// Video track 2, in stream 2.
|
|
|
|
|
VideoContentDescription* video_desc_2 = CreateVideoContentDescription();
|
|
|
|
|
StreamParams video_track_2;
|
|
|
|
|
video_track_2.id = kVideoTrackId2;
|
2018-03-02 11:34:10 -08:00
|
|
|
video_track_2.set_stream_ids({kStreamId2});
|
2018-12-11 15:30:11 -08:00
|
|
|
if (use_ssrcs) {
|
|
|
|
|
video_track_2.cname = kStream2Cname;
|
|
|
|
|
video_track_2.ssrcs.push_back(kVideoTrack2Ssrc);
|
|
|
|
|
}
|
2016-02-16 17:54:10 -08:00
|
|
|
video_desc_2->AddStream(video_track_2);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kVideoContentName2, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(video_desc_2));
|
2018-12-18 15:55:30 -08:00
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
|
|
|
|
kVideoContentName2, TransportDescription(kUfragVideo2, kPwdVideo2)));
|
2016-02-16 17:54:10 -08:00
|
|
|
|
|
|
|
|
// Video track 3, in stream 2.
|
|
|
|
|
VideoContentDescription* video_desc_3 = CreateVideoContentDescription();
|
|
|
|
|
StreamParams video_track_3;
|
|
|
|
|
video_track_3.id = kVideoTrackId3;
|
2018-03-02 11:34:10 -08:00
|
|
|
video_track_3.set_stream_ids({kStreamId2});
|
2018-12-11 15:30:11 -08:00
|
|
|
if (use_ssrcs) {
|
|
|
|
|
video_track_3.cname = kStream2Cname;
|
|
|
|
|
video_track_3.ssrcs.push_back(kVideoTrack3Ssrc);
|
|
|
|
|
}
|
2016-02-16 17:54:10 -08:00
|
|
|
video_desc_3->AddStream(video_track_3);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kVideoContentName3, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(video_desc_3));
|
2018-12-18 15:55:30 -08:00
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
|
|
|
|
kVideoContentName3, TransportDescription(kUfragVideo3, kPwdVideo3)));
|
2018-02-01 12:22:16 -08:00
|
|
|
desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
|
2016-02-16 17:54:10 -08:00
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2016-02-16 17:54:10 -08:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Creates an audio content description with no streams, and some default
|
|
|
|
|
// configuration.
|
2013-07-10 00:45:36 +00:00
|
|
|
AudioContentDescription* CreateAudioContentDescription() {
|
|
|
|
|
AudioContentDescription* audio = new AudioContentDescription();
|
|
|
|
|
audio->set_rtcp_mux(true);
|
2015-12-09 12:37:51 -08:00
|
|
|
audio->set_rtcp_reduced_size(true);
|
2021-11-04 13:52:31 +00:00
|
|
|
audio->AddCrypto(CryptoParams(
|
|
|
|
|
1, "AES_CM_128_HMAC_SHA1_32",
|
|
|
|
|
"inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32",
|
|
|
|
|
"dummy_session_params"));
|
2013-07-10 00:45:36 +00:00
|
|
|
audio->set_protocol(cricket::kMediaProtocolSavpf);
|
2020-07-01 21:07:32 +02:00
|
|
|
audio->AddCodec(AudioCodec(111, "opus", 48000, 0, 2));
|
2017-01-23 08:55:48 -08:00
|
|
|
audio->AddCodec(AudioCodec(103, "ISAC", 16000, 0, 1));
|
|
|
|
|
audio->AddCodec(AudioCodec(104, "ISAC", 32000, 0, 1));
|
2013-07-10 00:45:36 +00:00
|
|
|
return audio;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-02 16:31:36 -07:00
|
|
|
// Turns the existing reference description into a unified plan description,
|
|
|
|
|
// with 3 audio MediaContentDescriptions with special StreamParams that
|
|
|
|
|
// contain 0 or multiple stream ids: - audio track 1 has 1 media stream id -
|
|
|
|
|
// audio track 2 has 2 media stream ids - audio track 3 has 0 media stream ids
|
2018-10-17 10:25:28 -07:00
|
|
|
void MakeUnifiedPlanDescriptionMultipleStreamIds(const int msid_signaling) {
|
2018-04-02 16:31:36 -07:00
|
|
|
desc_.RemoveContentByName(kVideoContentName);
|
|
|
|
|
desc_.RemoveTransportInfoByName(kVideoContentName);
|
|
|
|
|
RemoveVideoCandidates();
|
|
|
|
|
|
|
|
|
|
// Audio track 2 has 2 media stream ids.
|
|
|
|
|
AudioContentDescription* audio_desc_2 = CreateAudioContentDescription();
|
|
|
|
|
StreamParams audio_track_2;
|
|
|
|
|
audio_track_2.id = kAudioTrackId2;
|
|
|
|
|
audio_track_2.cname = kStream1Cname;
|
|
|
|
|
audio_track_2.set_stream_ids({kStreamId1, kStreamId2});
|
|
|
|
|
audio_track_2.ssrcs.push_back(kAudioTrack2Ssrc);
|
|
|
|
|
audio_desc_2->AddStream(audio_track_2);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kAudioContentName2, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(audio_desc_2));
|
2018-12-18 15:55:30 -08:00
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
|
|
|
|
kAudioContentName2, TransportDescription(kUfragVoice2, kPwdVoice2)));
|
2018-04-02 16:31:36 -07:00
|
|
|
|
|
|
|
|
// Audio track 3 has no stream ids.
|
|
|
|
|
AudioContentDescription* audio_desc_3 = CreateAudioContentDescription();
|
|
|
|
|
StreamParams audio_track_3;
|
|
|
|
|
audio_track_3.id = kAudioTrackId3;
|
|
|
|
|
audio_track_3.cname = kStream2Cname;
|
|
|
|
|
audio_track_3.set_stream_ids({});
|
|
|
|
|
audio_track_3.ssrcs.push_back(kAudioTrack3Ssrc);
|
|
|
|
|
audio_desc_3->AddStream(audio_track_3);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kAudioContentName3, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(audio_desc_3));
|
2018-12-18 15:55:30 -08:00
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
|
|
|
|
kAudioContentName3, TransportDescription(kUfragVoice3, kPwdVoice3)));
|
2018-10-17 10:25:28 -07:00
|
|
|
desc_.set_msid_signaling(msid_signaling);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2018-04-02 16:31:36 -07:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-03 11:16:33 -07:00
|
|
|
// Turns the existing reference description into a unified plan description
|
|
|
|
|
// with one audio MediaContentDescription that contains one StreamParams with
|
|
|
|
|
// 0 ssrcs.
|
|
|
|
|
void MakeUnifiedPlanDescriptionNoSsrcSignaling() {
|
|
|
|
|
desc_.RemoveContentByName(kVideoContentName);
|
|
|
|
|
desc_.RemoveContentByName(kAudioContentName);
|
|
|
|
|
desc_.RemoveTransportInfoByName(kVideoContentName);
|
|
|
|
|
RemoveVideoCandidates();
|
|
|
|
|
|
|
|
|
|
AudioContentDescription* audio_desc = CreateAudioContentDescription();
|
|
|
|
|
StreamParams audio_track;
|
|
|
|
|
audio_track.id = kAudioTrackId1;
|
|
|
|
|
audio_track.set_stream_ids({kStreamId1});
|
|
|
|
|
audio_desc->AddStream(audio_track);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(audio_desc));
|
2018-04-03 11:16:33 -07:00
|
|
|
|
|
|
|
|
// Enable signaling a=msid lines.
|
|
|
|
|
desc_.set_msid_signaling(cricket::kMsidSignalingMediaSection);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2018-04-03 11:16:33 -07:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 17:54:10 -08:00
|
|
|
// Creates a video content description with no streams, and some default
|
|
|
|
|
// configuration.
|
|
|
|
|
VideoContentDescription* CreateVideoContentDescription() {
|
|
|
|
|
VideoContentDescription* video = new VideoContentDescription();
|
2021-11-04 13:52:31 +00:00
|
|
|
video->AddCrypto(CryptoParams(
|
|
|
|
|
1, "AES_CM_128_HMAC_SHA1_80",
|
|
|
|
|
"inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32", ""));
|
2016-02-16 17:54:10 -08:00
|
|
|
video->set_protocol(cricket::kMediaProtocolSavpf);
|
|
|
|
|
video->AddCodec(
|
2016-10-24 01:21:16 -07:00
|
|
|
VideoCodec(120, JsepSessionDescription::kDefaultVideoCodecName));
|
2016-02-16 17:54:10 -08:00
|
|
|
return video;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
template <class MCD>
|
|
|
|
|
void CompareMediaContentDescription(const MCD* cd1, const MCD* cd2) {
|
|
|
|
|
// type
|
2019-06-03 20:35:45 +02:00
|
|
|
EXPECT_EQ(cd1->type(), cd2->type());
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// content direction
|
|
|
|
|
EXPECT_EQ(cd1->direction(), cd2->direction());
|
|
|
|
|
|
|
|
|
|
// rtcp_mux
|
|
|
|
|
EXPECT_EQ(cd1->rtcp_mux(), cd2->rtcp_mux());
|
|
|
|
|
|
2015-12-09 12:37:51 -08:00
|
|
|
// rtcp_reduced_size
|
|
|
|
|
EXPECT_EQ(cd1->rtcp_reduced_size(), cd2->rtcp_reduced_size());
|
|
|
|
|
|
2021-11-04 13:52:31 +00:00
|
|
|
// cryptos
|
|
|
|
|
EXPECT_EQ(cd1->cryptos().size(), cd2->cryptos().size());
|
|
|
|
|
if (cd1->cryptos().size() != cd2->cryptos().size()) {
|
|
|
|
|
ADD_FAILURE();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < cd1->cryptos().size(); ++i) {
|
|
|
|
|
const CryptoParams c1 = cd1->cryptos().at(i);
|
|
|
|
|
const CryptoParams c2 = cd2->cryptos().at(i);
|
|
|
|
|
EXPECT_TRUE(c1.Matches(c2));
|
|
|
|
|
EXPECT_EQ(c1.key_params, c2.key_params);
|
|
|
|
|
EXPECT_EQ(c1.session_params, c2.session_params);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// protocol
|
2015-02-24 20:18:55 +00:00
|
|
|
// Use an equivalence class here, for old and new versions of the
|
|
|
|
|
// protocol description.
|
|
|
|
|
if (cd1->protocol() == cricket::kMediaProtocolDtlsSctp ||
|
2015-02-24 20:19:35 +00:00
|
|
|
cd1->protocol() == cricket::kMediaProtocolUdpDtlsSctp ||
|
|
|
|
|
cd1->protocol() == cricket::kMediaProtocolTcpDtlsSctp) {
|
|
|
|
|
const bool cd2_is_also_dtls_sctp =
|
2015-02-24 20:18:55 +00:00
|
|
|
cd2->protocol() == cricket::kMediaProtocolDtlsSctp ||
|
2015-02-24 20:19:35 +00:00
|
|
|
cd2->protocol() == cricket::kMediaProtocolUdpDtlsSctp ||
|
|
|
|
|
cd2->protocol() == cricket::kMediaProtocolTcpDtlsSctp;
|
|
|
|
|
EXPECT_TRUE(cd2_is_also_dtls_sctp);
|
2015-02-24 20:18:55 +00:00
|
|
|
} else {
|
|
|
|
|
EXPECT_EQ(cd1->protocol(), cd2->protocol());
|
|
|
|
|
}
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// codecs
|
|
|
|
|
EXPECT_EQ(cd1->codecs(), cd2->codecs());
|
|
|
|
|
|
|
|
|
|
// bandwidth
|
|
|
|
|
EXPECT_EQ(cd1->bandwidth(), cd2->bandwidth());
|
|
|
|
|
|
|
|
|
|
// streams
|
|
|
|
|
EXPECT_EQ(cd1->streams(), cd2->streams());
|
|
|
|
|
|
2018-10-10 22:33:20 +02:00
|
|
|
// extmap-allow-mixed
|
2018-10-23 10:17:39 +02:00
|
|
|
EXPECT_EQ(cd1->extmap_allow_mixed_enum(), cd2->extmap_allow_mixed_enum());
|
2018-10-10 22:33:20 +02:00
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// extmap
|
|
|
|
|
ASSERT_EQ(cd1->rtp_header_extensions().size(),
|
|
|
|
|
cd2->rtp_header_extensions().size());
|
|
|
|
|
for (size_t i = 0; i < cd1->rtp_header_extensions().size(); ++i) {
|
2016-05-26 11:24:55 -07:00
|
|
|
const RtpExtension ext1 = cd1->rtp_header_extensions().at(i);
|
|
|
|
|
const RtpExtension ext2 = cd2->rtp_header_extensions().at(i);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_EQ(ext1.uri, ext2.uri);
|
|
|
|
|
EXPECT_EQ(ext1.id, ext2.id);
|
2017-06-29 12:31:36 -07:00
|
|
|
EXPECT_EQ(ext1.encrypt, ext2.encrypt);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-11 15:30:11 -08:00
|
|
|
void CompareRidDescriptionIds(const std::vector<RidDescription>& rids,
|
|
|
|
|
const std::vector<std::string>& ids) {
|
|
|
|
|
// Order of elements does not matter, only equivalence of sets.
|
|
|
|
|
EXPECT_EQ(rids.size(), ids.size());
|
|
|
|
|
for (const std::string& id : ids) {
|
2019-01-28 17:25:26 -08:00
|
|
|
EXPECT_EQ(1l, absl::c_count_if(rids, [id](const RidDescription& rid) {
|
|
|
|
|
return rid.rid == id;
|
|
|
|
|
}));
|
2018-12-11 15:30:11 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-03 11:35:05 -08:00
|
|
|
void CompareSimulcastDescription(const SimulcastDescription& simulcast1,
|
|
|
|
|
const SimulcastDescription& simulcast2) {
|
|
|
|
|
EXPECT_EQ(simulcast1.send_layers().size(), simulcast2.send_layers().size());
|
|
|
|
|
EXPECT_EQ(simulcast1.receive_layers().size(),
|
|
|
|
|
simulcast2.receive_layers().size());
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 13:36:16 +02:00
|
|
|
void CompareSctpDataContentDescription(
|
|
|
|
|
const SctpDataContentDescription* dcd1,
|
|
|
|
|
const SctpDataContentDescription* dcd2) {
|
2019-04-23 05:20:17 +00:00
|
|
|
EXPECT_EQ(dcd1->use_sctpmap(), dcd2->use_sctpmap());
|
2019-05-13 13:36:16 +02:00
|
|
|
EXPECT_EQ(dcd1->port(), dcd2->port());
|
|
|
|
|
EXPECT_EQ(dcd1->max_message_size(), dcd2->max_message_size());
|
2019-04-23 05:20:17 +00:00
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
void CompareSessionDescription(const SessionDescription& desc1,
|
|
|
|
|
const SessionDescription& desc2) {
|
|
|
|
|
// Compare content descriptions.
|
|
|
|
|
if (desc1.contents().size() != desc2.contents().size()) {
|
|
|
|
|
ADD_FAILURE();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < desc1.contents().size(); ++i) {
|
|
|
|
|
const cricket::ContentInfo& c1 = desc1.contents().at(i);
|
|
|
|
|
const cricket::ContentInfo& c2 = desc2.contents().at(i);
|
2016-12-12 18:37:36 -08:00
|
|
|
// ContentInfo properties.
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_EQ(c1.name, c2.name);
|
2016-12-12 18:37:36 -08:00
|
|
|
EXPECT_EQ(c1.type, c2.type);
|
|
|
|
|
EXPECT_EQ(c1.rejected, c2.rejected);
|
|
|
|
|
EXPECT_EQ(c1.bundle_only, c2.bundle_only);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(IsAudioContent(&c1), IsAudioContent(&c2));
|
|
|
|
|
if (IsAudioContent(&c1)) {
|
|
|
|
|
const AudioContentDescription* acd1 =
|
2017-12-21 15:14:30 -08:00
|
|
|
c1.media_description()->as_audio();
|
2013-07-10 00:45:36 +00:00
|
|
|
const AudioContentDescription* acd2 =
|
2017-12-21 15:14:30 -08:00
|
|
|
c2.media_description()->as_audio();
|
2013-07-10 00:45:36 +00:00
|
|
|
CompareMediaContentDescription<AudioContentDescription>(acd1, acd2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(IsVideoContent(&c1), IsVideoContent(&c2));
|
|
|
|
|
if (IsVideoContent(&c1)) {
|
|
|
|
|
const VideoContentDescription* vcd1 =
|
2017-12-21 15:14:30 -08:00
|
|
|
c1.media_description()->as_video();
|
2013-07-10 00:45:36 +00:00
|
|
|
const VideoContentDescription* vcd2 =
|
2017-12-21 15:14:30 -08:00
|
|
|
c2.media_description()->as_video();
|
2013-07-10 00:45:36 +00:00
|
|
|
CompareMediaContentDescription<VideoContentDescription>(vcd1, vcd2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
|
2019-05-13 13:36:16 +02:00
|
|
|
if (c1.media_description()->as_sctp()) {
|
|
|
|
|
ASSERT_TRUE(c2.media_description()->as_sctp());
|
|
|
|
|
const SctpDataContentDescription* scd1 =
|
|
|
|
|
c1.media_description()->as_sctp();
|
|
|
|
|
const SctpDataContentDescription* scd2 =
|
|
|
|
|
c2.media_description()->as_sctp();
|
|
|
|
|
CompareSctpDataContentDescription(scd1, scd2);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
2018-12-03 11:35:05 -08:00
|
|
|
|
|
|
|
|
CompareSimulcastDescription(
|
|
|
|
|
c1.media_description()->simulcast_description(),
|
|
|
|
|
c2.media_description()->simulcast_description());
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// group
|
|
|
|
|
const cricket::ContentGroups groups1 = desc1.groups();
|
|
|
|
|
const cricket::ContentGroups groups2 = desc2.groups();
|
|
|
|
|
EXPECT_EQ(groups1.size(), groups1.size());
|
|
|
|
|
if (groups1.size() != groups2.size()) {
|
|
|
|
|
ADD_FAILURE();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < groups1.size(); ++i) {
|
|
|
|
|
const cricket::ContentGroup group1 = groups1.at(i);
|
|
|
|
|
const cricket::ContentGroup group2 = groups2.at(i);
|
|
|
|
|
EXPECT_EQ(group1.semantics(), group2.semantics());
|
|
|
|
|
const cricket::ContentNames names1 = group1.content_names();
|
|
|
|
|
const cricket::ContentNames names2 = group2.content_names();
|
|
|
|
|
EXPECT_EQ(names1.size(), names2.size());
|
|
|
|
|
if (names1.size() != names2.size()) {
|
|
|
|
|
ADD_FAILURE();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
cricket::ContentNames::const_iterator iter1 = names1.begin();
|
|
|
|
|
cricket::ContentNames::const_iterator iter2 = names2.begin();
|
|
|
|
|
while (iter1 != names1.end()) {
|
|
|
|
|
EXPECT_EQ(*iter1++, *iter2++);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// transport info
|
|
|
|
|
const cricket::TransportInfos transports1 = desc1.transport_infos();
|
|
|
|
|
const cricket::TransportInfos transports2 = desc2.transport_infos();
|
|
|
|
|
EXPECT_EQ(transports1.size(), transports2.size());
|
|
|
|
|
if (transports1.size() != transports2.size()) {
|
|
|
|
|
ADD_FAILURE();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < transports1.size(); ++i) {
|
|
|
|
|
const cricket::TransportInfo transport1 = transports1.at(i);
|
|
|
|
|
const cricket::TransportInfo transport2 = transports2.at(i);
|
|
|
|
|
EXPECT_EQ(transport1.content_name, transport2.content_name);
|
|
|
|
|
EXPECT_EQ(transport1.description.ice_ufrag,
|
|
|
|
|
transport2.description.ice_ufrag);
|
|
|
|
|
EXPECT_EQ(transport1.description.ice_pwd, transport2.description.ice_pwd);
|
2018-05-24 11:37:28 -07:00
|
|
|
EXPECT_EQ(transport1.description.ice_mode,
|
|
|
|
|
transport2.description.ice_mode);
|
2013-07-10 00:45:36 +00:00
|
|
|
if (transport1.description.identity_fingerprint) {
|
|
|
|
|
EXPECT_EQ(*transport1.description.identity_fingerprint,
|
|
|
|
|
*transport2.description.identity_fingerprint);
|
|
|
|
|
} else {
|
|
|
|
|
EXPECT_EQ(transport1.description.identity_fingerprint.get(),
|
|
|
|
|
transport2.description.identity_fingerprint.get());
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(transport1.description.transport_options,
|
|
|
|
|
transport2.description.transport_options);
|
|
|
|
|
}
|
2015-10-22 13:14:45 -07:00
|
|
|
|
|
|
|
|
// global attributes
|
|
|
|
|
EXPECT_EQ(desc1.msid_supported(), desc2.msid_supported());
|
2018-10-23 10:17:39 +02:00
|
|
|
EXPECT_EQ(desc1.extmap_allow_mixed(), desc2.extmap_allow_mixed());
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CompareSessionDescription(const JsepSessionDescription& desc1,
|
|
|
|
|
const JsepSessionDescription& desc2) {
|
|
|
|
|
EXPECT_EQ(desc1.session_id(), desc2.session_id());
|
|
|
|
|
EXPECT_EQ(desc1.session_version(), desc2.session_version());
|
|
|
|
|
CompareSessionDescription(*desc1.description(), *desc2.description());
|
|
|
|
|
if (desc1.number_of_mediasections() != desc2.number_of_mediasections())
|
|
|
|
|
return false;
|
|
|
|
|
for (size_t i = 0; i < desc1.number_of_mediasections(); ++i) {
|
|
|
|
|
const IceCandidateCollection* cc1 = desc1.candidates(i);
|
|
|
|
|
const IceCandidateCollection* cc2 = desc2.candidates(i);
|
2016-12-12 18:37:36 -08:00
|
|
|
if (cc1->count() != cc2->count()) {
|
|
|
|
|
ADD_FAILURE();
|
2013-07-10 00:45:36 +00:00
|
|
|
return false;
|
2016-12-12 18:37:36 -08:00
|
|
|
}
|
2013-07-10 00:45:36 +00:00
|
|
|
for (size_t j = 0; j < cc1->count(); ++j) {
|
|
|
|
|
const IceCandidateInterface* c1 = cc1->at(j);
|
|
|
|
|
const IceCandidateInterface* c2 = cc2->at(j);
|
|
|
|
|
EXPECT_EQ(c1->sdp_mid(), c2->sdp_mid());
|
|
|
|
|
EXPECT_EQ(c1->sdp_mline_index(), c2->sdp_mline_index());
|
|
|
|
|
EXPECT_TRUE(c1->candidate().IsEquivalent(c2->candidate()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 22:30:23 +02:00
|
|
|
// Disable the ice-ufrag and ice-pwd in given `sdp` message by replacing
|
2013-07-10 00:45:36 +00:00
|
|
|
// them with invalid keywords so that the parser will just ignore them.
|
|
|
|
|
bool RemoveCandidateUfragPwd(std::string* sdp) {
|
2019-02-14 15:13:09 -08:00
|
|
|
absl::StrReplaceAll(
|
|
|
|
|
{{"a=ice-ufrag", "a=xice-ufrag"}, {"a=ice-pwd", "a=xice-pwd"}}, sdp);
|
2013-07-10 00:45:36 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 22:30:23 +02:00
|
|
|
// Update the candidates in `jdesc` to use the given `ufrag` and `pwd`.
|
2013-07-10 00:45:36 +00:00
|
|
|
bool UpdateCandidateUfragPwd(JsepSessionDescription* jdesc,
|
|
|
|
|
int mline_index,
|
|
|
|
|
const std::string& ufrag,
|
|
|
|
|
const std::string& pwd) {
|
|
|
|
|
std::string content_name;
|
|
|
|
|
if (mline_index == 0) {
|
|
|
|
|
content_name = kAudioContentName;
|
|
|
|
|
} else if (mline_index == 1) {
|
|
|
|
|
content_name = kVideoContentName;
|
|
|
|
|
} else {
|
2021-11-15 16:57:07 +01:00
|
|
|
RTC_DCHECK_NOTREACHED();
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
TransportInfo transport_info(content_name,
|
2015-09-17 18:54:52 -07:00
|
|
|
TransportDescription(ufrag, pwd));
|
2013-07-10 00:45:36 +00:00
|
|
|
SessionDescription* desc =
|
|
|
|
|
const_cast<SessionDescription*>(jdesc->description());
|
|
|
|
|
desc->RemoveTransportInfoByName(content_name);
|
2018-12-18 15:55:30 -08:00
|
|
|
desc->AddTransportInfo(transport_info);
|
2013-07-10 00:45:36 +00:00
|
|
|
for (size_t i = 0; i < jdesc_.number_of_mediasections(); ++i) {
|
|
|
|
|
const IceCandidateCollection* cc = jdesc_.candidates(i);
|
|
|
|
|
for (size_t j = 0; j < cc->count(); ++j) {
|
|
|
|
|
if (cc->at(j)->sdp_mline_index() == mline_index) {
|
|
|
|
|
const_cast<Candidate&>(cc->at(j)->candidate()).set_username(ufrag);
|
|
|
|
|
const_cast<Candidate&>(cc->at(j)->candidate()).set_password(pwd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddIceOptions(const std::string& content_name,
|
|
|
|
|
const std::vector<std::string>& transport_options) {
|
|
|
|
|
ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
|
|
|
|
|
cricket::TransportInfo transport_info =
|
|
|
|
|
*(desc_.GetTransportInfoByName(content_name));
|
|
|
|
|
desc_.RemoveTransportInfoByName(content_name);
|
|
|
|
|
transport_info.description.transport_options = transport_options;
|
|
|
|
|
desc_.AddTransportInfo(transport_info);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-28 15:17:14 -08:00
|
|
|
void SetIceUfragPwd(const std::string& content_name,
|
|
|
|
|
const std::string& ice_ufrag,
|
|
|
|
|
const std::string& ice_pwd) {
|
|
|
|
|
ASSERT_TRUE(desc_.GetTransportInfoByName(content_name) != NULL);
|
|
|
|
|
cricket::TransportInfo transport_info =
|
|
|
|
|
*(desc_.GetTransportInfoByName(content_name));
|
|
|
|
|
desc_.RemoveTransportInfoByName(content_name);
|
|
|
|
|
transport_info.description.ice_ufrag = ice_ufrag;
|
|
|
|
|
transport_info.description.ice_pwd = ice_pwd;
|
|
|
|
|
desc_.AddTransportInfo(transport_info);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
void AddFingerprint() {
|
|
|
|
|
desc_.RemoveTransportInfoByName(kAudioContentName);
|
|
|
|
|
desc_.RemoveTransportInfoByName(kVideoContentName);
|
2018-10-15 19:27:44 -07:00
|
|
|
rtc::SSLFingerprint fingerprint(rtc::DIGEST_SHA_1, kIdentityDigest);
|
2018-12-18 15:55:30 -08:00
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
2016-01-28 13:24:37 -08:00
|
|
|
kAudioContentName,
|
2016-02-16 17:54:10 -08:00
|
|
|
TransportDescription(std::vector<std::string>(), kUfragVoice, kPwdVoice,
|
|
|
|
|
cricket::ICEMODE_FULL,
|
2018-12-18 15:55:30 -08:00
|
|
|
cricket::CONNECTIONROLE_NONE, &fingerprint)));
|
|
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
2016-01-28 13:24:37 -08:00
|
|
|
kVideoContentName,
|
2016-02-16 17:54:10 -08:00
|
|
|
TransportDescription(std::vector<std::string>(), kUfragVideo, kPwdVideo,
|
|
|
|
|
cricket::ICEMODE_FULL,
|
2018-12-18 15:55:30 -08:00
|
|
|
cricket::CONNECTIONROLE_NONE, &fingerprint)));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2017-06-29 12:31:36 -07:00
|
|
|
void AddExtmap(bool encrypted) {
|
2020-02-28 11:54:40 +01:00
|
|
|
audio_desc_ = new AudioContentDescription(*audio_desc_);
|
|
|
|
|
video_desc_ = new VideoContentDescription(*video_desc_);
|
2017-06-29 12:31:36 -07:00
|
|
|
audio_desc_->AddRtpHeaderExtension(
|
|
|
|
|
RtpExtension(kExtmapUri, kExtmapId, encrypted));
|
|
|
|
|
video_desc_->AddRtpHeaderExtension(
|
|
|
|
|
RtpExtension(kExtmapUri, kExtmapId, encrypted));
|
2013-07-10 00:45:36 +00:00
|
|
|
desc_.RemoveContentByName(kAudioContentName);
|
|
|
|
|
desc_.RemoveContentByName(kVideoContentName);
|
2019-06-03 20:35:45 +02:00
|
|
|
desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(audio_desc_));
|
|
|
|
|
desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp,
|
|
|
|
|
absl::WrapUnique(video_desc_));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-11-04 13:52:31 +00:00
|
|
|
void RemoveCryptos() {
|
|
|
|
|
audio_desc_->set_cryptos(std::vector<CryptoParams>());
|
|
|
|
|
video_desc_->set_cryptos(std::vector<CryptoParams>());
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-03 11:16:33 -07:00
|
|
|
// Removes everything in StreamParams from the session description that is
|
|
|
|
|
// used for a=ssrc lines.
|
|
|
|
|
void RemoveSsrcSignalingFromStreamParams() {
|
2019-06-03 20:35:45 +02:00
|
|
|
for (cricket::ContentInfo& content_info :
|
|
|
|
|
jdesc_.description()->contents()) {
|
2018-04-03 11:16:33 -07:00
|
|
|
// With Unified Plan there should be one StreamParams per m= section.
|
|
|
|
|
StreamParams& stream =
|
|
|
|
|
content_info.media_description()->mutable_streams()[0];
|
|
|
|
|
stream.ssrcs.clear();
|
|
|
|
|
stream.ssrc_groups.clear();
|
|
|
|
|
stream.cname.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 10:25:28 -07:00
|
|
|
// Removes all a=ssrc lines from the SDP string, except for the
|
|
|
|
|
// "a=ssrc:... cname:..." lines.
|
|
|
|
|
void RemoveSsrcMsidLinesFromSdpString(std::string* sdp_string) {
|
|
|
|
|
const char kAttributeSsrc[] = "a=ssrc";
|
|
|
|
|
const char kAttributeCname[] = "cname";
|
|
|
|
|
size_t ssrc_line_pos = sdp_string->find(kAttributeSsrc);
|
|
|
|
|
while (ssrc_line_pos != std::string::npos) {
|
|
|
|
|
size_t beg_line_pos = sdp_string->rfind('\n', ssrc_line_pos);
|
|
|
|
|
size_t end_line_pos = sdp_string->find('\n', ssrc_line_pos);
|
|
|
|
|
size_t cname_pos = sdp_string->find(kAttributeCname, ssrc_line_pos);
|
|
|
|
|
if (cname_pos == std::string::npos || cname_pos > end_line_pos) {
|
|
|
|
|
// Only erase a=ssrc lines that don't contain "cname".
|
|
|
|
|
sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
|
|
|
|
|
ssrc_line_pos = sdp_string->find(kAttributeSsrc, beg_line_pos);
|
|
|
|
|
} else {
|
|
|
|
|
// Skip the "a=ssrc:... cname" line and find the next "a=ssrc" line.
|
|
|
|
|
ssrc_line_pos = sdp_string->find(kAttributeSsrc, end_line_pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-03 11:16:33 -07:00
|
|
|
// Removes all a=ssrc lines from the SDP string.
|
|
|
|
|
void RemoveSsrcLinesFromSdpString(std::string* sdp_string) {
|
|
|
|
|
const char kAttributeSsrc[] = "a=ssrc";
|
|
|
|
|
while (sdp_string->find(kAttributeSsrc) != std::string::npos) {
|
|
|
|
|
size_t pos_ssrc_attribute = sdp_string->find(kAttributeSsrc);
|
|
|
|
|
size_t beg_line_pos = sdp_string->rfind('\n', pos_ssrc_attribute);
|
|
|
|
|
size_t end_line_pos = sdp_string->find('\n', pos_ssrc_attribute);
|
|
|
|
|
sdp_string->erase(beg_line_pos, end_line_pos - beg_line_pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-28 14:57:10 -08:00
|
|
|
bool TestSerializeDirection(RtpTransceiverDirection direction) {
|
2013-07-10 00:45:36 +00:00
|
|
|
audio_desc_->set_direction(direction);
|
|
|
|
|
video_desc_->set_direction(direction);
|
|
|
|
|
std::string new_sdp = kSdpFullString;
|
|
|
|
|
ReplaceDirection(direction, &new_sdp);
|
|
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
if (!jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version())) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_EQ(new_sdp, message);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestSerializeRejected(bool audio_rejected, bool video_rejected) {
|
2020-02-28 11:54:40 +01:00
|
|
|
audio_desc_ = new AudioContentDescription(*audio_desc_);
|
|
|
|
|
video_desc_ = new VideoContentDescription(*video_desc_);
|
2017-03-21 11:04:53 -07:00
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
desc_.RemoveContentByName(kAudioContentName);
|
|
|
|
|
desc_.RemoveContentByName(kVideoContentName);
|
2017-12-20 16:34:00 -08:00
|
|
|
desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
|
2019-06-03 20:35:45 +02:00
|
|
|
absl::WrapUnique(audio_desc_));
|
2017-12-20 16:34:00 -08:00
|
|
|
desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
|
2019-06-03 20:35:45 +02:00
|
|
|
absl::WrapUnique(video_desc_));
|
2016-02-16 17:54:10 -08:00
|
|
|
SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
|
|
|
|
|
audio_rejected ? "" : kPwdVoice);
|
|
|
|
|
SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
|
|
|
|
|
video_rejected ? "" : kPwdVideo);
|
2015-12-28 15:17:14 -08:00
|
|
|
|
|
|
|
|
std::string new_sdp = kSdpString;
|
2013-07-10 00:45:36 +00:00
|
|
|
ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_no_candidates(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_EQ(new_sdp, message);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 19:48:38 -08:00
|
|
|
void AddSctpDataChannel(bool use_sctpmap) {
|
2019-05-13 13:36:16 +02:00
|
|
|
std::unique_ptr<SctpDataContentDescription> data(
|
|
|
|
|
new SctpDataContentDescription());
|
|
|
|
|
sctp_desc_ = data.get();
|
|
|
|
|
sctp_desc_->set_use_sctpmap(use_sctpmap);
|
2019-05-31 10:17:38 +00:00
|
|
|
sctp_desc_->set_protocol(cricket::kMediaProtocolUdpDtlsSctp);
|
2019-05-13 13:36:16 +02:00
|
|
|
sctp_desc_->set_port(kDefaultSctpPort);
|
2017-12-20 16:34:00 -08:00
|
|
|
desc_.AddContent(kDataContentName, MediaProtocolType::kSctp,
|
2019-06-03 20:35:45 +02:00
|
|
|
std::move(data));
|
2018-12-18 15:55:30 -08:00
|
|
|
desc_.AddTransportInfo(TransportInfo(
|
|
|
|
|
kDataContentName, TransportDescription(kUfragData, kPwdData)));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2017-11-28 14:57:10 -08:00
|
|
|
bool TestDeserializeDirection(RtpTransceiverDirection direction) {
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string new_sdp = kSdpFullString;
|
|
|
|
|
ReplaceDirection(direction, &new_sdp);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription new_jdesc(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
|
|
|
|
|
|
|
|
|
|
audio_desc_->set_direction(direction);
|
|
|
|
|
video_desc_->set_direction(direction);
|
2019-04-12 07:01:29 +02:00
|
|
|
if (!jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version())) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestDeserializeRejected(bool audio_rejected, bool video_rejected) {
|
2015-12-28 15:17:14 -08:00
|
|
|
std::string new_sdp = kSdpString;
|
2013-07-10 00:45:36 +00:00
|
|
|
ReplaceRejected(audio_rejected, video_rejected, &new_sdp);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription new_jdesc(SdpType::kOffer);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_TRUE(SdpDeserialize(new_sdp, &new_jdesc));
|
2015-12-28 15:17:14 -08:00
|
|
|
|
2020-02-28 11:54:40 +01:00
|
|
|
audio_desc_ = new AudioContentDescription(*audio_desc_);
|
|
|
|
|
video_desc_ = new VideoContentDescription(*video_desc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
desc_.RemoveContentByName(kAudioContentName);
|
|
|
|
|
desc_.RemoveContentByName(kVideoContentName);
|
2017-12-20 16:34:00 -08:00
|
|
|
desc_.AddContent(kAudioContentName, MediaProtocolType::kRtp, audio_rejected,
|
2019-06-03 20:35:45 +02:00
|
|
|
absl::WrapUnique(audio_desc_));
|
2017-12-20 16:34:00 -08:00
|
|
|
desc_.AddContent(kVideoContentName, MediaProtocolType::kRtp, video_rejected,
|
2019-06-03 20:35:45 +02:00
|
|
|
absl::WrapUnique(video_desc_));
|
2016-02-16 17:54:10 -08:00
|
|
|
SetIceUfragPwd(kAudioContentName, audio_rejected ? "" : kUfragVoice,
|
|
|
|
|
audio_rejected ? "" : kPwdVoice);
|
|
|
|
|
SetIceUfragPwd(kVideoContentName, video_rejected ? "" : kUfragVideo,
|
|
|
|
|
video_rejected ? "" : kPwdVideo);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_no_candidates(kDummyType);
|
2019-04-12 07:01:29 +02:00
|
|
|
if (!jdesc_no_candidates.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2015-12-28 15:17:14 -08:00
|
|
|
jdesc_.session_version())) {
|
2013-07-10 00:45:36 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2015-12-28 15:17:14 -08:00
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
|
2013-07-10 00:45:36 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-29 12:31:36 -07:00
|
|
|
void TestDeserializeExtmap(bool session_level,
|
|
|
|
|
bool media_level,
|
|
|
|
|
bool encrypted) {
|
|
|
|
|
AddExtmap(encrypted);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription new_jdesc(SdpType::kOffer);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(new_jdesc.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_extmap(SdpType::kOffer);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_extmap = kSdpString;
|
|
|
|
|
if (session_level) {
|
2017-06-29 12:31:36 -07:00
|
|
|
InjectAfter(kSessionTime,
|
|
|
|
|
encrypted ? kExtmapWithDirectionAndAttributeEncrypted
|
|
|
|
|
: kExtmapWithDirectionAndAttribute,
|
2013-07-10 00:45:36 +00:00
|
|
|
&sdp_with_extmap);
|
|
|
|
|
}
|
|
|
|
|
if (media_level) {
|
2017-06-29 12:31:36 -07:00
|
|
|
InjectAfter(kAttributeIcePwdVoice,
|
|
|
|
|
encrypted ? kExtmapWithDirectionAndAttributeEncrypted
|
|
|
|
|
: kExtmapWithDirectionAndAttribute,
|
2013-07-10 00:45:36 +00:00
|
|
|
&sdp_with_extmap);
|
2017-06-29 12:31:36 -07:00
|
|
|
InjectAfter(kAttributeIcePwdVideo,
|
|
|
|
|
encrypted ? kExtmapWithDirectionAndAttributeEncrypted
|
|
|
|
|
: kExtmapWithDirectionAndAttribute,
|
2013-07-10 00:45:36 +00:00
|
|
|
&sdp_with_extmap);
|
|
|
|
|
}
|
|
|
|
|
// The extmap can't be present at the same time in both session level and
|
|
|
|
|
// media level.
|
|
|
|
|
if (session_level && media_level) {
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_FALSE(
|
|
|
|
|
webrtc::SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap, &error));
|
|
|
|
|
EXPECT_NE(std::string::npos, error.description.find("a=extmap"));
|
|
|
|
|
} else {
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_extmap, &jdesc_with_extmap));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_with_extmap, new_jdesc));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VerifyCodecParameter(const cricket::CodecParameterMap& params,
|
|
|
|
|
const std::string& name,
|
|
|
|
|
int expected_value) {
|
|
|
|
|
cricket::CodecParameterMap::const_iterator found = params.find(name);
|
|
|
|
|
ASSERT_TRUE(found != params.end());
|
2018-07-05 11:59:48 +02:00
|
|
|
EXPECT_EQ(found->second, rtc::ToString(expected_value));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestDeserializeCodecParams(const CodecParams& params,
|
|
|
|
|
JsepSessionDescription* jdesc_output) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
// Include semantics for WebRTC Media Streams since it is supported by
|
|
|
|
|
// this parser, and will be added to the SDP when serializing a session
|
|
|
|
|
// description.
|
|
|
|
|
"a=msid-semantic: WMS\r\n"
|
|
|
|
|
// Pl type 111 preferred.
|
2020-07-01 21:07:32 +02:00
|
|
|
"m=audio 9 RTP/SAVPF 111 104 103 105\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
// Pltype 111 listed before 103 and 104 in the map.
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
// Pltype 103 listed before 104.
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n"
|
2015-02-17 12:36:41 +00:00
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
2020-07-01 21:07:32 +02:00
|
|
|
"a=rtpmap:105 telephone-event/8000\r\n"
|
|
|
|
|
"a=fmtp:105 0-15,66,70\r\n"
|
2013-08-12 21:18:15 +00:00
|
|
|
"a=fmtp:111 ";
|
2013-07-10 00:45:36 +00:00
|
|
|
std::ostringstream os;
|
2015-05-15 13:14:24 -07:00
|
|
|
os << "minptime=" << params.min_ptime << "; stereo=" << params.stereo
|
2013-08-12 21:18:15 +00:00
|
|
|
<< "; sprop-stereo=" << params.sprop_stereo
|
|
|
|
|
<< "; useinbandfec=" << params.useinband
|
2020-01-14 12:11:31 +01:00
|
|
|
<< "; maxaveragebitrate=" << params.maxaveragebitrate
|
|
|
|
|
<< "\r\n"
|
|
|
|
|
"a=ptime:"
|
|
|
|
|
<< params.ptime
|
|
|
|
|
<< "\r\n"
|
|
|
|
|
"a=maxptime:"
|
|
|
|
|
<< params.max_ptime << "\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
sdp += os.str();
|
|
|
|
|
|
2014-06-09 12:51:39 +00:00
|
|
|
os.clear();
|
|
|
|
|
os.str("");
|
|
|
|
|
// Pl type 100 preferred.
|
2021-03-11 15:28:00 +01:00
|
|
|
os << "m=video 9 RTP/SAVPF 99 95 96\r\n"
|
|
|
|
|
"a=rtpmap:96 VP9/90000\r\n" // out-of-order wrt the m= line.
|
2020-01-14 12:11:31 +01:00
|
|
|
"a=rtpmap:99 VP8/90000\r\n"
|
|
|
|
|
"a=rtpmap:95 RTX/90000\r\n"
|
|
|
|
|
"a=fmtp:95 apt=99;\r\n";
|
2014-06-09 12:51:39 +00:00
|
|
|
sdp += os.str();
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// Deserialize
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
|
|
|
|
|
|
|
|
|
|
const AudioContentDescription* acd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstAudioContentDescription(jdesc_output->description());
|
|
|
|
|
ASSERT_TRUE(acd);
|
2013-07-10 00:45:36 +00:00
|
|
|
ASSERT_FALSE(acd->codecs().empty());
|
|
|
|
|
cricket::AudioCodec opus = acd->codecs()[0];
|
|
|
|
|
EXPECT_EQ("opus", opus.name);
|
|
|
|
|
EXPECT_EQ(111, opus.id);
|
|
|
|
|
VerifyCodecParameter(opus.params, "minptime", params.min_ptime);
|
|
|
|
|
VerifyCodecParameter(opus.params, "stereo", params.stereo);
|
|
|
|
|
VerifyCodecParameter(opus.params, "sprop-stereo", params.sprop_stereo);
|
|
|
|
|
VerifyCodecParameter(opus.params, "useinbandfec", params.useinband);
|
2013-07-26 19:17:59 +00:00
|
|
|
VerifyCodecParameter(opus.params, "maxaveragebitrate",
|
|
|
|
|
params.maxaveragebitrate);
|
2013-07-10 00:45:36 +00:00
|
|
|
for (size_t i = 0; i < acd->codecs().size(); ++i) {
|
|
|
|
|
cricket::AudioCodec codec = acd->codecs()[i];
|
|
|
|
|
VerifyCodecParameter(codec.params, "ptime", params.ptime);
|
|
|
|
|
VerifyCodecParameter(codec.params, "maxptime", params.max_ptime);
|
|
|
|
|
}
|
2014-06-09 12:51:39 +00:00
|
|
|
|
2020-07-01 21:07:32 +02:00
|
|
|
cricket::AudioCodec dtmf = acd->codecs()[3];
|
|
|
|
|
EXPECT_EQ("telephone-event", dtmf.name);
|
|
|
|
|
EXPECT_EQ(105, dtmf.id);
|
|
|
|
|
EXPECT_EQ(3u,
|
|
|
|
|
dtmf.params.size()); // ptime and max_ptime count as parameters.
|
|
|
|
|
EXPECT_EQ(dtmf.params.begin()->first, "");
|
|
|
|
|
EXPECT_EQ(dtmf.params.begin()->second, "0-15,66,70");
|
|
|
|
|
|
2014-06-09 12:51:39 +00:00
|
|
|
const VideoContentDescription* vcd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstVideoContentDescription(jdesc_output->description());
|
|
|
|
|
ASSERT_TRUE(vcd);
|
2014-06-09 12:51:39 +00:00
|
|
|
ASSERT_FALSE(vcd->codecs().empty());
|
|
|
|
|
cricket::VideoCodec vp8 = vcd->codecs()[0];
|
|
|
|
|
EXPECT_EQ("VP8", vp8.name);
|
|
|
|
|
EXPECT_EQ(99, vp8.id);
|
|
|
|
|
cricket::VideoCodec rtx = vcd->codecs()[1];
|
|
|
|
|
EXPECT_EQ("RTX", rtx.name);
|
|
|
|
|
EXPECT_EQ(95, rtx.id);
|
|
|
|
|
VerifyCodecParameter(rtx.params, "apt", vp8.id);
|
2021-03-11 15:28:00 +01:00
|
|
|
// VP9 is listed last in the m= line so should come after VP8 and RTX.
|
|
|
|
|
cricket::VideoCodec vp9 = vcd->codecs()[2];
|
|
|
|
|
EXPECT_EQ("VP9", vp9.name);
|
|
|
|
|
EXPECT_EQ(96, vp9.id);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestDeserializeRtcpFb(JsepSessionDescription* jdesc_output,
|
|
|
|
|
bool use_wildcard) {
|
2015-02-18 21:37:46 +00:00
|
|
|
std::string sdp_session_and_audio =
|
2013-07-10 00:45:36 +00:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
// Include semantics for WebRTC Media Streams since it is supported by
|
|
|
|
|
// this parser, and will be added to the SDP when serializing a session
|
|
|
|
|
// description.
|
|
|
|
|
"a=msid-semantic: WMS\r\n"
|
2014-10-23 23:37:22 +00:00
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
2015-02-18 21:37:46 +00:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n";
|
|
|
|
|
std::string sdp_video =
|
2013-07-10 00:45:36 +00:00
|
|
|
"m=video 3457 RTP/SAVPF 101\r\n"
|
|
|
|
|
"a=rtpmap:101 VP8/90000\r\n"
|
2019-05-24 13:40:02 +02:00
|
|
|
"a=rtcp-fb:101 goog-lntf\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=rtcp-fb:101 nack\r\n"
|
2014-01-14 10:00:58 +00:00
|
|
|
"a=rtcp-fb:101 nack pli\r\n"
|
2015-02-18 21:37:46 +00:00
|
|
|
"a=rtcp-fb:101 goog-remb\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
std::ostringstream os;
|
2015-02-18 21:37:46 +00:00
|
|
|
os << sdp_session_and_audio;
|
|
|
|
|
os << "a=rtcp-fb:" << (use_wildcard ? "*" : "111") << " nack\r\n";
|
|
|
|
|
os << sdp_video;
|
2013-07-10 00:45:36 +00:00
|
|
|
os << "a=rtcp-fb:" << (use_wildcard ? "*" : "101") << " ccm fir\r\n";
|
2015-02-18 21:37:46 +00:00
|
|
|
std::string sdp = os.str();
|
2013-07-10 00:45:36 +00:00
|
|
|
// Deserialize
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, jdesc_output, &error));
|
|
|
|
|
const AudioContentDescription* acd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstAudioContentDescription(jdesc_output->description());
|
|
|
|
|
ASSERT_TRUE(acd);
|
2013-07-10 00:45:36 +00:00
|
|
|
ASSERT_FALSE(acd->codecs().empty());
|
|
|
|
|
cricket::AudioCodec opus = acd->codecs()[0];
|
|
|
|
|
EXPECT_EQ(111, opus.id);
|
|
|
|
|
EXPECT_TRUE(opus.HasFeedbackParam(cricket::FeedbackParam(
|
|
|
|
|
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
|
|
|
|
|
|
|
|
|
const VideoContentDescription* vcd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstVideoContentDescription(jdesc_output->description());
|
|
|
|
|
ASSERT_TRUE(vcd);
|
2013-07-10 00:45:36 +00:00
|
|
|
ASSERT_FALSE(vcd->codecs().empty());
|
|
|
|
|
cricket::VideoCodec vp8 = vcd->codecs()[0];
|
|
|
|
|
EXPECT_STREQ(webrtc::JsepSessionDescription::kDefaultVideoCodecName,
|
|
|
|
|
vp8.name.c_str());
|
|
|
|
|
EXPECT_EQ(101, vp8.id);
|
|
|
|
|
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
2019-05-24 13:40:02 +02:00
|
|
|
cricket::kRtcpFbParamLntf, cricket::kParamValueEmpty)));
|
|
|
|
|
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
2013-07-10 00:45:36 +00:00
|
|
|
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
2014-01-14 10:00:58 +00:00
|
|
|
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
|
|
|
|
cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)));
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
|
|
|
|
cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)));
|
|
|
|
|
EXPECT_TRUE(vp8.HasFeedbackParam(cricket::FeedbackParam(
|
|
|
|
|
cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Two SDP messages can mean the same thing but be different strings, e.g.
|
|
|
|
|
// some of the lines can be serialized in different order.
|
|
|
|
|
// However, a deserialized description can be compared field by field and has
|
|
|
|
|
// no order. If deserializer has already been tested, serializing then
|
|
|
|
|
// deserializing and comparing JsepSessionDescription will test
|
|
|
|
|
// the serializer sufficiently.
|
2018-02-01 12:22:16 -08:00
|
|
|
void TestSerialize(const JsepSessionDescription& jdesc) {
|
|
|
|
|
std::string message = webrtc::SdpSerialize(jdesc);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output_des(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(message, &jdesc_output_des, &error));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output_des));
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-21 11:04:53 -07:00
|
|
|
// Calling 'Initialize' with a copy of the inner SessionDescription will
|
|
|
|
|
// create a copy of the JsepSessionDescription without candidates. The
|
|
|
|
|
// 'connection address' field, previously set from the candidates, must also
|
|
|
|
|
// be reset.
|
|
|
|
|
void MakeDescriptionWithoutCandidates(JsepSessionDescription* jdesc) {
|
|
|
|
|
rtc::SocketAddress audio_addr("0.0.0.0", 9);
|
|
|
|
|
rtc::SocketAddress video_addr("0.0.0.0", 9);
|
|
|
|
|
audio_desc_->set_connection_address(audio_addr);
|
|
|
|
|
video_desc_->set_connection_address(video_addr);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc->Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
2017-03-21 11:04:53 -07:00
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
protected:
|
|
|
|
|
SessionDescription desc_;
|
|
|
|
|
AudioContentDescription* audio_desc_;
|
|
|
|
|
VideoContentDescription* video_desc_;
|
2019-05-13 13:36:16 +02:00
|
|
|
SctpDataContentDescription* sctp_desc_;
|
2013-07-10 00:45:36 +00:00
|
|
|
Candidates candidates_;
|
2016-04-27 06:47:29 -07:00
|
|
|
std::unique_ptr<IceCandidateInterface> jcandidate_;
|
2013-07-10 00:45:36 +00:00
|
|
|
JsepSessionDescription jdesc_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void TestMismatch(const std::string& string1, const std::string& string2) {
|
|
|
|
|
int position = 0;
|
|
|
|
|
for (size_t i = 0; i < string1.length() && i < string2.length(); ++i) {
|
|
|
|
|
if (string1.c_str()[i] != string2.c_str()[i]) {
|
2013-07-22 21:07:49 +00:00
|
|
|
position = static_cast<int>(i);
|
2013-07-10 00:45:36 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(0, position) << "Strings mismatch at the " << position
|
|
|
|
|
<< " character\n"
|
2020-01-14 12:11:31 +01:00
|
|
|
" 1: "
|
|
|
|
|
<< string1.substr(position, 20)
|
|
|
|
|
<< "\n"
|
|
|
|
|
" 2: "
|
|
|
|
|
<< string2.substr(position, 20) << "\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescription) {
|
|
|
|
|
// SessionDescription with desc and candidates.
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
TestMismatch(std::string(kSdpFullString), message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionEmpty) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_empty(kDummyType);
|
2018-02-01 12:22:16 -08:00
|
|
|
EXPECT_EQ("", webrtc::SdpSerialize(jdesc_empty));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-11-04 13:52:31 +00:00
|
|
|
// This tests serialization of SDP with a=crypto and a=fingerprint, as would be
|
2013-07-10 00:45:36 +00:00
|
|
|
// the case in a DTLS offer.
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprint) {
|
|
|
|
|
AddFingerprint();
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_fingerprint(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
std::string sdp_with_fingerprint = kSdpString;
|
|
|
|
|
InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
|
|
|
|
|
InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(sdp_with_fingerprint, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This tests serialization of SDP with a=fingerprint with no a=crypto, as would
|
|
|
|
|
// be the case in a DTLS answer.
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithFingerprintNoCryptos) {
|
|
|
|
|
AddFingerprint();
|
2021-11-04 13:52:31 +00:00
|
|
|
RemoveCryptos();
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_fingerprint(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
MakeDescriptionWithoutCandidates(&jdesc_with_fingerprint);
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_with_fingerprint);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
std::string sdp_with_fingerprint = kSdpString;
|
|
|
|
|
Replace(kAttributeCryptoVoice, "", &sdp_with_fingerprint);
|
|
|
|
|
Replace(kAttributeCryptoVideo, "", &sdp_with_fingerprint);
|
|
|
|
|
InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
|
|
|
|
|
InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(sdp_with_fingerprint, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithoutCandidates) {
|
|
|
|
|
// JsepSessionDescription with desc but without candidates.
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_no_candidates(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
MakeDescriptionWithoutCandidates(&jdesc_no_candidates);
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_no_candidates);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_EQ(std::string(kSdpString), message);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-26 21:04:26 +02:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBundles) {
|
|
|
|
|
ContentGroup group1(cricket::GROUP_TYPE_BUNDLE);
|
|
|
|
|
group1.AddContentName(kAudioContentName);
|
|
|
|
|
group1.AddContentName(kVideoContentName);
|
|
|
|
|
desc_.AddGroup(group1);
|
|
|
|
|
ContentGroup group2(cricket::GROUP_TYPE_BUNDLE);
|
|
|
|
|
group2.AddContentName(kAudioContentName2);
|
|
|
|
|
desc_.AddGroup(group2);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_bundle = kSdpFullString;
|
|
|
|
|
InjectAfter(kSessionTime,
|
2021-04-26 21:04:26 +02:00
|
|
|
"a=group:BUNDLE audio_content_name video_content_name\r\n"
|
|
|
|
|
"a=group:BUNDLE audio_content_name_2\r\n",
|
2013-07-10 00:45:36 +00:00
|
|
|
&sdp_with_bundle);
|
|
|
|
|
EXPECT_EQ(sdp_with_bundle, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithBandwidth) {
|
2017-12-21 15:14:30 -08:00
|
|
|
VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
|
2020-07-27 15:52:02 -07:00
|
|
|
vcd->set_bandwidth(100 * 1000 + 755); // Integer division will drop the 755.
|
|
|
|
|
vcd->set_bandwidth_type("AS");
|
2017-12-21 15:14:30 -08:00
|
|
|
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
|
2020-07-27 15:52:02 -07:00
|
|
|
acd->set_bandwidth(555);
|
|
|
|
|
acd->set_bandwidth_type("TIAS");
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_bandwidth = kSdpFullString;
|
2014-07-16 21:03:13 +00:00
|
|
|
InjectAfter("c=IN IP4 74.125.224.39\r\n", "b=AS:100\r\n",
|
2013-07-10 00:45:36 +00:00
|
|
|
&sdp_with_bandwidth);
|
2020-07-27 15:52:02 -07:00
|
|
|
InjectAfter("c=IN IP4 74.125.127.126\r\n", "b=TIAS:555\r\n",
|
|
|
|
|
&sdp_with_bandwidth);
|
|
|
|
|
EXPECT_EQ(sdp_with_bandwidth, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Should default to b=AS if bandwidth_type isn't set.
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithMissingBandwidthType) {
|
|
|
|
|
VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
|
|
|
|
|
vcd->set_bandwidth(100 * 1000);
|
|
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
|
|
|
|
jdesc_.session_version()));
|
|
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
|
|
|
|
std::string sdp_with_bandwidth = kSdpFullString;
|
|
|
|
|
InjectAfter("c=IN IP4 74.125.224.39\r\n", "b=AS:100\r\n",
|
2013-07-10 00:45:36 +00:00
|
|
|
&sdp_with_bandwidth);
|
|
|
|
|
EXPECT_EQ(sdp_with_bandwidth, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithIceOptions) {
|
|
|
|
|
std::vector<std::string> transport_options;
|
|
|
|
|
transport_options.push_back(kIceOption1);
|
|
|
|
|
transport_options.push_back(kIceOption3);
|
|
|
|
|
AddIceOptions(kAudioContentName, transport_options);
|
|
|
|
|
transport_options.clear();
|
|
|
|
|
transport_options.push_back(kIceOption2);
|
|
|
|
|
transport_options.push_back(kIceOption3);
|
|
|
|
|
AddIceOptions(kVideoContentName, transport_options);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_ice_options = kSdpFullString;
|
|
|
|
|
InjectAfter(kAttributeIcePwdVoice, "a=ice-options:iceoption1 iceoption3\r\n",
|
|
|
|
|
&sdp_with_ice_options);
|
|
|
|
|
InjectAfter(kAttributeIcePwdVideo, "a=ice-options:iceoption2 iceoption3\r\n",
|
|
|
|
|
&sdp_with_ice_options);
|
|
|
|
|
EXPECT_EQ(sdp_with_ice_options, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
|
2017-11-28 14:57:10 -08:00
|
|
|
EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kRecvOnly));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
|
2017-11-28 14:57:10 -08:00
|
|
|
EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kSendOnly));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
|
2017-11-28 14:57:10 -08:00
|
|
|
EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kInactive));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
|
|
|
|
|
EXPECT_TRUE(TestSerializeRejected(true, false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithVideoRejected) {
|
|
|
|
|
EXPECT_TRUE(TestSerializeRejected(false, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
|
|
|
|
|
EXPECT_TRUE(TestSerializeRejected(true, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
|
2017-02-17 19:48:38 -08:00
|
|
|
bool use_sctpmap = true;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2017-03-21 11:04:53 -07:00
|
|
|
MakeDescriptionWithoutCandidates(&jsep_desc);
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jsep_desc);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
std::string expected_sdp = kSdpString;
|
|
|
|
|
expected_sdp.append(kSdpSctpDataChannelString);
|
|
|
|
|
EXPECT_EQ(message, expected_sdp);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 13:36:16 +02:00
|
|
|
void MutateJsepSctpPort(JsepSessionDescription* jdesc,
|
|
|
|
|
const SessionDescription& desc,
|
|
|
|
|
int port) {
|
|
|
|
|
// Take our pre-built session description and change the SCTP port.
|
|
|
|
|
std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
|
|
|
|
|
SctpDataContentDescription* dcdesc =
|
|
|
|
|
mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
|
|
|
|
|
dcdesc->set_port(port);
|
|
|
|
|
ASSERT_TRUE(
|
|
|
|
|
jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion));
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-01 18:30:30 +00:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
|
2017-02-17 19:48:38 -08:00
|
|
|
bool use_sctpmap = true;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
MakeDescriptionWithoutCandidates(&jsep_desc);
|
2014-05-01 18:30:30 +00:00
|
|
|
|
|
|
|
|
const int kNewPort = 1234;
|
2019-05-13 13:36:16 +02:00
|
|
|
MutateJsepSctpPort(&jsep_desc, desc_, kNewPort);
|
2014-05-01 18:30:30 +00:00
|
|
|
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jsep_desc);
|
2014-05-01 18:30:30 +00:00
|
|
|
|
|
|
|
|
std::string expected_sdp = kSdpString;
|
|
|
|
|
expected_sdp.append(kSdpSctpDataChannelString);
|
|
|
|
|
|
2019-02-14 15:13:09 -08:00
|
|
|
absl::StrReplaceAll(
|
|
|
|
|
{{rtc::ToString(kDefaultSctpPort), rtc::ToString(kNewPort)}},
|
|
|
|
|
&expected_sdp);
|
2014-05-01 18:30:30 +00:00
|
|
|
|
|
|
|
|
EXPECT_EQ(expected_sdp, message);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-10 22:33:20 +02:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapAllowMixed) {
|
2018-10-23 10:17:39 +02:00
|
|
|
jdesc_.description()->set_extmap_allow_mixed(true);
|
2018-10-10 22:33:20 +02:00
|
|
|
TestSerialize(jdesc_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeMediaContentDescriptionWithExtmapAllowMixed) {
|
|
|
|
|
cricket::MediaContentDescription* video_desc =
|
|
|
|
|
jdesc_.description()->GetContentDescriptionByName(kVideoContentName);
|
|
|
|
|
ASSERT_TRUE(video_desc);
|
|
|
|
|
cricket::MediaContentDescription* audio_desc =
|
|
|
|
|
jdesc_.description()->GetContentDescriptionByName(kAudioContentName);
|
|
|
|
|
ASSERT_TRUE(audio_desc);
|
2018-10-23 10:17:39 +02:00
|
|
|
video_desc->set_extmap_allow_mixed_enum(
|
2018-10-10 22:33:20 +02:00
|
|
|
cricket::MediaContentDescription::kMedia);
|
2018-10-23 10:17:39 +02:00
|
|
|
audio_desc->set_extmap_allow_mixed_enum(
|
2018-10-10 22:33:20 +02:00
|
|
|
cricket::MediaContentDescription::kMedia);
|
|
|
|
|
TestSerialize(jdesc_);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmap) {
|
2017-06-29 12:31:36 -07:00
|
|
|
bool encrypted = false;
|
|
|
|
|
AddExtmap(encrypted);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription desc_with_extmap(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
MakeDescriptionWithoutCandidates(&desc_with_extmap);
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(desc_with_extmap);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
std::string sdp_with_extmap = kSdpString;
|
|
|
|
|
InjectAfter("a=mid:audio_content_name\r\n", kExtmap, &sdp_with_extmap);
|
|
|
|
|
InjectAfter("a=mid:video_content_name\r\n", kExtmap, &sdp_with_extmap);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(sdp_with_extmap, message);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-29 12:31:36 -07:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapEncrypted) {
|
|
|
|
|
bool encrypted = true;
|
|
|
|
|
AddExtmap(encrypted);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription desc_with_extmap(kDummyType);
|
2017-06-29 12:31:36 -07:00
|
|
|
ASSERT_TRUE(
|
2019-04-12 07:01:29 +02:00
|
|
|
desc_with_extmap.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
2018-02-01 12:22:16 -08:00
|
|
|
TestSerialize(desc_with_extmap);
|
2017-06-29 12:31:36 -07:00
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeCandidates) {
|
|
|
|
|
std::string message = webrtc::SdpSerializeCandidate(*jcandidate_);
|
2014-06-24 17:05:10 +00:00
|
|
|
EXPECT_EQ(std::string(kRawCandidate), message);
|
2015-12-16 18:37:23 -08:00
|
|
|
|
|
|
|
|
Candidate candidate_with_ufrag(candidates_.front());
|
|
|
|
|
candidate_with_ufrag.set_username("ABC");
|
|
|
|
|
jcandidate_.reset(new JsepIceCandidate(std::string("audio_content_name"), 0,
|
|
|
|
|
candidate_with_ufrag));
|
|
|
|
|
message = webrtc::SdpSerializeCandidate(*jcandidate_);
|
|
|
|
|
EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message);
|
2016-03-23 16:07:48 -07:00
|
|
|
|
|
|
|
|
Candidate candidate_with_network_info(candidates_.front());
|
|
|
|
|
candidate_with_network_info.set_network_id(1);
|
|
|
|
|
jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
|
|
|
|
|
candidate_with_network_info));
|
|
|
|
|
message = webrtc::SdpSerializeCandidate(*jcandidate_);
|
|
|
|
|
EXPECT_EQ(std::string(kRawCandidate) + " network-id 1", message);
|
|
|
|
|
candidate_with_network_info.set_network_cost(999);
|
|
|
|
|
jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
|
|
|
|
|
candidate_with_network_info));
|
|
|
|
|
message = webrtc::SdpSerializeCandidate(*jcandidate_);
|
|
|
|
|
EXPECT_EQ(std::string(kRawCandidate) + " network-id 1 network-cost 999",
|
|
|
|
|
message);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2018-08-09 01:16:13 -07:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeHostnameCandidate) {
|
|
|
|
|
rtc::SocketAddress address("a.test", 1234);
|
|
|
|
|
cricket::Candidate candidate(
|
|
|
|
|
cricket::ICE_CANDIDATE_COMPONENT_RTP, "udp", address, kCandidatePriority,
|
|
|
|
|
"", "", LOCAL_PORT_TYPE, kCandidateGeneration, kCandidateFoundation1);
|
|
|
|
|
JsepIceCandidate jcandidate(std::string("audio_content_name"), 0, candidate);
|
|
|
|
|
std::string message = webrtc::SdpSerializeCandidate(jcandidate);
|
|
|
|
|
EXPECT_EQ(std::string(kRawHostnameCandidate), message);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-13 06:05:55 +00:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeTcpCandidates) {
|
2015-01-15 06:53:07 +00:00
|
|
|
Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
|
2014-12-16 23:01:31 +00:00
|
|
|
rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
|
|
|
|
|
"", "", LOCAL_PORT_TYPE, kCandidateGeneration,
|
|
|
|
|
kCandidateFoundation1);
|
2014-08-08 22:29:20 +00:00
|
|
|
candidate.set_tcptype(cricket::TCPTYPE_ACTIVE_STR);
|
2016-04-27 06:47:29 -07:00
|
|
|
std::unique_ptr<IceCandidateInterface> jcandidate(
|
|
|
|
|
new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
|
2014-08-08 22:29:20 +00:00
|
|
|
|
|
|
|
|
std::string message = webrtc::SdpSerializeCandidate(*jcandidate);
|
|
|
|
|
EXPECT_EQ(std::string(kSdpTcpActiveCandidate), message);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 12:36:38 -07:00
|
|
|
// Test serializing a TCP candidate that came in with a missing tcptype. This
|
|
|
|
|
// shouldn't happen according to the spec, but our implementation has been
|
|
|
|
|
// accepting this for quite some time, treating it as a passive candidate.
|
|
|
|
|
//
|
|
|
|
|
// So, we should be able to at least convert such candidates to and from SDP.
|
|
|
|
|
// See: bugs.webrtc.org/11423
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseTcpCandidateWithoutTcptype) {
|
|
|
|
|
std::string missing_tcptype =
|
|
|
|
|
"candidate:a0+B/1 1 tcp 2130706432 192.168.1.5 9999 typ host";
|
|
|
|
|
JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(missing_tcptype, &jcandidate));
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(std::string(cricket::TCPTYPE_PASSIVE_STR),
|
|
|
|
|
jcandidate.candidate().tcptype());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseSslTcpCandidate) {
|
|
|
|
|
std::string ssltcp =
|
|
|
|
|
"candidate:a0+B/1 1 ssltcp 2130706432 192.168.1.5 9999 typ host tcptype "
|
|
|
|
|
"passive";
|
|
|
|
|
JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(ssltcp, &jcandidate));
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(std::string("ssltcp"), jcandidate.candidate().protocol());
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 10:29:17 -07:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithH264) {
|
Reland of Stop using hardcoded payload types for video codecs (patchset #1 id:1 of https://codereview.webrtc.org/2513633002/ )
Reason for revert:
The WebRtcBrowserTest.NegotiateUnsupportedVideoCodec test has been fixed in Chromium with the following change:
function removeVideoCodec(offerSdp) {
- offerSdp = offerSdp.replace('a=rtpmap:100 VP8/90000\r\n',
- 'a=rtpmap:100 XVP8/90000\r\n');
+ offerSdp = offerSdp.replace(/a=rtpmap:(\d+)\ VP8\/90000\r\n/,
+ 'a=rtpmap:$1 XVP8/90000\r\n');
return offerSdp;
}
Original issue's description:
> Revert of Stop using hardcoded payload types for video codecs (patchset #6 id:210001 of https://codereview.webrtc.org/2493133002/ )
>
> Reason for revert:
> Breaks chromium.fyi test:
> WebRtcBrowserTest.NegotiateUnsupportedVideoCodec
>
> Original issue's description:
> > Stop using hardcoded payload types for video codecs
> >
> > This CL stops using hardcoded payload types for different video codecs
> > and will dynamically assign them payload types incrementally from 96 to
> > 127 instead.
> >
> > This CL:
> > * Replaces 'std::vector<VideoCodec> DefaultVideoCodecList()' in
> > webrtcvideoengine2.cc with an explicit WebRtcVideoEncoderFactory for
> > internally supported software codecs instead. The purpose is to
> > streamline the payload type assignment in webrtcvideoengine2.cc which
> > will now have two encoder factories of the same
> > WebRtcVideoEncoderFactory type; one internal and one external.
> > * Removes webrtc::VideoEncoder::EncoderType and use cricket::VideoCodec
> > instead.
> > * Removes 'static VideoEncoder* Create(EncoderType codec_type)' and
> > moves the create function to the internal encoder factory instead.
> > * Removes video_encoder.cc. webrtc::VideoEncoder is now just an
> > interface without any static functions.
> > * The function GetSupportedCodecs in webrtcvideoengine2.cc unifies
> > the internal and external codecs and assigns them payload types
> > incrementally from 96 to 127.
> > * Updates webrtcvideoengine2_unittest.cc and removes assumptions about
> > what payload types will be used.
> >
> > BUG=webrtc:6677,webrtc:6705
> > R=hta@webrtc.org, ossu@webrtc.org, stefan@webrtc.org
> >
> > Committed: https://crrev.com/42043b95872b51321f508bf255d804ce3dff366b
> > Cr-Commit-Position: refs/heads/master@{#15135}
>
> TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:6677,webrtc:6705
>
> Committed: https://crrev.com/eacbaea920797ff751ca83050d140821f5055591
> Cr-Commit-Position: refs/heads/master@{#15140}
TBR=hta@webrtc.org,stefan@webrtc.org,ossu@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:6677,webrtc:6705
Review-Url: https://codereview.webrtc.org/2511933002
Cr-Commit-Position: refs/heads/master@{#15148}
2016-11-18 01:34:11 -08:00
|
|
|
cricket::VideoCodec h264_codec("H264");
|
|
|
|
|
h264_codec.SetParam("profile-level-id", "42e01f");
|
|
|
|
|
h264_codec.SetParam("level-asymmetry-allowed", "1");
|
|
|
|
|
h264_codec.SetParam("packetization-mode", "1");
|
|
|
|
|
video_desc_->AddCodec(h264_codec);
|
|
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
jdesc_.Initialize(desc_.Clone(), kSessionId, kSessionVersion);
|
2016-04-12 10:29:17 -07:00
|
|
|
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2016-04-12 10:29:17 -07:00
|
|
|
size_t after_pt = message.find(" H264/90000");
|
|
|
|
|
ASSERT_NE(after_pt, std::string::npos);
|
|
|
|
|
size_t before_pt = message.rfind("a=rtpmap:", after_pt);
|
|
|
|
|
ASSERT_NE(before_pt, std::string::npos);
|
|
|
|
|
before_pt += strlen("a=rtpmap:");
|
|
|
|
|
std::string pt = message.substr(before_pt, after_pt - before_pt);
|
2021-07-30 22:30:23 +02:00
|
|
|
// TODO(hta): Check if payload type `pt` occurs in the m=video line.
|
2016-04-12 10:29:17 -07:00
|
|
|
std::string to_find = "a=fmtp:" + pt + " ";
|
|
|
|
|
size_t fmtp_pos = message.find(to_find);
|
|
|
|
|
ASSERT_NE(std::string::npos, fmtp_pos) << "Failed to find " << to_find;
|
2019-01-28 11:43:52 +01:00
|
|
|
size_t fmtp_endpos = message.find('\n', fmtp_pos);
|
2016-04-12 10:29:17 -07:00
|
|
|
ASSERT_NE(std::string::npos, fmtp_endpos);
|
|
|
|
|
std::string fmtp_value = message.substr(fmtp_pos, fmtp_endpos);
|
|
|
|
|
EXPECT_NE(std::string::npos, fmtp_value.find("level-asymmetry-allowed=1"));
|
|
|
|
|
EXPECT_NE(std::string::npos, fmtp_value.find("packetization-mode=1"));
|
|
|
|
|
EXPECT_NE(std::string::npos, fmtp_value.find("profile-level-id=42e01f"));
|
2016-04-15 11:02:14 -07:00
|
|
|
// Check that there are no spaces after semicolons.
|
|
|
|
|
// https://bugs.webrtc.org/5793
|
|
|
|
|
EXPECT_EQ(std::string::npos, fmtp_value.find("; "));
|
2016-04-12 10:29:17 -07:00
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescription) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
// Deserialize
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpFullString, &jdesc));
|
|
|
|
|
// Verify
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-30 05:18:12 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutMline) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2013-10-30 05:18:12 +00:00
|
|
|
const char kSdpWithoutMline[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"a=msid-semantic: WMS local_stream_1 local_stream_2\r\n";
|
|
|
|
|
// Deserialize
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpWithoutMline, &jdesc));
|
|
|
|
|
EXPECT_EQ(0u, jdesc.description()->contents().size());
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCarriageReturn) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_without_carriage_return = kSdpFullString;
|
|
|
|
|
Replace("\r\n", "\n", &sdp_without_carriage_return);
|
|
|
|
|
// Deserialize
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_without_carriage_return, &jdesc));
|
|
|
|
|
// Verify
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCandidates) {
|
|
|
|
|
// SessionDescription with desc but without candidates.
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_no_candidates(kDummyType);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_no_candidates.Initialize(desc_.Clone(), kSessionId,
|
2013-07-10 00:45:36 +00:00
|
|
|
kSessionVersion));
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription new_jdesc(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpString, &new_jdesc));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_no_candidates, new_jdesc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmap) {
|
|
|
|
|
static const char kSdpNoRtpmapString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 11 22 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 49232 RTP/AVP 0 18 103\r\n"
|
|
|
|
|
// Codec that doesn't appear in the m= line will be ignored.
|
2015-02-17 12:36:41 +00:00
|
|
|
"a=rtpmap:104 ISAC/32000\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
// The rtpmap line for static payload codec is optional.
|
2022-05-31 16:51:23 +02:00
|
|
|
"a=rtpmap:18 G729/8000\r\n"
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=rtpmap:103 ISAC/16000\r\n";
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
|
|
|
|
|
cricket::AudioContentDescription* audio =
|
2018-12-18 15:55:30 -08:00
|
|
|
cricket::GetFirstAudioContentDescription(jdesc.description());
|
2013-07-10 00:45:36 +00:00
|
|
|
AudioCodecs ref_codecs;
|
2016-04-13 10:07:16 -07:00
|
|
|
// The codecs in the AudioContentDescription should be in the same order as
|
|
|
|
|
// the payload types (<fmt>s) on the m= line.
|
|
|
|
|
ref_codecs.push_back(AudioCodec(0, "PCMU", 8000, 0, 1));
|
2022-05-31 16:51:23 +02:00
|
|
|
ref_codecs.push_back(AudioCodec(18, "G729", 8000, 0, 1));
|
2017-01-23 08:55:48 -08:00
|
|
|
ref_codecs.push_back(AudioCodec(103, "ISAC", 16000, 0, 1));
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_EQ(ref_codecs, audio->codecs());
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 17:52:04 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutRtpmapButWithFmtp) {
|
|
|
|
|
static const char kSdpNoRtpmapString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 11 22 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 49232 RTP/AVP 18 103\r\n"
|
|
|
|
|
"a=fmtp:18 annexb=yes\r\n"
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n";
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2014-02-27 17:52:04 +00:00
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpNoRtpmapString, &jdesc));
|
|
|
|
|
cricket::AudioContentDescription* audio =
|
2018-12-18 15:55:30 -08:00
|
|
|
cricket::GetFirstAudioContentDescription(jdesc.description());
|
2014-02-27 17:52:04 +00:00
|
|
|
|
|
|
|
|
cricket::AudioCodec g729 = audio->codecs()[0];
|
|
|
|
|
EXPECT_EQ("G729", g729.name);
|
|
|
|
|
EXPECT_EQ(8000, g729.clockrate);
|
|
|
|
|
EXPECT_EQ(18, g729.id);
|
|
|
|
|
cricket::CodecParameterMap::iterator found = g729.params.find("annexb");
|
|
|
|
|
ASSERT_TRUE(found != g729.params.end());
|
|
|
|
|
EXPECT_EQ(found->second, "yes");
|
|
|
|
|
|
|
|
|
|
cricket::AudioCodec isac = audio->codecs()[1];
|
|
|
|
|
EXPECT_EQ("ISAC", isac.name);
|
|
|
|
|
EXPECT_EQ(103, isac.id);
|
|
|
|
|
EXPECT_EQ(16000, isac.clockrate);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// Ensure that we can deserialize SDP with a=fingerprint properly.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeJsepSessionDescriptionWithFingerprint) {
|
|
|
|
|
// Add a DTLS a=fingerprint attribute to our session description.
|
|
|
|
|
AddFingerprint();
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription new_jdesc(kDummyType);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(new_jdesc.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_fingerprint(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_fingerprint = kSdpString;
|
|
|
|
|
InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_fingerprint);
|
|
|
|
|
InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_fingerprint);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_fingerprint, &jdesc_with_fingerprint));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_with_fingerprint, new_jdesc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBundle) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_bundle(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_bundle = kSdpFullString;
|
|
|
|
|
InjectAfter(kSessionTime,
|
|
|
|
|
"a=group:BUNDLE audio_content_name video_content_name\r\n",
|
|
|
|
|
&sdp_with_bundle);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_bundle, &jdesc_with_bundle));
|
|
|
|
|
ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
|
|
|
|
|
group.AddContentName(kAudioContentName);
|
|
|
|
|
group.AddContentName(kVideoContentName);
|
|
|
|
|
desc_.AddGroup(group);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bundle));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithBandwidth) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_bandwidth(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_bandwidth = kSdpFullString;
|
|
|
|
|
InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n", "b=AS:100\r\n",
|
|
|
|
|
&sdp_with_bandwidth);
|
|
|
|
|
InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n", "b=AS:50\r\n",
|
|
|
|
|
&sdp_with_bandwidth);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
|
2017-12-21 15:14:30 -08:00
|
|
|
VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
vcd->set_bandwidth(100 * 1000);
|
2017-12-21 15:14:30 -08:00
|
|
|
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
acd->set_bandwidth(50 * 1000);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-27 15:52:02 -07:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithTiasBandwidth) {
|
|
|
|
|
JsepSessionDescription jdesc_with_bandwidth(kDummyType);
|
|
|
|
|
std::string sdp_with_bandwidth = kSdpFullString;
|
|
|
|
|
InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n", "b=TIAS:100000\r\n",
|
|
|
|
|
&sdp_with_bandwidth);
|
|
|
|
|
InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n", "b=TIAS:50000\r\n",
|
|
|
|
|
&sdp_with_bandwidth);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
|
|
|
|
|
VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
|
|
|
|
|
vcd->set_bandwidth(100 * 1000);
|
|
|
|
|
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
|
|
|
|
|
acd->set_bandwidth(50 * 1000);
|
|
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
|
|
|
|
jdesc_.session_version()));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-31 08:30:50 +02:00
|
|
|
TEST_F(WebRtcSdpTest,
|
|
|
|
|
DeserializeSessionDescriptionWithUnknownBandwidthModifier) {
|
|
|
|
|
JsepSessionDescription jdesc_with_bandwidth(kDummyType);
|
|
|
|
|
std::string sdp_with_bandwidth = kSdpFullString;
|
|
|
|
|
InjectAfter("a=mid:video_content_name\r\na=sendrecv\r\n",
|
|
|
|
|
"b=unknown:100000\r\n", &sdp_with_bandwidth);
|
|
|
|
|
InjectAfter("a=mid:audio_content_name\r\na=sendrecv\r\n",
|
|
|
|
|
"b=unknown:50000\r\n", &sdp_with_bandwidth);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
|
|
|
|
|
VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
|
|
|
|
|
vcd->set_bandwidth(-1);
|
|
|
|
|
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
|
|
|
|
|
acd->set_bandwidth(-1);
|
|
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
|
|
|
|
jdesc_.session_version()));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_bandwidth));
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithIceOptions) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_ice_options(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_ice_options = kSdpFullString;
|
|
|
|
|
InjectAfter(kSessionTime, "a=ice-options:iceoption3\r\n",
|
|
|
|
|
&sdp_with_ice_options);
|
|
|
|
|
InjectAfter(kAttributeIcePwdVoice, "a=ice-options:iceoption1\r\n",
|
|
|
|
|
&sdp_with_ice_options);
|
|
|
|
|
InjectAfter(kAttributeIcePwdVideo, "a=ice-options:iceoption2\r\n",
|
|
|
|
|
&sdp_with_ice_options);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_ice_options, &jdesc_with_ice_options));
|
|
|
|
|
std::vector<std::string> transport_options;
|
|
|
|
|
transport_options.push_back(kIceOption3);
|
|
|
|
|
transport_options.push_back(kIceOption1);
|
|
|
|
|
AddIceOptions(kAudioContentName, transport_options);
|
|
|
|
|
transport_options.clear();
|
|
|
|
|
transport_options.push_back(kIceOption3);
|
|
|
|
|
transport_options.push_back(kIceOption2);
|
|
|
|
|
AddIceOptions(kVideoContentName, transport_options);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ice_options));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithUfragPwd) {
|
|
|
|
|
// Remove the original ice-ufrag and ice-pwd
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_ufrag_pwd(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_ufrag_pwd = kSdpFullString;
|
|
|
|
|
EXPECT_TRUE(RemoveCandidateUfragPwd(&sdp_with_ufrag_pwd));
|
|
|
|
|
// Add session level ufrag and pwd
|
|
|
|
|
InjectAfter(kSessionTime,
|
|
|
|
|
"a=ice-pwd:session+level+icepwd\r\n"
|
|
|
|
|
"a=ice-ufrag:session+level+iceufrag\r\n",
|
|
|
|
|
&sdp_with_ufrag_pwd);
|
|
|
|
|
// Add media level ufrag and pwd for audio
|
|
|
|
|
InjectAfter(
|
|
|
|
|
"a=mid:audio_content_name\r\n",
|
|
|
|
|
"a=ice-pwd:media+level+icepwd\r\na=ice-ufrag:media+level+iceufrag\r\n",
|
|
|
|
|
&sdp_with_ufrag_pwd);
|
|
|
|
|
// Update the candidate ufrag and pwd to the expected ones.
|
|
|
|
|
EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 0, "media+level+iceufrag",
|
|
|
|
|
"media+level+icepwd"));
|
|
|
|
|
EXPECT_TRUE(UpdateCandidateUfragPwd(&jdesc_, 1, "session+level+iceufrag",
|
|
|
|
|
"session+level+icepwd"));
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_ufrag_pwd, &jdesc_with_ufrag_pwd));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_with_ufrag_pwd));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
|
2017-11-28 14:57:10 -08:00
|
|
|
EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kRecvOnly));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
|
2017-11-28 14:57:10 -08:00
|
|
|
EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kSendOnly));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
|
2017-11-28 14:57:10 -08:00
|
|
|
EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kInactive));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {
|
|
|
|
|
EXPECT_TRUE(TestDeserializeRejected(true, false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedVideo) {
|
|
|
|
|
EXPECT_TRUE(TestDeserializeRejected(false, true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudioVideo) {
|
|
|
|
|
EXPECT_TRUE(TestDeserializeRejected(true, true));
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-10 22:33:20 +02:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithExtmapAllowMixed) {
|
2018-10-23 10:17:39 +02:00
|
|
|
jdesc_.description()->set_extmap_allow_mixed(true);
|
2018-10-10 22:33:20 +02:00
|
|
|
std::string sdp_with_extmap_allow_mixed = kSdpFullString;
|
|
|
|
|
// Deserialize
|
|
|
|
|
JsepSessionDescription jdesc_deserialized(kDummyType);
|
2021-01-19 13:06:32 +01:00
|
|
|
ASSERT_TRUE(SdpDeserialize(sdp_with_extmap_allow_mixed, &jdesc_deserialized));
|
2018-10-10 22:33:20 +02:00
|
|
|
// Verify
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutExtmapAllowMixed) {
|
2018-10-23 10:17:39 +02:00
|
|
|
jdesc_.description()->set_extmap_allow_mixed(false);
|
2018-10-10 22:33:20 +02:00
|
|
|
std::string sdp_without_extmap_allow_mixed = kSdpFullString;
|
2021-01-19 13:06:32 +01:00
|
|
|
Replace(kExtmapAllowMixed, "", &sdp_without_extmap_allow_mixed);
|
2018-10-10 22:33:20 +02:00
|
|
|
// Deserialize
|
|
|
|
|
JsepSessionDescription jdesc_deserialized(kDummyType);
|
2021-01-19 13:06:32 +01:00
|
|
|
ASSERT_TRUE(
|
2018-10-10 22:33:20 +02:00
|
|
|
SdpDeserialize(sdp_without_extmap_allow_mixed, &jdesc_deserialized));
|
|
|
|
|
// Verify
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMediaContentDescriptionWithExtmapAllowMixed) {
|
|
|
|
|
cricket::MediaContentDescription* video_desc =
|
|
|
|
|
jdesc_.description()->GetContentDescriptionByName(kVideoContentName);
|
|
|
|
|
ASSERT_TRUE(video_desc);
|
|
|
|
|
cricket::MediaContentDescription* audio_desc =
|
|
|
|
|
jdesc_.description()->GetContentDescriptionByName(kAudioContentName);
|
|
|
|
|
ASSERT_TRUE(audio_desc);
|
2018-10-23 10:17:39 +02:00
|
|
|
video_desc->set_extmap_allow_mixed_enum(
|
2018-10-10 22:33:20 +02:00
|
|
|
cricket::MediaContentDescription::kMedia);
|
2018-10-23 10:17:39 +02:00
|
|
|
audio_desc->set_extmap_allow_mixed_enum(
|
2018-10-10 22:33:20 +02:00
|
|
|
cricket::MediaContentDescription::kMedia);
|
|
|
|
|
|
|
|
|
|
std::string sdp_with_extmap_allow_mixed = kSdpFullString;
|
|
|
|
|
InjectAfter("a=mid:audio_content_name\r\n", kExtmapAllowMixed,
|
|
|
|
|
&sdp_with_extmap_allow_mixed);
|
|
|
|
|
InjectAfter("a=mid:video_content_name\r\n", kExtmapAllowMixed,
|
|
|
|
|
&sdp_with_extmap_allow_mixed);
|
|
|
|
|
|
|
|
|
|
// Deserialize
|
|
|
|
|
JsepSessionDescription jdesc_deserialized(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_extmap_allow_mixed, &jdesc_deserialized));
|
|
|
|
|
// Verify
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, jdesc_deserialized));
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeCandidate) {
|
|
|
|
|
JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
|
|
|
|
|
|
|
|
|
|
std::string sdp = kSdpOneCandidate;
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
|
|
|
|
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
|
|
|
|
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
|
|
|
|
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
|
2016-03-23 16:07:48 -07:00
|
|
|
EXPECT_EQ(0, jcandidate.candidate().network_cost());
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Candidate line without generation extension.
|
|
|
|
|
sdp = kSdpOneCandidate;
|
|
|
|
|
Replace(" generation 2", "", &sdp);
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
|
|
|
|
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
|
|
|
|
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
|
|
|
|
Candidate expected = jcandidate_->candidate();
|
|
|
|
|
expected.set_generation(0);
|
|
|
|
|
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
|
|
|
|
|
|
2016-03-23 16:07:48 -07:00
|
|
|
// Candidate with network id and/or cost.
|
|
|
|
|
sdp = kSdpOneCandidate;
|
|
|
|
|
Replace(" generation 2", " generation 2 network-id 2", &sdp);
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
|
|
|
|
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
|
|
|
|
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
|
|
|
|
expected = jcandidate_->candidate();
|
|
|
|
|
expected.set_network_id(2);
|
|
|
|
|
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
|
|
|
|
|
EXPECT_EQ(0, jcandidate.candidate().network_cost());
|
|
|
|
|
// Add network cost
|
|
|
|
|
Replace(" network-id 2", " network-id 2 network-cost 9", &sdp);
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
|
|
|
|
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
|
|
|
|
|
EXPECT_EQ(9, jcandidate.candidate().network_cost());
|
|
|
|
|
|
2014-08-08 22:29:20 +00:00
|
|
|
sdp = kSdpTcpActiveCandidate;
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
|
|
|
|
// Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
|
2015-01-15 06:53:07 +00:00
|
|
|
Candidate candidate(ICE_CANDIDATE_COMPONENT_RTP, "tcp",
|
2014-12-16 23:01:31 +00:00
|
|
|
rtc::SocketAddress("192.168.1.5", 9), kCandidatePriority,
|
|
|
|
|
"", "", LOCAL_PORT_TYPE, kCandidateGeneration,
|
|
|
|
|
kCandidateFoundation1);
|
2016-04-27 06:47:29 -07:00
|
|
|
std::unique_ptr<IceCandidateInterface> jcandidate_template(
|
|
|
|
|
new JsepIceCandidate(std::string("audio_content_name"), 0, candidate));
|
2014-08-08 22:29:20 +00:00
|
|
|
EXPECT_TRUE(
|
|
|
|
|
jcandidate.candidate().IsEquivalent(jcandidate_template->candidate()));
|
|
|
|
|
sdp = kSdpTcpPassiveCandidate;
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
|
|
|
|
sdp = kSdpTcpSOCandidate;
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This test verifies the deserialization of candidate-attribute
|
2022-03-19 01:43:10 -07:00
|
|
|
// as per RFC 5245. Candidate-attribute will be of the format
|
2013-07-10 00:45:36 +00:00
|
|
|
// candidate:<blah>. This format will be used when candidates
|
|
|
|
|
// are trickled.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeRawCandidateAttribute) {
|
|
|
|
|
JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
|
|
|
|
|
|
|
|
|
|
std::string candidate_attribute = kRawCandidate;
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
|
|
|
|
|
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
|
|
|
|
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
|
|
|
|
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
|
|
|
|
|
EXPECT_EQ(2u, jcandidate.candidate().generation());
|
|
|
|
|
|
|
|
|
|
// Candidate line without generation extension.
|
|
|
|
|
candidate_attribute = kRawCandidate;
|
|
|
|
|
Replace(" generation 2", "", &candidate_attribute);
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
|
|
|
|
|
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
|
|
|
|
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
|
|
|
|
Candidate expected = jcandidate_->candidate();
|
|
|
|
|
expected.set_generation(0);
|
|
|
|
|
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
|
|
|
|
|
|
|
|
|
|
// Candidate line without candidate:
|
|
|
|
|
candidate_attribute = kRawCandidate;
|
|
|
|
|
Replace("candidate:", "", &candidate_attribute);
|
|
|
|
|
EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
|
|
|
|
|
|
2014-08-08 23:09:15 +00:00
|
|
|
// Candidate line with IPV6 address.
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(kRawIPV6Candidate, &jcandidate));
|
2018-08-09 01:16:13 -07:00
|
|
|
|
|
|
|
|
// Candidate line with hostname address.
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(kRawHostnameCandidate, &jcandidate));
|
2014-08-08 23:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This test verifies that the deserialization of an invalid candidate string
|
|
|
|
|
// fails.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeInvalidCandidiate) {
|
|
|
|
|
JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
|
|
|
|
|
|
|
|
|
|
std::string candidate_attribute = kRawCandidate;
|
|
|
|
|
candidate_attribute.replace(0, 1, "x");
|
|
|
|
|
EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
|
|
|
|
|
|
|
|
|
|
candidate_attribute = kSdpOneCandidate;
|
|
|
|
|
candidate_attribute.replace(0, 1, "x");
|
|
|
|
|
EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
candidate_attribute = kRawCandidate;
|
2014-08-08 23:09:15 +00:00
|
|
|
candidate_attribute.append("\r\n");
|
|
|
|
|
candidate_attribute.append(kRawCandidate);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_FALSE(SdpDeserializeCandidate(candidate_attribute, &jcandidate));
|
2014-08-08 23:09:15 +00:00
|
|
|
|
|
|
|
|
EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
|
2017-02-17 19:48:38 -08:00
|
|
|
bool use_sctpmap = true;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelString);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2019-05-31 10:17:38 +00:00
|
|
|
// Verify with UDP/DTLS/SCTP (already in kSdpSctpDataChannelString).
|
2015-02-24 20:19:35 +00:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
|
|
|
|
|
2019-05-31 10:17:38 +00:00
|
|
|
// Verify with DTLS/SCTP.
|
|
|
|
|
sdp_with_data.replace(sdp_with_data.find(kUdpDtlsSctp), strlen(kUdpDtlsSctp),
|
|
|
|
|
kDtlsSctp);
|
2015-02-24 20:19:35 +00:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
|
|
|
|
|
|
|
|
|
// Verify with TCP/DTLS/SCTP.
|
2019-05-31 10:17:38 +00:00
|
|
|
sdp_with_data.replace(sdp_with_data.find(kDtlsSctp), strlen(kDtlsSctp),
|
2015-02-24 20:19:35 +00:00
|
|
|
kTcpDtlsSctp);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-05 16:31:56 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpPort) {
|
2017-02-17 19:48:38 -08:00
|
|
|
bool use_sctpmap = false;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
2014-09-05 16:31:56 +00:00
|
|
|
|
|
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2015-02-24 20:19:26 +00:00
|
|
|
|
2014-09-05 16:31:56 +00:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-08 10:15:04 -07:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithSctpColonPort) {
|
2017-02-17 19:48:38 -08:00
|
|
|
bool use_sctpmap = false;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
2015-10-08 10:15:04 -07:00
|
|
|
|
|
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2015-10-08 10:15:04 -07:00
|
|
|
|
2019-04-11 10:41:24 +02:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-26 10:17:05 +02:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsButWrongMediaType) {
|
|
|
|
|
bool use_sctpmap = true;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
|
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
|
|
|
|
ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
|
|
|
|
|
|
|
|
|
std::string sdp = kSdpSessionString;
|
|
|
|
|
sdp += kSdpSctpDataChannelString;
|
|
|
|
|
|
|
|
|
|
const char needle[] = "m=application ";
|
|
|
|
|
sdp.replace(sdp.find(needle), strlen(needle), "m=application:bogus ");
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
|
2020-10-13 12:43:15 +02:00
|
|
|
EXPECT_EQ(1u, jdesc_output.description()->contents().size());
|
|
|
|
|
EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
|
2020-06-26 10:17:05 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-11 10:41:24 +02:00
|
|
|
// Helper function to set the max-message-size parameter in the
|
|
|
|
|
// SCTP data codec.
|
|
|
|
|
void MutateJsepSctpMaxMessageSize(const SessionDescription& desc,
|
2019-05-13 13:36:16 +02:00
|
|
|
int new_value,
|
2019-04-11 10:41:24 +02:00
|
|
|
JsepSessionDescription* jdesc) {
|
2019-05-10 09:31:04 +02:00
|
|
|
std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
|
2019-05-13 13:36:16 +02:00
|
|
|
SctpDataContentDescription* dcdesc =
|
|
|
|
|
mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
|
|
|
|
|
dcdesc->set_max_message_size(new_value);
|
2019-05-10 09:31:04 +02:00
|
|
|
jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion);
|
2019-04-11 10:41:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsWithMaxMessageSize) {
|
|
|
|
|
bool use_sctpmap = false;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
|
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
|
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
|
|
|
|
|
sdp_with_data.append("a=max-message-size:12345\r\n");
|
2019-05-13 13:36:16 +02:00
|
|
|
MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
|
2019-04-11 10:41:24 +02:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
|
2015-10-08 10:15:04 -07:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
2019-05-15 08:07:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSdpWithSctpDataChannelWithMaxMessageSize) {
|
|
|
|
|
bool use_sctpmap = false;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
|
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
|
|
|
|
MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
|
|
|
|
|
std::string message = webrtc::SdpSerialize(jdesc);
|
|
|
|
|
EXPECT_NE(std::string::npos,
|
|
|
|
|
message.find("\r\na=max-message-size:12345\r\n"));
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest,
|
|
|
|
|
SerializeSdpWithSctpDataChannelWithDefaultMaxMessageSize) {
|
|
|
|
|
// https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
|
|
|
|
|
// The default max message size is 64K.
|
|
|
|
|
bool use_sctpmap = false;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
|
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
|
|
|
|
MutateJsepSctpMaxMessageSize(desc_, 65536, &jdesc);
|
|
|
|
|
std::string message = webrtc::SdpSerialize(jdesc);
|
|
|
|
|
EXPECT_EQ(std::string::npos, message.find("\r\na=max-message-size:"));
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(message, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
2015-10-08 10:15:04 -07:00
|
|
|
}
|
|
|
|
|
|
2014-09-05 16:31:56 +00:00
|
|
|
// Test to check the behaviour if sctp-port is specified
|
|
|
|
|
// on the m= line and in a=sctp-port.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithMultiSctpPort) {
|
2017-02-17 19:48:38 -08:00
|
|
|
bool use_sctpmap = true;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
2014-09-05 16:31:56 +00:00
|
|
|
|
|
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
// Append m= attributes
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelString);
|
|
|
|
|
// Append a=sctp-port attribute
|
|
|
|
|
sdp_with_data.append("a=sctp-port 5000\r\n");
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2014-09-05 16:31:56 +00:00
|
|
|
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 13:36:16 +02:00
|
|
|
// Test behavior if a=rtpmap occurs in an SCTP section.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpmapAttribute) {
|
|
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
// Append m= attributes
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelString);
|
|
|
|
|
// Append a=rtpmap attribute
|
|
|
|
|
sdp_with_data.append("a=rtpmap:111 opus/48000/2\r\n");
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
// Correct behavior is to ignore the extra attribute.
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-19 23:04:26 +00:00
|
|
|
// For crbug/344475.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithCorruptedSctpDataChannels) {
|
|
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelString);
|
|
|
|
|
// Remove the "\n" at the end.
|
|
|
|
|
sdp_with_data = sdp_with_data.substr(0, sdp_with_data.size() - 1);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2014-02-19 23:04:26 +00:00
|
|
|
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
// No crash is a pass.
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 19:48:38 -08:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndUnusualPort) {
|
|
|
|
|
bool use_sctpmap = true;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
|
|
|
|
|
|
|
|
|
// First setup the expected JsepSessionDescription.
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2019-05-13 13:36:16 +02:00
|
|
|
MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
|
2013-10-07 23:32:02 +00:00
|
|
|
|
2014-05-01 18:30:30 +00:00
|
|
|
// Then get the deserialized JsepSessionDescription.
|
2013-10-07 23:32:02 +00:00
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelString);
|
2019-02-14 15:13:09 -08:00
|
|
|
absl::StrReplaceAll(
|
|
|
|
|
{{rtc::ToString(kDefaultSctpPort), rtc::ToString(kUnusualSctpPort)}},
|
|
|
|
|
&sdp_with_data);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2013-10-07 23:32:02 +00:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
2017-02-17 19:48:38 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest,
|
|
|
|
|
DeserializeSdpWithSctpDataChannelAndUnusualPortInAttribute) {
|
|
|
|
|
bool use_sctpmap = false;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2019-05-13 13:36:16 +02:00
|
|
|
MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
|
2014-09-05 16:31:56 +00:00
|
|
|
|
|
|
|
|
// We need to test the deserialized JsepSessionDescription from
|
|
|
|
|
// kSdpSctpDataChannelStringWithSctpPort for
|
|
|
|
|
// draft-ietf-mmusic-sctp-sdp-07
|
|
|
|
|
// a=sctp-port
|
2017-02-17 19:48:38 -08:00
|
|
|
std::string sdp_with_data = kSdpString;
|
2014-09-05 16:31:56 +00:00
|
|
|
sdp_with_data.append(kSdpSctpDataChannelStringWithSctpPort);
|
2019-02-14 15:13:09 -08:00
|
|
|
absl::StrReplaceAll(
|
|
|
|
|
{{rtc::ToString(kDefaultSctpPort), rtc::ToString(kUnusualSctpPort)}},
|
|
|
|
|
&sdp_with_data);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2014-09-05 16:31:56 +00:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
2013-10-07 23:32:02 +00:00
|
|
|
}
|
|
|
|
|
|
2015-06-24 15:31:25 -07:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
|
2017-02-17 19:48:38 -08:00
|
|
|
bool use_sctpmap = true;
|
|
|
|
|
AddSctpDataChannel(use_sctpmap);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2019-05-13 13:36:16 +02:00
|
|
|
SctpDataContentDescription* dcd = GetFirstSctpDataContentDescription(&desc_);
|
2013-09-13 23:48:58 +00:00
|
|
|
dcd->set_bandwidth(100 * 1000);
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
2013-08-30 21:24:16 +00:00
|
|
|
|
|
|
|
|
std::string sdp_with_bandwidth = kSdpString;
|
2015-06-24 15:31:25 -07:00
|
|
|
sdp_with_bandwidth.append(kSdpSctpDataChannelString);
|
2013-08-30 21:24:16 +00:00
|
|
|
InjectAfter("a=mid:data_content_name\r\n", "b=AS:100\r\n",
|
|
|
|
|
&sdp_with_bandwidth);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_bandwidth(kDummyType);
|
2013-08-30 21:24:16 +00:00
|
|
|
|
2015-06-24 15:31:25 -07:00
|
|
|
// SCTP has congestion control, so we shouldn't limit the bandwidth
|
|
|
|
|
// as we do for RTP.
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
|
2013-08-30 21:24:16 +00:00
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_with_bandwidth));
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-29 12:31:36 -07:00
|
|
|
class WebRtcSdpExtmapTest : public WebRtcSdpTest,
|
2019-04-09 15:11:12 +02:00
|
|
|
public ::testing::WithParamInterface<bool> {};
|
2017-06-29 12:31:36 -07:00
|
|
|
|
|
|
|
|
TEST_P(WebRtcSdpExtmapTest,
|
|
|
|
|
DeserializeSessionDescriptionWithSessionLevelExtmap) {
|
|
|
|
|
bool encrypted = GetParam();
|
|
|
|
|
TestDeserializeExtmap(true, false, encrypted);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2017-06-29 12:31:36 -07:00
|
|
|
TEST_P(WebRtcSdpExtmapTest, DeserializeSessionDescriptionWithMediaLevelExtmap) {
|
|
|
|
|
bool encrypted = GetParam();
|
|
|
|
|
TestDeserializeExtmap(false, true, encrypted);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2017-06-29 12:31:36 -07:00
|
|
|
TEST_P(WebRtcSdpExtmapTest, DeserializeSessionDescriptionWithInvalidExtmap) {
|
|
|
|
|
bool encrypted = GetParam();
|
|
|
|
|
TestDeserializeExtmap(true, true, encrypted);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2019-01-31 12:20:57 +01:00
|
|
|
INSTANTIATE_TEST_SUITE_P(Encrypted,
|
|
|
|
|
WebRtcSdpExtmapTest,
|
|
|
|
|
::testing::Values(false, true));
|
2017-06-29 12:31:36 -07:00
|
|
|
|
2013-12-05 00:24:06 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutEndLineBreak) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2013-12-05 00:24:06 +00:00
|
|
|
std::string sdp = kSdpFullString;
|
|
|
|
|
sdp = sdp.substr(0, sdp.size() - 2); // Remove \r\n at the end.
|
|
|
|
|
// Deserialize
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_FALSE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
|
2022-04-07 09:54:51 +00:00
|
|
|
const std::string lastline = "a=ssrc:3 msid:local_stream_1 video_track_id_1";
|
2013-12-05 00:24:06 +00:00
|
|
|
EXPECT_EQ(lastline, error.line);
|
|
|
|
|
EXPECT_EQ("Invalid SDP line.", error.description);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeCandidateWithDifferentTransport) {
|
|
|
|
|
JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
|
|
|
|
|
std::string new_sdp = kSdpOneCandidate;
|
|
|
|
|
Replace("udp", "unsupported_transport", &new_sdp);
|
|
|
|
|
EXPECT_FALSE(SdpDeserializeCandidate(new_sdp, &jcandidate));
|
|
|
|
|
new_sdp = kSdpOneCandidate;
|
|
|
|
|
Replace("udp", "uDP", &new_sdp);
|
|
|
|
|
EXPECT_TRUE(SdpDeserializeCandidate(new_sdp, &jcandidate));
|
|
|
|
|
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
|
|
|
|
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
|
|
|
|
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 18:37:23 -08:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeCandidateWithUfragPwd) {
|
2013-07-10 00:45:36 +00:00
|
|
|
JsepIceCandidate jcandidate(kDummyMid, kDummyIndex);
|
2015-12-16 18:37:23 -08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
|
SdpDeserializeCandidate(kSdpOneCandidateWithUfragPwd, &jcandidate));
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
|
|
|
|
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
|
|
|
|
Candidate ref_candidate = jcandidate_->candidate();
|
|
|
|
|
ref_candidate.set_username("user_rtp");
|
|
|
|
|
ref_candidate.set_password("password_rtp");
|
|
|
|
|
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(ref_candidate));
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 17:52:04 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithConferenceFlag) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2014-02-27 17:52:04 +00:00
|
|
|
|
|
|
|
|
// Deserialize
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
|
|
|
|
|
|
|
|
|
|
// Verify
|
|
|
|
|
cricket::AudioContentDescription* audio =
|
2018-12-18 15:55:30 -08:00
|
|
|
cricket::GetFirstAudioContentDescription(jdesc.description());
|
2014-02-27 17:52:04 +00:00
|
|
|
EXPECT_TRUE(audio->conference_mode());
|
|
|
|
|
|
|
|
|
|
cricket::VideoContentDescription* video =
|
2018-12-18 15:55:30 -08:00
|
|
|
cricket::GetFirstVideoContentDescription(jdesc.description());
|
2014-02-27 17:52:04 +00:00
|
|
|
EXPECT_TRUE(video->conference_mode());
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-16 01:24:29 -07:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeSdpWithConferenceFlag) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2017-09-16 01:24:29 -07:00
|
|
|
|
|
|
|
|
// We tested deserialization already above, so just test that if we serialize
|
|
|
|
|
// and deserialize the flag doesn't disappear.
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpConferenceString, &jdesc));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string reserialized = webrtc::SdpSerialize(jdesc);
|
2017-09-16 01:24:29 -07:00
|
|
|
EXPECT_TRUE(SdpDeserialize(reserialized, &jdesc));
|
|
|
|
|
|
|
|
|
|
// Verify.
|
|
|
|
|
cricket::AudioContentDescription* audio =
|
2018-12-18 15:55:30 -08:00
|
|
|
cricket::GetFirstAudioContentDescription(jdesc.description());
|
2017-09-16 01:24:29 -07:00
|
|
|
EXPECT_TRUE(audio->conference_mode());
|
|
|
|
|
|
|
|
|
|
cricket::VideoContentDescription* video =
|
2018-12-18 15:55:30 -08:00
|
|
|
cricket::GetFirstVideoContentDescription(jdesc.description());
|
2017-09-16 01:24:29 -07:00
|
|
|
EXPECT_TRUE(video->conference_mode());
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-24 14:01:18 +02:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeAndDeserializeRemoteNetEstimate) {
|
|
|
|
|
{
|
|
|
|
|
// By default remote estimates are disabled.
|
|
|
|
|
JsepSessionDescription dst(kDummyType);
|
|
|
|
|
SdpDeserialize(webrtc::SdpSerialize(jdesc_), &dst);
|
|
|
|
|
EXPECT_FALSE(cricket::GetFirstVideoContentDescription(dst.description())
|
|
|
|
|
->remote_estimate());
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// When remote estimate is enabled, the setting is propagated via SDP.
|
|
|
|
|
cricket::GetFirstVideoContentDescription(jdesc_.description())
|
|
|
|
|
->set_remote_estimate(true);
|
|
|
|
|
JsepSessionDescription dst(kDummyType);
|
|
|
|
|
SdpDeserialize(webrtc::SdpSerialize(jdesc_), &dst);
|
|
|
|
|
EXPECT_TRUE(cricket::GetFirstVideoContentDescription(dst.description())
|
|
|
|
|
->remote_estimate());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
|
|
|
|
|
const char kSdpDestroyer[] = "!@#$%^&";
|
2015-01-07 19:15:51 +00:00
|
|
|
const char kSdpEmptyType[] = " =candidate";
|
|
|
|
|
const char kSdpEqualAsPlus[] = "a+candidate";
|
|
|
|
|
const char kSdpSpaceAfterEqual[] = "a= candidate";
|
|
|
|
|
const char kSdpUpperType[] = "A=candidate";
|
|
|
|
|
const char kSdpEmptyLine[] = "";
|
|
|
|
|
const char kSdpMissingValue[] = "a=";
|
|
|
|
|
|
|
|
|
|
const char kSdpBrokenFingerprint[] =
|
|
|
|
|
"a=fingerprint:sha-1 "
|
2013-07-10 00:45:36 +00:00
|
|
|
"4AAD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
|
2015-01-07 19:15:51 +00:00
|
|
|
const char kSdpExtraField[] =
|
|
|
|
|
"a=fingerprint:sha-1 "
|
2013-07-10 00:45:36 +00:00
|
|
|
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB XXX";
|
2015-01-07 19:15:51 +00:00
|
|
|
const char kSdpMissingSpace[] =
|
|
|
|
|
"a=fingerprint:sha-1"
|
2013-07-10 00:45:36 +00:00
|
|
|
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
|
2014-01-14 10:00:58 +00:00
|
|
|
// MD5 is not allowed in fingerprints.
|
2015-01-07 19:15:51 +00:00
|
|
|
const char kSdpMd5[] =
|
|
|
|
|
"a=fingerprint:md5 "
|
2014-01-14 10:00:58 +00:00
|
|
|
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Broken session description
|
2014-04-02 23:19:09 +00:00
|
|
|
ExpectParseFailure("v=", kSdpDestroyer);
|
|
|
|
|
ExpectParseFailure("o=", kSdpDestroyer);
|
|
|
|
|
ExpectParseFailure("s=-", kSdpDestroyer);
|
2013-07-10 00:45:36 +00:00
|
|
|
// Broken time description
|
2014-04-02 23:19:09 +00:00
|
|
|
ExpectParseFailure("t=", kSdpDestroyer);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Broken media description
|
2014-04-02 23:19:09 +00:00
|
|
|
ExpectParseFailure("m=audio", "c=IN IP4 74.125.224.39");
|
|
|
|
|
ExpectParseFailure("m=video", kSdpDestroyer);
|
2020-06-26 10:17:05 +02:00
|
|
|
ExpectParseFailure("m=", "c=IN IP4 74.125.224.39");
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Invalid lines
|
2015-01-07 19:15:51 +00:00
|
|
|
ExpectParseFailure("a=candidate", kSdpEmptyType);
|
|
|
|
|
ExpectParseFailure("a=candidate", kSdpEqualAsPlus);
|
|
|
|
|
ExpectParseFailure("a=candidate", kSdpSpaceAfterEqual);
|
|
|
|
|
ExpectParseFailure("a=candidate", kSdpUpperType);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Bogus fingerprint replacing a=sendrev. We selected this attribute
|
|
|
|
|
// because it's orthogonal to what we are replacing and hence
|
|
|
|
|
// safe.
|
2015-01-07 19:15:51 +00:00
|
|
|
ExpectParseFailure("a=sendrecv", kSdpBrokenFingerprint);
|
|
|
|
|
ExpectParseFailure("a=sendrecv", kSdpExtraField);
|
|
|
|
|
ExpectParseFailure("a=sendrecv", kSdpMissingSpace);
|
|
|
|
|
ExpectParseFailure("a=sendrecv", kSdpMd5);
|
|
|
|
|
|
|
|
|
|
// Empty Line
|
|
|
|
|
ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpEmptyLine);
|
|
|
|
|
ExpectParseFailure("a=rtcp:2347 IN IP4 74.125.127.126", kSdpMissingValue);
|
2014-04-02 23:19:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithInvalidAttributeValue) {
|
|
|
|
|
// ssrc
|
|
|
|
|
ExpectParseFailure("a=ssrc:1", "a=ssrc:badvalue");
|
2016-02-16 17:54:10 -08:00
|
|
|
ExpectParseFailure("a=ssrc-group:FEC 2 3", "a=ssrc-group:FEC badvalue 3");
|
2021-11-04 13:52:31 +00:00
|
|
|
// crypto
|
|
|
|
|
ExpectParseFailure("a=crypto:1 ", "a=crypto:badvalue ");
|
2014-04-02 23:19:09 +00:00
|
|
|
// rtpmap
|
|
|
|
|
ExpectParseFailure("a=rtpmap:111 ", "a=rtpmap:badvalue ");
|
|
|
|
|
ExpectParseFailure("opus/48000/2", "opus/badvalue/2");
|
|
|
|
|
ExpectParseFailure("opus/48000/2", "opus/48000/badvalue");
|
|
|
|
|
// candidate
|
|
|
|
|
ExpectParseFailure("1 udp 2130706432", "badvalue udp 2130706432");
|
|
|
|
|
ExpectParseFailure("1 udp 2130706432", "1 udp badvalue");
|
|
|
|
|
ExpectParseFailure("192.168.1.5 1234", "192.168.1.5 badvalue");
|
|
|
|
|
ExpectParseFailure("rport 2346", "rport badvalue");
|
|
|
|
|
ExpectParseFailure("rport 2346 generation 2",
|
|
|
|
|
"rport 2346 generation badvalue");
|
|
|
|
|
// m line
|
|
|
|
|
ExpectParseFailure("m=audio 2345 RTP/SAVPF 111 103 104",
|
|
|
|
|
"m=audio 2345 RTP/SAVPF 111 badvalue 104");
|
|
|
|
|
|
|
|
|
|
// bandwidth
|
|
|
|
|
ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
|
|
|
|
|
"b=AS:badvalue\r\n", "b=AS:badvalue");
|
2020-07-31 08:30:50 +02:00
|
|
|
ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n", "b=AS\r\n",
|
|
|
|
|
"b=AS");
|
|
|
|
|
ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n", "b=AS:\r\n",
|
|
|
|
|
"b=AS:");
|
|
|
|
|
ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
|
|
|
|
|
"b=AS:12:34\r\n", "b=AS:12:34");
|
|
|
|
|
|
2014-04-02 23:19:09 +00:00
|
|
|
// rtcp-fb
|
|
|
|
|
ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
|
|
|
|
|
"a=rtcp-fb:badvalue nack\r\n",
|
|
|
|
|
"a=rtcp-fb:badvalue nack");
|
|
|
|
|
// extmap
|
|
|
|
|
ExpectParseFailureWithNewLines("a=mid:video_content_name\r\n",
|
|
|
|
|
"a=extmap:badvalue http://example.com\r\n",
|
|
|
|
|
"a=extmap:badvalue http://example.com");
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
const char kSdpWithReorderedPlTypesString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
2014-10-23 23:37:22 +00:00
|
|
|
"m=audio 9 RTP/SAVPF 104 103\r\n" // Pl type 104 preferred.
|
2013-07-10 00:45:36 +00:00
|
|
|
"a=rtpmap:111 opus/48000/2\r\n" // Pltype 111 listed before 103 and 104
|
|
|
|
|
// in the map.
|
|
|
|
|
"a=rtpmap:103 ISAC/16000\r\n" // Pltype 103 listed before 104 in the map.
|
2015-02-17 12:36:41 +00:00
|
|
|
"a=rtpmap:104 ISAC/32000\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Deserialize
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpWithReorderedPlTypesString, &jdesc_output));
|
|
|
|
|
|
|
|
|
|
const AudioContentDescription* acd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstAudioContentDescription(jdesc_output.description());
|
|
|
|
|
ASSERT_TRUE(acd);
|
2013-07-10 00:45:36 +00:00
|
|
|
ASSERT_FALSE(acd->codecs().empty());
|
2015-02-17 12:36:41 +00:00
|
|
|
EXPECT_EQ("ISAC", acd->codecs()[0].name);
|
|
|
|
|
EXPECT_EQ(32000, acd->codecs()[0].clockrate);
|
2013-07-10 00:45:36 +00:00
|
|
|
EXPECT_EQ(104, acd->codecs()[0].id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSerializeCodecParams) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
CodecParams params;
|
|
|
|
|
params.max_ptime = 40;
|
|
|
|
|
params.ptime = 30;
|
|
|
|
|
params.min_ptime = 10;
|
|
|
|
|
params.sprop_stereo = 1;
|
|
|
|
|
params.stereo = 1;
|
|
|
|
|
params.useinband = 1;
|
2013-07-26 19:17:59 +00:00
|
|
|
params.maxaveragebitrate = 128000;
|
2013-07-10 00:45:36 +00:00
|
|
|
TestDeserializeCodecParams(params, &jdesc_output);
|
2018-02-01 12:22:16 -08:00
|
|
|
TestSerialize(jdesc_output);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFb) {
|
|
|
|
|
const bool kUseWildcard = false;
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
|
2018-02-01 12:22:16 -08:00
|
|
|
TestSerialize(jdesc_output);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSerializeRtcpFbWildcard) {
|
|
|
|
|
const bool kUseWildcard = true;
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
TestDeserializeRtcpFb(&jdesc_output, kUseWildcard);
|
2018-02-01 12:22:16 -08:00
|
|
|
TestSerialize(jdesc_output);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
const char kSdpWithFmtpString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
2015-05-15 09:21:23 -07:00
|
|
|
"a=fmtp:120 x-google-min-bitrate=10;x-google-max-quantization=40\r\n";
|
|
|
|
|
|
|
|
|
|
// Deserialize
|
|
|
|
|
SdpParseError error;
|
2015-05-15 13:14:24 -07:00
|
|
|
EXPECT_TRUE(
|
|
|
|
|
webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
|
2015-05-15 09:21:23 -07:00
|
|
|
|
|
|
|
|
const VideoContentDescription* vcd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstVideoContentDescription(jdesc_output.description());
|
|
|
|
|
ASSERT_TRUE(vcd);
|
2015-05-15 09:21:23 -07:00
|
|
|
ASSERT_FALSE(vcd->codecs().empty());
|
|
|
|
|
cricket::VideoCodec vp8 = vcd->codecs()[0];
|
|
|
|
|
EXPECT_EQ("VP8", vp8.name);
|
|
|
|
|
EXPECT_EQ(120, vp8.id);
|
|
|
|
|
cricket::CodecParameterMap::iterator found =
|
|
|
|
|
vp8.params.find("x-google-min-bitrate");
|
|
|
|
|
ASSERT_TRUE(found != vp8.params.end());
|
|
|
|
|
EXPECT_EQ(found->second, "10");
|
|
|
|
|
found = vp8.params.find("x-google-max-quantization");
|
|
|
|
|
ASSERT_TRUE(found != vp8.params.end());
|
|
|
|
|
EXPECT_EQ(found->second, "40");
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-03 01:22:42 -07:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSprops) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2016-06-03 01:22:42 -07:00
|
|
|
|
|
|
|
|
const char kSdpWithFmtpString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=video 49170 RTP/AVP 98\r\n"
|
|
|
|
|
"a=rtpmap:98 H264/90000\r\n"
|
|
|
|
|
"a=fmtp:98 profile-level-id=42A01E; "
|
|
|
|
|
"sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==\r\n";
|
|
|
|
|
|
|
|
|
|
// Deserialize.
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(
|
|
|
|
|
webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
|
|
|
|
|
|
|
|
|
|
const VideoContentDescription* vcd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstVideoContentDescription(jdesc_output.description());
|
|
|
|
|
ASSERT_TRUE(vcd);
|
2016-06-03 01:22:42 -07:00
|
|
|
ASSERT_FALSE(vcd->codecs().empty());
|
|
|
|
|
cricket::VideoCodec h264 = vcd->codecs()[0];
|
|
|
|
|
EXPECT_EQ("H264", h264.name);
|
|
|
|
|
EXPECT_EQ(98, h264.id);
|
|
|
|
|
cricket::CodecParameterMap::const_iterator found =
|
|
|
|
|
h264.params.find("profile-level-id");
|
|
|
|
|
ASSERT_TRUE(found != h264.params.end());
|
|
|
|
|
EXPECT_EQ(found->second, "42A01E");
|
|
|
|
|
found = h264.params.find("sprop-parameter-sets");
|
|
|
|
|
ASSERT_TRUE(found != h264.params.end());
|
|
|
|
|
EXPECT_EQ(found->second, "Z0IACpZTBYmI,aMljiA==");
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 09:21:23 -07:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeVideoFmtpWithSpace) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2015-05-15 09:21:23 -07:00
|
|
|
|
|
|
|
|
const char kSdpWithFmtpString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
"a=fmtp:120 x-google-min-bitrate=10; x-google-max-quantization=40\r\n";
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
// Deserialize
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(
|
|
|
|
|
webrtc::SdpDeserialize(kSdpWithFmtpString, &jdesc_output, &error));
|
|
|
|
|
|
|
|
|
|
const VideoContentDescription* vcd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstVideoContentDescription(jdesc_output.description());
|
|
|
|
|
ASSERT_TRUE(vcd);
|
2013-07-10 00:45:36 +00:00
|
|
|
ASSERT_FALSE(vcd->codecs().empty());
|
|
|
|
|
cricket::VideoCodec vp8 = vcd->codecs()[0];
|
|
|
|
|
EXPECT_EQ("VP8", vp8.name);
|
|
|
|
|
EXPECT_EQ(120, vp8.id);
|
|
|
|
|
cricket::CodecParameterMap::iterator found =
|
|
|
|
|
vp8.params.find("x-google-min-bitrate");
|
|
|
|
|
ASSERT_TRUE(found != vp8.params.end());
|
|
|
|
|
EXPECT_EQ(found->second, "10");
|
|
|
|
|
found = vp8.params.find("x-google-max-quantization");
|
|
|
|
|
ASSERT_TRUE(found != vp8.params.end());
|
|
|
|
|
EXPECT_EQ(found->second, "40");
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-04 15:38:50 +02:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializePacketizationAttributeWithIllegalValue) {
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
|
|
|
|
|
const char kSdpWithPacketizationString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=packetization:111 unknownpacketizationattributeforaudio\r\n"
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120 121 122\r\n"
|
|
|
|
|
"a=rtpmap:120 VP8/90000\r\n"
|
|
|
|
|
"a=packetization:120 raw\r\n"
|
|
|
|
|
"a=rtpmap:121 VP9/90000\r\n"
|
|
|
|
|
"a=rtpmap:122 H264/90000\r\n"
|
|
|
|
|
"a=packetization:122 unknownpacketizationattributevalue\r\n";
|
|
|
|
|
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(kSdpWithPacketizationString, &jdesc_output,
|
|
|
|
|
&error));
|
|
|
|
|
|
|
|
|
|
AudioContentDescription* acd =
|
|
|
|
|
GetFirstAudioContentDescription(jdesc_output.description());
|
|
|
|
|
ASSERT_TRUE(acd);
|
|
|
|
|
ASSERT_THAT(acd->codecs(), testing::SizeIs(1));
|
|
|
|
|
cricket::AudioCodec opus = acd->codecs()[0];
|
|
|
|
|
EXPECT_EQ(opus.name, "opus");
|
|
|
|
|
EXPECT_EQ(opus.id, 111);
|
|
|
|
|
|
|
|
|
|
const VideoContentDescription* vcd =
|
|
|
|
|
GetFirstVideoContentDescription(jdesc_output.description());
|
|
|
|
|
ASSERT_TRUE(vcd);
|
|
|
|
|
ASSERT_THAT(vcd->codecs(), testing::SizeIs(3));
|
|
|
|
|
cricket::VideoCodec vp8 = vcd->codecs()[0];
|
|
|
|
|
EXPECT_EQ(vp8.name, "VP8");
|
|
|
|
|
EXPECT_EQ(vp8.id, 120);
|
|
|
|
|
EXPECT_EQ(vp8.packetization, "raw");
|
|
|
|
|
cricket::VideoCodec vp9 = vcd->codecs()[1];
|
|
|
|
|
EXPECT_EQ(vp9.name, "VP9");
|
|
|
|
|
EXPECT_EQ(vp9.id, 121);
|
|
|
|
|
EXPECT_EQ(vp9.packetization, absl::nullopt);
|
|
|
|
|
cricket::VideoCodec h264 = vcd->codecs()[2];
|
|
|
|
|
EXPECT_EQ(h264.name, "H264");
|
|
|
|
|
EXPECT_EQ(h264.id, 122);
|
|
|
|
|
EXPECT_EQ(h264.packetization, absl::nullopt);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-30 07:41:18 -08:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithUnknownParameter) {
|
2017-12-21 15:14:30 -08:00
|
|
|
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
|
2017-01-30 07:41:18 -08:00
|
|
|
|
|
|
|
|
cricket::AudioCodecs codecs = acd->codecs();
|
|
|
|
|
codecs[0].params["unknown-future-parameter"] = "SomeFutureValue";
|
|
|
|
|
acd->set_codecs(codecs);
|
|
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2017-01-30 07:41:18 -08:00
|
|
|
jdesc_.session_version()));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2017-01-30 07:41:18 -08:00
|
|
|
std::string sdp_with_fmtp = kSdpFullString;
|
|
|
|
|
InjectAfter("a=rtpmap:111 opus/48000/2\r\n",
|
|
|
|
|
"a=fmtp:111 unknown-future-parameter=SomeFutureValue\r\n",
|
|
|
|
|
&sdp_with_fmtp);
|
|
|
|
|
EXPECT_EQ(sdp_with_fmtp, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithKnownFmtpParameter) {
|
2017-12-21 15:14:30 -08:00
|
|
|
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
|
2017-01-30 07:41:18 -08:00
|
|
|
|
|
|
|
|
cricket::AudioCodecs codecs = acd->codecs();
|
|
|
|
|
codecs[0].params["stereo"] = "1";
|
|
|
|
|
acd->set_codecs(codecs);
|
|
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2017-01-30 07:41:18 -08:00
|
|
|
jdesc_.session_version()));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2017-01-30 07:41:18 -08:00
|
|
|
std::string sdp_with_fmtp = kSdpFullString;
|
|
|
|
|
InjectAfter("a=rtpmap:111 opus/48000/2\r\n", "a=fmtp:111 stereo=1\r\n",
|
|
|
|
|
&sdp_with_fmtp);
|
|
|
|
|
EXPECT_EQ(sdp_with_fmtp, message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithPTimeAndMaxPTime) {
|
2017-12-21 15:14:30 -08:00
|
|
|
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
|
2017-01-30 07:41:18 -08:00
|
|
|
|
|
|
|
|
cricket::AudioCodecs codecs = acd->codecs();
|
|
|
|
|
codecs[0].params["ptime"] = "20";
|
|
|
|
|
codecs[0].params["maxptime"] = "120";
|
|
|
|
|
acd->set_codecs(codecs);
|
|
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2017-01-30 07:41:18 -08:00
|
|
|
jdesc_.session_version()));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2017-01-30 07:41:18 -08:00
|
|
|
std::string sdp_with_fmtp = kSdpFullString;
|
|
|
|
|
InjectAfter("a=rtpmap:104 ISAC/32000\r\n",
|
|
|
|
|
"a=maxptime:120\r\n" // No comma here. String merging!
|
|
|
|
|
"a=ptime:20\r\n",
|
|
|
|
|
&sdp_with_fmtp);
|
|
|
|
|
EXPECT_EQ(sdp_with_fmtp, message);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-01 21:07:32 +02:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeAudioFmtpWithTelephoneEvent) {
|
|
|
|
|
AudioContentDescription* acd = GetFirstAudioContentDescription(&desc_);
|
|
|
|
|
|
|
|
|
|
cricket::AudioCodecs codecs = acd->codecs();
|
|
|
|
|
cricket::AudioCodec dtmf(105, "telephone-event", 8000, 0, 1);
|
|
|
|
|
dtmf.params[""] = "0-15";
|
|
|
|
|
codecs.push_back(dtmf);
|
|
|
|
|
acd->set_codecs(codecs);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
|
|
|
|
jdesc_.session_version()));
|
|
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
|
|
|
|
std::string sdp_with_fmtp = kSdpFullString;
|
|
|
|
|
InjectAfter("m=audio 2345 RTP/SAVPF 111 103 104", " 105", &sdp_with_fmtp);
|
|
|
|
|
InjectAfter(
|
|
|
|
|
"a=rtpmap:104 ISAC/32000\r\n",
|
|
|
|
|
"a=rtpmap:105 telephone-event/8000\r\n" // No comma here. String merging!
|
|
|
|
|
"a=fmtp:105 0-15\r\n",
|
|
|
|
|
&sdp_with_fmtp);
|
|
|
|
|
EXPECT_EQ(sdp_with_fmtp, message);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeVideoFmtp) {
|
2017-12-21 15:14:30 -08:00
|
|
|
VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
cricket::VideoCodecs codecs = vcd->codecs();
|
|
|
|
|
codecs[0].params["x-google-min-bitrate"] = "10";
|
|
|
|
|
vcd->set_codecs(codecs);
|
|
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-07-10 00:45:36 +00:00
|
|
|
jdesc_.session_version()));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_fmtp = kSdpFullString;
|
|
|
|
|
InjectAfter("a=rtpmap:120 VP8/90000\r\n",
|
|
|
|
|
"a=fmtp:120 x-google-min-bitrate=10\r\n", &sdp_with_fmtp);
|
|
|
|
|
EXPECT_EQ(sdp_with_fmtp, message);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-04 15:38:50 +02:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeVideoPacketizationAttribute) {
|
|
|
|
|
VideoContentDescription* vcd = GetFirstVideoContentDescription(&desc_);
|
|
|
|
|
|
|
|
|
|
cricket::VideoCodecs codecs = vcd->codecs();
|
|
|
|
|
codecs[0].packetization = "raw";
|
|
|
|
|
vcd->set_codecs(codecs);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
|
|
|
|
jdesc_.session_version()));
|
|
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
|
|
|
|
std::string sdp_with_packetization = kSdpFullString;
|
|
|
|
|
InjectAfter("a=rtpmap:120 VP8/90000\r\n", "a=packetization:120 raw\r\n",
|
|
|
|
|
&sdp_with_packetization);
|
|
|
|
|
EXPECT_EQ(sdp_with_packetization, message);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-24 11:37:28 -07:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeAndSerializeSdpWithIceLite) {
|
|
|
|
|
// Deserialize the baseline description, making sure it's ICE full.
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_icelite(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string sdp_with_icelite = kSdpFullString;
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
|
|
|
|
|
cricket::SessionDescription* desc = jdesc_with_icelite.description();
|
|
|
|
|
const cricket::TransportInfo* tinfo1 =
|
|
|
|
|
desc->GetTransportInfoByName("audio_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::ICEMODE_FULL, tinfo1->description.ice_mode);
|
|
|
|
|
const cricket::TransportInfo* tinfo2 =
|
|
|
|
|
desc->GetTransportInfoByName("video_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::ICEMODE_FULL, tinfo2->description.ice_mode);
|
2018-05-24 11:37:28 -07:00
|
|
|
|
|
|
|
|
// Add "a=ice-lite" and deserialize, making sure it's ICE lite.
|
2013-07-10 00:45:36 +00:00
|
|
|
InjectAfter(kSessionTime, "a=ice-lite\r\n", &sdp_with_icelite);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_icelite, &jdesc_with_icelite));
|
|
|
|
|
desc = jdesc_with_icelite.description();
|
|
|
|
|
const cricket::TransportInfo* atinfo =
|
|
|
|
|
desc->GetTransportInfoByName("audio_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::ICEMODE_LITE, atinfo->description.ice_mode);
|
|
|
|
|
const cricket::TransportInfo* vtinfo =
|
|
|
|
|
desc->GetTransportInfoByName("video_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::ICEMODE_LITE, vtinfo->description.ice_mode);
|
2018-05-24 11:37:28 -07:00
|
|
|
|
|
|
|
|
// Now that we know deserialization works, we can use TestSerialize to test
|
|
|
|
|
// serialization.
|
|
|
|
|
TestSerialize(jdesc_with_icelite);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verifies that the candidates in the input SDP are parsed and serialized
|
|
|
|
|
// correctly in the output SDP.
|
|
|
|
|
TEST_F(WebRtcSdpTest, RoundTripSdpWithSctpDataChannelsWithCandidates) {
|
|
|
|
|
std::string sdp_with_data = kSdpString;
|
|
|
|
|
sdp_with_data.append(kSdpSctpDataChannelWithCandidatesString);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
2018-02-01 12:22:16 -08:00
|
|
|
EXPECT_EQ(sdp_with_data, webrtc::SdpSerialize(jdesc_output));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
2013-08-23 23:21:25 +00:00
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeDtlsSetupAttribute) {
|
|
|
|
|
AddFingerprint();
|
|
|
|
|
TransportInfo audio_transport_info =
|
|
|
|
|
*(desc_.GetTransportInfoByName(kAudioContentName));
|
|
|
|
|
EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
|
|
|
|
|
audio_transport_info.description.connection_role);
|
|
|
|
|
audio_transport_info.description.connection_role =
|
|
|
|
|
cricket::CONNECTIONROLE_ACTIVE;
|
|
|
|
|
|
|
|
|
|
TransportInfo video_transport_info =
|
|
|
|
|
*(desc_.GetTransportInfoByName(kVideoContentName));
|
|
|
|
|
EXPECT_EQ(cricket::CONNECTIONROLE_NONE,
|
|
|
|
|
video_transport_info.description.connection_role);
|
|
|
|
|
video_transport_info.description.connection_role =
|
|
|
|
|
cricket::CONNECTIONROLE_ACTIVE;
|
|
|
|
|
|
|
|
|
|
desc_.RemoveTransportInfoByName(kAudioContentName);
|
|
|
|
|
desc_.RemoveTransportInfoByName(kVideoContentName);
|
|
|
|
|
|
|
|
|
|
desc_.AddTransportInfo(audio_transport_info);
|
|
|
|
|
desc_.AddTransportInfo(video_transport_info);
|
|
|
|
|
|
2019-04-12 07:01:29 +02:00
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
2013-08-23 23:21:25 +00:00
|
|
|
jdesc_.session_version()));
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(jdesc_);
|
2013-08-23 23:21:25 +00:00
|
|
|
std::string sdp_with_dtlssetup = kSdpFullString;
|
|
|
|
|
|
|
|
|
|
// Fingerprint attribute is necessary to add DTLS setup attribute.
|
|
|
|
|
InjectAfter(kAttributeIcePwdVoice, kFingerprint, &sdp_with_dtlssetup);
|
|
|
|
|
InjectAfter(kAttributeIcePwdVideo, kFingerprint, &sdp_with_dtlssetup);
|
2021-07-30 22:30:23 +02:00
|
|
|
// Now adding `setup` attribute.
|
2013-08-23 23:21:25 +00:00
|
|
|
InjectAfter(kFingerprint, "a=setup:active\r\n", &sdp_with_dtlssetup);
|
|
|
|
|
EXPECT_EQ(sdp_with_dtlssetup, message);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 09:12:51 +00:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributeActpass) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
|
2013-08-23 23:21:25 +00:00
|
|
|
std::string sdp_with_dtlssetup = kSdpFullString;
|
|
|
|
|
InjectAfter(kSessionTime, "a=setup:actpass\r\n", &sdp_with_dtlssetup);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
|
|
|
|
|
cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
|
|
|
|
|
const cricket::TransportInfo* atinfo =
|
|
|
|
|
desc->GetTransportInfoByName("audio_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
|
|
|
|
|
atinfo->description.connection_role);
|
|
|
|
|
const cricket::TransportInfo* vtinfo =
|
|
|
|
|
desc->GetTransportInfoByName("video_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::CONNECTIONROLE_ACTPASS,
|
|
|
|
|
vtinfo->description.connection_role);
|
2021-08-19 09:12:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributeActive) {
|
|
|
|
|
JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
|
|
|
|
|
std::string sdp_with_dtlssetup = kSdpFullString;
|
|
|
|
|
InjectAfter(kSessionTime, "a=setup:active\r\n", &sdp_with_dtlssetup);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
|
|
|
|
|
cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
|
|
|
|
|
const cricket::TransportInfo* atinfo =
|
|
|
|
|
desc->GetTransportInfoByName("audio_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
|
|
|
|
|
atinfo->description.connection_role);
|
|
|
|
|
const cricket::TransportInfo* vtinfo =
|
|
|
|
|
desc->GetTransportInfoByName("video_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::CONNECTIONROLE_ACTIVE,
|
|
|
|
|
vtinfo->description.connection_role);
|
|
|
|
|
}
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeDtlsSetupAttributePassive) {
|
|
|
|
|
JsepSessionDescription jdesc_with_dtlssetup(kDummyType);
|
|
|
|
|
std::string sdp_with_dtlssetup = kSdpFullString;
|
|
|
|
|
InjectAfter(kSessionTime, "a=setup:passive\r\n", &sdp_with_dtlssetup);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_with_dtlssetup, &jdesc_with_dtlssetup));
|
|
|
|
|
cricket::SessionDescription* desc = jdesc_with_dtlssetup.description();
|
|
|
|
|
const cricket::TransportInfo* atinfo =
|
|
|
|
|
desc->GetTransportInfoByName("audio_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
|
|
|
|
|
atinfo->description.connection_role);
|
|
|
|
|
const cricket::TransportInfo* vtinfo =
|
|
|
|
|
desc->GetTransportInfoByName("video_content_name");
|
|
|
|
|
EXPECT_EQ(cricket::CONNECTIONROLE_PASSIVE,
|
|
|
|
|
vtinfo->description.connection_role);
|
2013-08-23 23:21:25 +00:00
|
|
|
}
|
2014-08-05 19:19:05 +00:00
|
|
|
|
|
|
|
|
// Verifies that the order of the serialized m-lines follows the order of the
|
|
|
|
|
// ContentInfo in SessionDescription, and vise versa for deserialization.
|
|
|
|
|
TEST_F(WebRtcSdpTest, MediaContentOrderMaintainedRoundTrip) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2014-08-05 19:19:05 +00:00
|
|
|
const std::string media_content_sdps[3] = {kSdpAudioString, kSdpVideoString,
|
|
|
|
|
kSdpSctpDataChannelString};
|
|
|
|
|
const cricket::MediaType media_types[3] = {cricket::MEDIA_TYPE_AUDIO,
|
|
|
|
|
cricket::MEDIA_TYPE_VIDEO,
|
|
|
|
|
cricket::MEDIA_TYPE_DATA};
|
|
|
|
|
|
|
|
|
|
// Verifies all 6 permutations.
|
|
|
|
|
for (size_t i = 0; i < 6; ++i) {
|
|
|
|
|
size_t media_content_in_sdp[3];
|
|
|
|
|
// The index of the first media content.
|
|
|
|
|
media_content_in_sdp[0] = i / 2;
|
|
|
|
|
// The index of the second media content.
|
|
|
|
|
media_content_in_sdp[1] = (media_content_in_sdp[0] + i % 2 + 1) % 3;
|
|
|
|
|
// The index of the third media content.
|
|
|
|
|
media_content_in_sdp[2] = (media_content_in_sdp[0] + (i + 1) % 2 + 1) % 3;
|
|
|
|
|
|
|
|
|
|
std::string sdp_string = kSdpSessionString;
|
|
|
|
|
for (size_t i = 0; i < 3; ++i)
|
|
|
|
|
sdp_string += media_content_sdps[media_content_in_sdp[i]];
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_string, &jdesc));
|
|
|
|
|
cricket::SessionDescription* desc = jdesc.description();
|
|
|
|
|
EXPECT_EQ(3u, desc->contents().size());
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 3; ++i) {
|
|
|
|
|
const cricket::MediaContentDescription* mdesc =
|
2017-12-21 15:14:30 -08:00
|
|
|
desc->contents()[i].media_description();
|
2014-08-05 19:19:05 +00:00
|
|
|
EXPECT_EQ(media_types[media_content_in_sdp[i]], mdesc->type());
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string serialized_sdp = webrtc::SdpSerialize(jdesc);
|
2014-08-05 19:19:05 +00:00
|
|
|
EXPECT_EQ(sdp_string, serialized_sdp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-16 17:54:10 -08:00
|
|
|
|
2016-12-12 18:37:36 -08:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeBundleOnlyAttribute) {
|
|
|
|
|
MakeBundleOnlyDescription();
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription deserialized_description(kDummyType);
|
2017-01-03 13:53:47 -08:00
|
|
|
ASSERT_TRUE(
|
2016-12-12 18:37:36 -08:00
|
|
|
SdpDeserialize(kBundleOnlySdpFullString, &deserialized_description));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-03 13:53:47 -08:00
|
|
|
// The semantics of "a=bundle-only" are only defined when it's used in
|
|
|
|
|
// combination with a 0 port on the m= line. We should ignore it if used with a
|
|
|
|
|
// nonzero port.
|
|
|
|
|
TEST_F(WebRtcSdpTest, IgnoreBundleOnlyWithNonzeroPort) {
|
|
|
|
|
// Make the base bundle-only description but unset the bundle-only flag.
|
|
|
|
|
MakeBundleOnlyDescription();
|
|
|
|
|
jdesc_.description()->contents()[1].bundle_only = false;
|
|
|
|
|
|
|
|
|
|
std::string modified_sdp = kBundleOnlySdpFullString;
|
|
|
|
|
Replace("m=video 0", "m=video 9", &modified_sdp);
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription deserialized_description(kDummyType);
|
2017-01-03 13:53:47 -08:00
|
|
|
ASSERT_TRUE(SdpDeserialize(modified_sdp, &deserialized_description));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
|
2016-12-12 18:37:36 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeBundleOnlyAttribute) {
|
|
|
|
|
MakeBundleOnlyDescription();
|
2018-02-01 12:22:16 -08:00
|
|
|
TestSerialize(jdesc_);
|
2016-12-12 18:37:36 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 17:54:10 -08:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializePlanBSessionDescription) {
|
|
|
|
|
MakePlanBDescription();
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription deserialized_description(kDummyType);
|
2016-02-16 17:54:10 -08:00
|
|
|
EXPECT_TRUE(SdpDeserialize(kPlanBSdpFullString, &deserialized_description));
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializePlanBSessionDescription) {
|
|
|
|
|
MakePlanBDescription();
|
2018-02-01 12:22:16 -08:00
|
|
|
TestSerialize(jdesc_);
|
2016-02-16 17:54:10 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-02 16:31:36 -07:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescription) {
|
|
|
|
|
MakeUnifiedPlanDescription();
|
2016-03-09 17:02:30 -08:00
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription deserialized_description(kDummyType);
|
2021-11-04 13:52:31 +00:00
|
|
|
EXPECT_TRUE(
|
2018-04-02 16:31:36 -07:00
|
|
|
SdpDeserialize(kUnifiedPlanSdpFullString, &deserialized_description));
|
2016-03-09 17:02:30 -08:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-02 16:31:36 -07:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescription) {
|
2016-02-16 17:54:10 -08:00
|
|
|
MakeUnifiedPlanDescription();
|
2018-04-02 16:31:36 -07:00
|
|
|
TestSerialize(jdesc_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This tests deserializing a Unified Plan SDP that is compatible with both
|
2018-10-17 10:25:28 -07:00
|
|
|
// Unified Plan and Plan B style SDP, meaning that it contains both "a=ssrc
|
|
|
|
|
// msid" lines and "a=msid " lines. It tests the case for audio/video tracks
|
2018-04-02 16:31:36 -07:00
|
|
|
// with no stream ids and multiple stream ids. For parsing this, the Unified
|
|
|
|
|
// Plan a=msid lines should take priority, because the Plan B style a=ssrc msid
|
|
|
|
|
// lines do not support multiple stream ids and no stream ids.
|
2018-10-17 10:25:28 -07:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionSpecialMsid) {
|
|
|
|
|
// Create both msid lines for Plan B and Unified Plan support.
|
|
|
|
|
MakeUnifiedPlanDescriptionMultipleStreamIds(
|
|
|
|
|
cricket::kMsidSignalingMediaSection |
|
|
|
|
|
cricket::kMsidSignalingSsrcAttribute);
|
2016-02-16 17:54:10 -08:00
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription deserialized_description(kDummyType);
|
2018-04-02 16:31:36 -07:00
|
|
|
EXPECT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullStringWithSpecialMsid,
|
|
|
|
|
&deserialized_description));
|
2016-02-16 17:54:10 -08:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
|
2018-12-04 11:25:05 +01:00
|
|
|
EXPECT_EQ(cricket::kMsidSignalingMediaSection |
|
|
|
|
|
cricket::kMsidSignalingSsrcAttribute,
|
|
|
|
|
deserialized_description.description()->msid_signaling());
|
2016-02-16 17:54:10 -08:00
|
|
|
}
|
|
|
|
|
|
2018-10-17 10:25:28 -07:00
|
|
|
// Tests the serialization of a Unified Plan SDP that is compatible for both
|
|
|
|
|
// Unified Plan and Plan B style SDPs, meaning that it contains both "a=ssrc
|
|
|
|
|
// msid" lines and "a=msid " lines. It tests the case for no stream ids and
|
|
|
|
|
// multiple stream ids.
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionSpecialMsid) {
|
|
|
|
|
// Create both msid lines for Plan B and Unified Plan support.
|
|
|
|
|
MakeUnifiedPlanDescriptionMultipleStreamIds(
|
|
|
|
|
cricket::kMsidSignalingMediaSection |
|
|
|
|
|
cricket::kMsidSignalingSsrcAttribute);
|
|
|
|
|
std::string serialized_sdp = webrtc::SdpSerialize(jdesc_);
|
|
|
|
|
// We explicitly test that the serialized SDP string is equal to the hard
|
|
|
|
|
// coded SDP string. This is necessary, because in the parser "a=msid" lines
|
|
|
|
|
// take priority over "a=ssrc msid" lines. This means if we just used
|
|
|
|
|
// TestSerialize(), it could serialize an SDP that omits "a=ssrc msid" lines,
|
|
|
|
|
// and still pass, because the deserialized version would be the same.
|
|
|
|
|
EXPECT_EQ(kUnifiedPlanSdpFullStringWithSpecialMsid, serialized_sdp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
|
|
|
|
|
// that signal stream IDs) is deserialized appropriately. It tests the case for
|
|
|
|
|
// no stream ids and multiple stream ids.
|
|
|
|
|
TEST_F(WebRtcSdpTest, UnifiedPlanDeserializeSessionDescriptionSpecialMsid) {
|
|
|
|
|
// Only create a=msid lines for strictly Unified Plan stream ID support.
|
|
|
|
|
MakeUnifiedPlanDescriptionMultipleStreamIds(
|
|
|
|
|
cricket::kMsidSignalingMediaSection);
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription deserialized_description(kDummyType);
|
|
|
|
|
std::string unified_plan_sdp_string =
|
|
|
|
|
kUnifiedPlanSdpFullStringWithSpecialMsid;
|
|
|
|
|
RemoveSsrcMsidLinesFromSdpString(&unified_plan_sdp_string);
|
|
|
|
|
EXPECT_TRUE(
|
|
|
|
|
SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tests that a Unified Plan style SDP (does not contain "a=ssrc msid" lines
|
|
|
|
|
// that signal stream IDs) is serialized appropriately. It tests the case for no
|
|
|
|
|
// stream ids and multiple stream ids.
|
|
|
|
|
TEST_F(WebRtcSdpTest, UnifiedPlanSerializeSessionDescriptionSpecialMsid) {
|
|
|
|
|
// Only create a=msid lines for strictly Unified Plan stream ID support.
|
|
|
|
|
MakeUnifiedPlanDescriptionMultipleStreamIds(
|
|
|
|
|
cricket::kMsidSignalingMediaSection);
|
|
|
|
|
|
2018-02-01 12:22:16 -08:00
|
|
|
TestSerialize(jdesc_);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-03 11:16:33 -07:00
|
|
|
// This tests that a Unified Plan SDP with no a=ssrc lines is
|
|
|
|
|
// serialized/deserialized appropriately. In this case the
|
|
|
|
|
// MediaContentDescription will contain a StreamParams object that doesn't have
|
|
|
|
|
// any SSRCs. Vice versa, this will be created upon deserializing an SDP with no
|
|
|
|
|
// SSRC lines.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeUnifiedPlanSessionDescriptionNoSsrcSignaling) {
|
|
|
|
|
MakeUnifiedPlanDescription();
|
|
|
|
|
RemoveSsrcSignalingFromStreamParams();
|
|
|
|
|
std::string unified_plan_sdp_string = kUnifiedPlanSdpFullString;
|
|
|
|
|
RemoveSsrcLinesFromSdpString(&unified_plan_sdp_string);
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription deserialized_description(kDummyType);
|
|
|
|
|
EXPECT_TRUE(
|
|
|
|
|
SdpDeserialize(unified_plan_sdp_string, &deserialized_description));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, deserialized_description));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeUnifiedPlanSessionDescriptionNoSsrcSignaling) {
|
|
|
|
|
MakeUnifiedPlanDescription();
|
|
|
|
|
RemoveSsrcSignalingFromStreamParams();
|
|
|
|
|
|
|
|
|
|
TestSerialize(jdesc_);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-01 12:22:16 -08:00
|
|
|
TEST_F(WebRtcSdpTest, EmptyDescriptionHasNoMsidSignaling) {
|
|
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
|
|
|
|
ASSERT_TRUE(SdpDeserialize(kSdpSessionString, &jsep_desc));
|
|
|
|
|
EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DataChannelOnlyHasNoMsidSignaling) {
|
|
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
|
|
|
|
std::string sdp = kSdpSessionString;
|
|
|
|
|
sdp += kSdpSctpDataChannelString;
|
|
|
|
|
ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
EXPECT_EQ(0, jsep_desc.description()->msid_signaling());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, PlanBHasSsrcAttributeMsidSignaling) {
|
|
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
|
|
|
|
ASSERT_TRUE(SdpDeserialize(kPlanBSdpFullString, &jsep_desc));
|
|
|
|
|
EXPECT_EQ(cricket::kMsidSignalingSsrcAttribute,
|
|
|
|
|
jsep_desc.description()->msid_signaling());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, UnifiedPlanHasMediaSectionMsidSignaling) {
|
|
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
|
|
|
|
ASSERT_TRUE(SdpDeserialize(kUnifiedPlanSdpFullString, &jsep_desc));
|
|
|
|
|
EXPECT_EQ(cricket::kMsidSignalingMediaSection,
|
|
|
|
|
jsep_desc.description()->msid_signaling());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char kMediaSectionMsidLine[] = "a=msid:local_stream_1 audio_track_id_1";
|
|
|
|
|
const char kSsrcAttributeMsidLine[] =
|
|
|
|
|
"a=ssrc:1 msid:local_stream_1 audio_track_id_1";
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeOnlyMediaSectionMsid) {
|
|
|
|
|
jdesc_.description()->set_msid_signaling(cricket::kMsidSignalingMediaSection);
|
|
|
|
|
std::string sdp = webrtc::SdpSerialize(jdesc_);
|
|
|
|
|
|
|
|
|
|
EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
|
|
|
|
|
EXPECT_EQ(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeOnlySsrcAttributeMsid) {
|
|
|
|
|
jdesc_.description()->set_msid_signaling(
|
|
|
|
|
cricket::kMsidSignalingSsrcAttribute);
|
|
|
|
|
std::string sdp = webrtc::SdpSerialize(jdesc_);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(std::string::npos, sdp.find(kMediaSectionMsidLine));
|
|
|
|
|
EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeBothMediaSectionAndSsrcAttributeMsid) {
|
|
|
|
|
jdesc_.description()->set_msid_signaling(
|
|
|
|
|
cricket::kMsidSignalingMediaSection |
|
|
|
|
|
cricket::kMsidSignalingSsrcAttribute);
|
|
|
|
|
std::string sdp = webrtc::SdpSerialize(jdesc_);
|
|
|
|
|
|
|
|
|
|
EXPECT_NE(std::string::npos, sdp.find(kMediaSectionMsidLine));
|
|
|
|
|
EXPECT_NE(std::string::npos, sdp.find(kSsrcAttributeMsidLine));
|
2016-02-16 17:54:10 -08:00
|
|
|
}
|
2016-09-28 10:04:34 -07:00
|
|
|
|
2016-12-13 16:37:06 -08:00
|
|
|
// Regression test for integer overflow bug:
|
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=648071
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeLargeBandwidthLimit) {
|
|
|
|
|
// Bandwidth attribute is the max signed 32-bit int, which will get
|
|
|
|
|
// multiplied by 1000 and cause int overflow if not careful.
|
2017-01-20 12:43:58 -08:00
|
|
|
static const char kSdpWithLargeBandwidth[] =
|
2016-12-13 16:37:06 -08:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"b=AS:2147483647\r\n"
|
|
|
|
|
"foo=fail\r\n";
|
|
|
|
|
|
|
|
|
|
ExpectParseFailure(std::string(kSdpWithLargeBandwidth), "foo=fail");
|
|
|
|
|
}
|
2017-01-20 12:43:58 -08:00
|
|
|
|
2017-08-02 11:26:34 -07:00
|
|
|
// Similar to the above, except that negative values are illegal, not just
|
|
|
|
|
// error-prone as large values are.
|
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=675361
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializingNegativeBandwidthLimitFails) {
|
|
|
|
|
static const char kSdpWithNegativeBandwidth[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"b=AS:-1000\r\n";
|
|
|
|
|
|
|
|
|
|
ExpectParseFailure(std::string(kSdpWithNegativeBandwidth), "b=AS:-1000");
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-03 17:49:30 -07:00
|
|
|
// An exception to the above rule: a value of -1 for b=AS should just be
|
|
|
|
|
// ignored, resulting in "kAutoBandwidth" in the deserialized object.
|
|
|
|
|
// Applications historically may be using "b=AS:-1" to mean "no bandwidth
|
|
|
|
|
// limit", but this is now what ommitting the attribute entirely will do, so
|
|
|
|
|
// ignoring it will have the intended effect.
|
|
|
|
|
TEST_F(WebRtcSdpTest, BandwidthLimitOfNegativeOneIgnored) {
|
|
|
|
|
static const char kSdpWithBandwidthOfNegativeOne[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=video 3457 RTP/SAVPF 120\r\n"
|
|
|
|
|
"b=AS:-1\r\n";
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2017-08-03 17:49:30 -07:00
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpWithBandwidthOfNegativeOne, &jdesc_output));
|
|
|
|
|
const VideoContentDescription* vcd =
|
2017-12-21 15:14:30 -08:00
|
|
|
GetFirstVideoContentDescription(jdesc_output.description());
|
|
|
|
|
ASSERT_TRUE(vcd);
|
2017-08-03 17:49:30 -07:00
|
|
|
EXPECT_EQ(cricket::kAutoBandwidth, vcd->bandwidth());
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-20 12:43:58 -08:00
|
|
|
// Test that "ufrag"/"pwd" in the candidate line itself are ignored, and only
|
|
|
|
|
// the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
|
|
|
|
|
// Regression test for:
|
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=681286
|
|
|
|
|
TEST_F(WebRtcSdpTest, IceCredentialsInCandidateStringIgnored) {
|
|
|
|
|
// Important piece is "ufrag foo pwd bar".
|
|
|
|
|
static const char kSdpWithIceCredentialsInCandidateString[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2 ufrag foo pwd bar\r\n";
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2017-01-20 12:43:58 -08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
|
SdpDeserialize(kSdpWithIceCredentialsInCandidateString, &jdesc_output));
|
|
|
|
|
const IceCandidateCollection* candidates = jdesc_output.candidates(0);
|
2018-09-06 12:12:28 +02:00
|
|
|
ASSERT_NE(nullptr, candidates);
|
|
|
|
|
ASSERT_EQ(1U, candidates->count());
|
|
|
|
|
cricket::Candidate c = candidates->at(0)->candidate();
|
|
|
|
|
EXPECT_EQ("ufrag_voice", c.username());
|
|
|
|
|
EXPECT_EQ("pwd_voice", c.password());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test that attribute lines "a=ice-ufrag-something"/"a=ice-pwd-something" are
|
|
|
|
|
// ignored, and only the "a=ice-ufrag"/"a=ice-pwd" attributes are used.
|
|
|
|
|
// Regression test for:
|
|
|
|
|
// https://bugs.chromium.org/p/webrtc/issues/detail?id=9712
|
|
|
|
|
TEST_F(WebRtcSdpTest, AttributeWithPartialMatchingNameIsIgnored) {
|
|
|
|
|
static const char kSdpWithFooIceCredentials[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag-something:foo\r\na=ice-pwd-something:bar\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 1234 typ host "
|
|
|
|
|
"generation 2\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(kSdpWithFooIceCredentials, &jdesc_output));
|
|
|
|
|
const IceCandidateCollection* candidates = jdesc_output.candidates(0);
|
2017-01-20 12:43:58 -08:00
|
|
|
ASSERT_NE(nullptr, candidates);
|
2018-07-03 12:53:23 +02:00
|
|
|
ASSERT_EQ(1U, candidates->count());
|
2017-01-20 12:43:58 -08:00
|
|
|
cricket::Candidate c = candidates->at(0)->candidate();
|
|
|
|
|
EXPECT_EQ("ufrag_voice", c.username());
|
|
|
|
|
EXPECT_EQ("pwd_voice", c.password());
|
|
|
|
|
}
|
2017-02-10 12:35:05 -08:00
|
|
|
|
|
|
|
|
// Test that SDP with an invalid port number in "a=candidate" lines is
|
|
|
|
|
// rejected, without crashing.
|
|
|
|
|
// Regression test for:
|
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=677029
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeInvalidPortInCandidateAttribute) {
|
|
|
|
|
static const char kSdpWithInvalidCandidatePort[] =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=ice-ufrag:ufrag_voice\r\na=ice-pwd:pwd_voice\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=candidate:a0+B/1 1 udp 2130706432 192.168.1.5 12345678 typ host "
|
|
|
|
|
"generation 2 raddr 192.168.1.1 rport 87654321\r\n";
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2017-02-10 12:35:05 -08:00
|
|
|
EXPECT_FALSE(SdpDeserialize(kSdpWithInvalidCandidatePort, &jdesc_output));
|
|
|
|
|
}
|
2017-02-10 17:26:22 -08:00
|
|
|
|
2022-12-05 19:59:10 +01:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithStreamIdAndTrackId) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id track_id\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
auto stream = jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->streams()[0];
|
|
|
|
|
ASSERT_EQ(stream.stream_ids().size(), 1u);
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[0], "stream_id");
|
|
|
|
|
EXPECT_EQ(stream.id, "track_id");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithEmptyStreamIdAndTrackId) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:- track_id\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
auto stream = jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->streams()[0];
|
|
|
|
|
ASSERT_EQ(stream.stream_ids().size(), 0u);
|
|
|
|
|
EXPECT_EQ(stream.id, "track_id");
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-10 17:26:22 -08:00
|
|
|
// Test that "a=msid" with a missing track ID is rejected and doesn't crash.
|
|
|
|
|
// Regression test for:
|
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=686405
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingTrackId) {
|
2022-12-05 19:59:10 +01:00
|
|
|
std::string sdp =
|
2017-02-10 17:26:22 -08:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id \r\n";
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2022-12-05 19:59:10 +01:00
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
|
2017-02-10 17:26:22 -08:00
|
|
|
}
|
|
|
|
|
|
2022-12-08 12:46:20 +01:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutColon) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAttributes) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithTooManySpaces) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id track_id bogus\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithDifferentTrackIds) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id track_id\r\n"
|
|
|
|
|
"a=msid:stream_id2 track_id2\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 13:20:01 +01:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppData) {
|
2022-12-05 19:59:10 +01:00
|
|
|
std::string sdp =
|
2022-12-05 13:20:01 +01:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2022-12-05 19:59:10 +01:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
auto stream = jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->streams()[0];
|
|
|
|
|
ASSERT_EQ(stream.stream_ids().size(), 1u);
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[0], "stream_id");
|
|
|
|
|
// Track id is randomly generated.
|
|
|
|
|
EXPECT_NE(stream.id, "");
|
2022-12-05 13:20:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataTwoStreams) {
|
2022-12-05 19:59:10 +01:00
|
|
|
std::string sdp =
|
2022-12-05 13:20:01 +01:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id\r\n"
|
|
|
|
|
"a=msid:stream_id2\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2022-12-05 19:59:10 +01:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
auto stream = jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->streams()[0];
|
|
|
|
|
ASSERT_EQ(stream.stream_ids().size(), 2u);
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[0], "stream_id");
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[1], "stream_id2");
|
|
|
|
|
// Track id is randomly generated.
|
|
|
|
|
EXPECT_NE(stream.id, "");
|
2022-12-05 13:20:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataDuplicate) {
|
2022-12-05 19:59:10 +01:00
|
|
|
std::string sdp =
|
2022-12-05 13:20:01 +01:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id\r\n"
|
|
|
|
|
"a=msid:stream_id\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2022-12-05 19:59:10 +01:00
|
|
|
// This is somewhat silly but accept it. Duplicates get filtered.
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
auto stream = jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->streams()[0];
|
|
|
|
|
ASSERT_EQ(stream.stream_ids().size(), 1u);
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[0], "stream_id");
|
|
|
|
|
// Track id is randomly generated.
|
|
|
|
|
EXPECT_NE(stream.id, "");
|
2022-12-05 13:20:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataMixed) {
|
2022-12-05 19:59:10 +01:00
|
|
|
std::string sdp =
|
2022-12-05 13:20:01 +01:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id\r\n"
|
2022-12-05 19:59:10 +01:00
|
|
|
"a=msid:stream_id2 track_id\r\n";
|
2022-12-05 13:20:01 +01:00
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
// Mixing the syntax like this is not a good idea but we accept it
|
|
|
|
|
// and the result is the second track_id.
|
2022-12-05 19:59:10 +01:00
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
auto stream = jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->streams()[0];
|
|
|
|
|
ASSERT_EQ(stream.stream_ids().size(), 2u);
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[0], "stream_id");
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[1], "stream_id2");
|
|
|
|
|
|
|
|
|
|
// Track id is taken from second line.
|
|
|
|
|
EXPECT_EQ(stream.id, "track_id");
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 12:46:20 +01:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataMixed2) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id track_id\r\n"
|
|
|
|
|
"a=msid:stream_id2\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
// Mixing the syntax like this is not a good idea but we accept it
|
|
|
|
|
// and the result is the second track_id.
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
auto stream = jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->streams()[0];
|
|
|
|
|
ASSERT_EQ(stream.stream_ids().size(), 2u);
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[0], "stream_id");
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[1], "stream_id2");
|
|
|
|
|
|
|
|
|
|
// Track id is taken from first line.
|
|
|
|
|
EXPECT_EQ(stream.id, "track_id");
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 19:59:10 +01:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithoutAppDataMixedNoStream) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid:stream_id\r\n"
|
|
|
|
|
"a=msid:- track_id\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
// This is somewhat undefined behavior but accept it and expect a single
|
|
|
|
|
// stream.
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
auto stream = jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->streams()[0];
|
|
|
|
|
ASSERT_EQ(stream.stream_ids().size(), 1u);
|
|
|
|
|
EXPECT_EQ(stream.stream_ids()[0], "stream_id");
|
|
|
|
|
EXPECT_EQ(stream.id, "track_id");
|
2022-12-05 13:20:01 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-10 17:26:22 -08:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeMsidAttributeWithMissingStreamId) {
|
2022-12-05 19:59:10 +01:00
|
|
|
std::string sdp =
|
2017-02-10 17:26:22 -08:00
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n"
|
|
|
|
|
"a=msid: track_id\r\n";
|
|
|
|
|
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
2022-12-05 19:59:10 +01:00
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc_output));
|
2017-02-10 17:26:22 -08:00
|
|
|
}
|
2017-03-21 11:04:53 -07:00
|
|
|
|
|
|
|
|
// Tests that if both session-level address and media-level address exist, use
|
|
|
|
|
// the media-level address.
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseConnectionData) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
|
|
|
|
|
// Sesssion-level address.
|
|
|
|
|
std::string sdp = kSdpFullString;
|
|
|
|
|
InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
|
|
|
|
|
const auto& content1 = jsep_desc.description()->contents()[0];
|
|
|
|
|
EXPECT_EQ("74.125.127.126:2345",
|
2017-12-21 15:14:30 -08:00
|
|
|
content1.media_description()->connection_address().ToString());
|
2017-03-21 11:04:53 -07:00
|
|
|
const auto& content2 = jsep_desc.description()->contents()[1];
|
|
|
|
|
EXPECT_EQ("74.125.224.39:3457",
|
2017-12-21 15:14:30 -08:00
|
|
|
content2.media_description()->connection_address().ToString());
|
2017-03-21 11:04:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tests that the session-level connection address will be used if the media
|
|
|
|
|
// level-addresses are not specified.
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseConnectionDataSessionLevelOnly) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
|
|
|
|
|
// Sesssion-level address.
|
|
|
|
|
std::string sdp = kSdpString;
|
|
|
|
|
InjectAfter("s=-\r\n", "c=IN IP4 192.168.0.3\r\n", &sdp);
|
|
|
|
|
// Remove the media level addresses.
|
|
|
|
|
Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
|
|
|
|
|
Replace("c=IN IP4 0.0.0.0\r\n", "", &sdp);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
|
|
|
|
|
const auto& content1 = jsep_desc.description()->contents()[0];
|
|
|
|
|
EXPECT_EQ("192.168.0.3:9",
|
2017-12-21 15:14:30 -08:00
|
|
|
content1.media_description()->connection_address().ToString());
|
2017-03-21 11:04:53 -07:00
|
|
|
const auto& content2 = jsep_desc.description()->contents()[1];
|
|
|
|
|
EXPECT_EQ("192.168.0.3:9",
|
2017-12-21 15:14:30 -08:00
|
|
|
content2.media_description()->connection_address().ToString());
|
2017-03-21 11:04:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseConnectionDataIPv6) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
|
|
|
|
|
std::string sdp = kSdpString;
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
Replace("m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP4 0.0.0.0\r\n",
|
|
|
|
|
"m=audio 9 RTP/SAVPF 111 103 104\r\nc=IN IP6 "
|
|
|
|
|
"2001:0db8:85a3:0000:0000:8a2e:0370:7335\r\n",
|
|
|
|
|
&sdp);
|
|
|
|
|
Replace("m=video 9 RTP/SAVPF 120\r\nc=IN IP4 0.0.0.0\r\n",
|
|
|
|
|
"m=video 9 RTP/SAVPF 120\r\nc=IN IP6 "
|
|
|
|
|
"2001:0db8:85a3:0000:0000:8a2e:0370:7336\r\n",
|
|
|
|
|
&sdp);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
const auto& content1 = jsep_desc.description()->contents()[0];
|
|
|
|
|
EXPECT_EQ("[2001:db8:85a3::8a2e:370:7335]:9",
|
2017-12-21 15:14:30 -08:00
|
|
|
content1.media_description()->connection_address().ToString());
|
2017-03-21 11:04:53 -07:00
|
|
|
const auto& content2 = jsep_desc.description()->contents()[1];
|
|
|
|
|
EXPECT_EQ("[2001:db8:85a3::8a2e:370:7336]:9",
|
2017-12-21 15:14:30 -08:00
|
|
|
content2.media_description()->connection_address().ToString());
|
2017-03-21 11:04:53 -07:00
|
|
|
}
|
|
|
|
|
|
2019-02-08 12:53:06 -08:00
|
|
|
// Test that a c= line that contains a hostname connection address can be
|
|
|
|
|
// parsed.
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseConnectionDataWithHostnameConnectionAddress) {
|
|
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
|
|
|
|
std::string sdp = kSdpString;
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
|
|
|
|
|
sdp = kSdpString;
|
|
|
|
|
Replace("c=IN IP4 0.0.0.0\r\n", "c=IN IP4 example.local\r\n", &sdp);
|
|
|
|
|
Replace("c=IN IP4 0.0.0.0\r\n", "c=IN IP4 example.local\r\n", &sdp);
|
|
|
|
|
ASSERT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
|
|
|
|
|
ASSERT_NE(nullptr, jsep_desc.description());
|
|
|
|
|
const auto& content1 = jsep_desc.description()->contents()[0];
|
|
|
|
|
EXPECT_EQ("example.local:9",
|
|
|
|
|
content1.media_description()->connection_address().ToString());
|
|
|
|
|
const auto& content2 = jsep_desc.description()->contents()[1];
|
|
|
|
|
EXPECT_EQ("example.local:9",
|
|
|
|
|
content2.media_description()->connection_address().ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test that the invalid or unsupported connection data cannot be parsed.
|
2017-03-21 11:04:53 -07:00
|
|
|
TEST_F(WebRtcSdpTest, ParseConnectionDataFailure) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
std::string sdp = kSdpString;
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
|
|
|
|
|
// Unsupported multicast IPv4 address.
|
|
|
|
|
sdp = kSdpFullString;
|
|
|
|
|
Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP4 74.125.224.39/127\r\n", &sdp);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
|
|
|
|
|
// Unsupported multicast IPv6 address.
|
|
|
|
|
sdp = kSdpFullString;
|
|
|
|
|
Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 ::1/3\r\n", &sdp);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
|
|
|
|
|
// Mismatched address type.
|
|
|
|
|
sdp = kSdpFullString;
|
|
|
|
|
Replace("c=IN IP4 74.125.224.39\r\n", "c=IN IP6 74.125.224.39\r\n", &sdp);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
|
|
|
|
|
sdp = kSdpFullString;
|
|
|
|
|
Replace("c=IN IP4 74.125.224.39\r\n",
|
|
|
|
|
"c=IN IP4 2001:0db8:85a3:0000:0000:8a2e:0370:7334\r\n", &sdp);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeAndDeserializeWithConnectionAddress) {
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription expected_jsep(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
MakeDescriptionWithoutCandidates(&expected_jsep);
|
|
|
|
|
// Serialization.
|
2018-02-01 12:22:16 -08:00
|
|
|
std::string message = webrtc::SdpSerialize(expected_jsep);
|
2017-03-21 11:04:53 -07:00
|
|
|
// Deserialization.
|
2017-12-07 10:27:41 -08:00
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
2017-03-21 11:04:53 -07:00
|
|
|
EXPECT_TRUE(SdpDeserialize(message, &jdesc));
|
2017-12-21 15:14:30 -08:00
|
|
|
auto audio_desc = jdesc.description()
|
|
|
|
|
->GetContentByName(kAudioContentName)
|
|
|
|
|
->media_description();
|
|
|
|
|
auto video_desc = jdesc.description()
|
|
|
|
|
->GetContentByName(kVideoContentName)
|
|
|
|
|
->media_description();
|
2017-03-21 11:04:53 -07:00
|
|
|
EXPECT_EQ(audio_desc_->connection_address().ToString(),
|
|
|
|
|
audio_desc->connection_address().ToString());
|
|
|
|
|
EXPECT_EQ(video_desc_->connection_address().ToString(),
|
|
|
|
|
video_desc->connection_address().ToString());
|
|
|
|
|
}
|
2018-04-16 10:45:24 -07:00
|
|
|
|
|
|
|
|
// RFC4566 says "If a session has no meaningful name, the value "s= " SHOULD be
|
|
|
|
|
// used (i.e., a single space as the session name)." So we should accept that.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeEmptySessionName) {
|
|
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
|
|
|
|
std::string sdp = kSdpString;
|
|
|
|
|
Replace("s=-\r\n", "s= \r\n", &sdp);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jsep_desc));
|
|
|
|
|
}
|
2018-12-03 11:35:05 -08:00
|
|
|
|
|
|
|
|
// Simulcast malformed input test for invalid format.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSimulcastNegative_EmptyAttribute) {
|
2022-04-07 09:54:51 +00:00
|
|
|
ExpectParseFailureWithNewLines(
|
|
|
|
|
"a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n", "a=simulcast:\r\n",
|
|
|
|
|
"a=simulcast:");
|
2018-12-03 11:35:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tests that duplicate simulcast entries in the SDP triggers a parse failure.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSimulcastNegative_DuplicateAttribute) {
|
2022-04-07 09:54:51 +00:00
|
|
|
ExpectParseFailureWithNewLines(
|
|
|
|
|
"a=ssrc:3 msid:local_stream_1 video_track_id_1\r\n",
|
|
|
|
|
"a=simulcast:send 1\r\na=simulcast:recv 2\r\n", "a=simulcast:");
|
2018-12-03 11:35:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validates that deserialization uses the a=simulcast: attribute
|
|
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeSimulcastAttribute) {
|
2018-12-11 15:30:11 -08:00
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send\r\n";
|
|
|
|
|
sdp += "a=rid:2 send\r\n";
|
|
|
|
|
sdp += "a=rid:3 send\r\n";
|
|
|
|
|
sdp += "a=rid:4 recv\r\n";
|
|
|
|
|
sdp += "a=rid:5 recv\r\n";
|
|
|
|
|
sdp += "a=rid:6 recv\r\n";
|
2018-12-03 11:35:05 -08:00
|
|
|
sdp += "a=simulcast:send 1,2;3 recv 4;5;6\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_TRUE(media->HasSimulcast());
|
|
|
|
|
EXPECT_EQ(2ul, media->simulcast_description().send_layers().size());
|
|
|
|
|
EXPECT_EQ(3ul, media->simulcast_description().receive_layers().size());
|
2018-12-11 15:30:11 -08:00
|
|
|
EXPECT_FALSE(media->streams().empty());
|
|
|
|
|
const std::vector<RidDescription>& rids = media->streams()[0].rids();
|
|
|
|
|
CompareRidDescriptionIds(rids, {"1", "2", "3"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validates that deserialization removes rids that do not appear in SDP
|
|
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeSimulcastAttributeRemovesUnknownRids) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send\r\n";
|
|
|
|
|
sdp += "a=rid:3 send\r\n";
|
|
|
|
|
sdp += "a=rid:4 recv\r\n";
|
|
|
|
|
sdp += "a=simulcast:send 1,2;3 recv 4;5,6\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_TRUE(media->HasSimulcast());
|
|
|
|
|
const SimulcastDescription& simulcast = media->simulcast_description();
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().size());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.receive_layers().size());
|
|
|
|
|
|
|
|
|
|
std::vector<SimulcastLayer> all_send_layers =
|
|
|
|
|
simulcast.send_layers().GetAllLayers();
|
|
|
|
|
EXPECT_EQ(2ul, all_send_layers.size());
|
2019-01-28 17:25:26 -08:00
|
|
|
EXPECT_EQ(0,
|
|
|
|
|
absl::c_count_if(all_send_layers, [](const SimulcastLayer& layer) {
|
|
|
|
|
return layer.rid == "2";
|
|
|
|
|
}));
|
2018-12-11 15:30:11 -08:00
|
|
|
|
|
|
|
|
std::vector<SimulcastLayer> all_receive_layers =
|
|
|
|
|
simulcast.receive_layers().GetAllLayers();
|
|
|
|
|
ASSERT_EQ(1ul, all_receive_layers.size());
|
|
|
|
|
EXPECT_EQ("4", all_receive_layers[0].rid);
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(media->streams().empty());
|
|
|
|
|
const std::vector<RidDescription>& rids = media->streams()[0].rids();
|
|
|
|
|
CompareRidDescriptionIds(rids, {"1", "3"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validates that Simulcast removes rids that appear in both send and receive.
|
|
|
|
|
TEST_F(WebRtcSdpTest,
|
|
|
|
|
TestDeserializeSimulcastAttributeRemovesDuplicateSendReceive) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send\r\n";
|
|
|
|
|
sdp += "a=rid:2 send\r\n";
|
|
|
|
|
sdp += "a=rid:3 send\r\n";
|
|
|
|
|
sdp += "a=rid:4 recv\r\n";
|
|
|
|
|
sdp += "a=simulcast:send 1;2;3 recv 2;4\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_TRUE(media->HasSimulcast());
|
|
|
|
|
const SimulcastDescription& simulcast = media->simulcast_description();
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().size());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.receive_layers().size());
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.receive_layers().GetAllLayers().size());
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(media->streams().empty());
|
|
|
|
|
const std::vector<RidDescription>& rids = media->streams()[0].rids();
|
|
|
|
|
CompareRidDescriptionIds(rids, {"1", "3"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ignores empty rid line.
|
|
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeIgnoresEmptyRidLines) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send\r\n";
|
|
|
|
|
sdp += "a=rid:2 send\r\n";
|
|
|
|
|
sdp += "a=rid\r\n"; // Should ignore this line.
|
|
|
|
|
sdp += "a=rid:\r\n"; // Should ignore this line.
|
|
|
|
|
sdp += "a=simulcast:send 1;2\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_TRUE(media->HasSimulcast());
|
|
|
|
|
const SimulcastDescription& simulcast = media->simulcast_description();
|
|
|
|
|
EXPECT_TRUE(simulcast.receive_layers().empty());
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().size());
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(media->streams().empty());
|
|
|
|
|
const std::vector<RidDescription>& rids = media->streams()[0].rids();
|
|
|
|
|
CompareRidDescriptionIds(rids, {"1", "2"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ignores malformed rid lines.
|
|
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeIgnoresMalformedRidLines) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send pt=\r\n"; // Should ignore this line.
|
|
|
|
|
sdp += "a=rid:2 receive\r\n"; // Should ignore this line.
|
|
|
|
|
sdp += "a=rid:3 max-width=720;pt=120\r\n"; // Should ignore this line.
|
|
|
|
|
sdp += "a=rid:4\r\n"; // Should ignore this line.
|
|
|
|
|
sdp += "a=rid:5 send\r\n";
|
|
|
|
|
sdp += "a=simulcast:send 1,2,3;4,5\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_TRUE(media->HasSimulcast());
|
|
|
|
|
const SimulcastDescription& simulcast = media->simulcast_description();
|
|
|
|
|
EXPECT_TRUE(simulcast.receive_layers().empty());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.send_layers().size());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.send_layers().GetAllLayers().size());
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(media->streams().empty());
|
|
|
|
|
const std::vector<RidDescription>& rids = media->streams()[0].rids();
|
|
|
|
|
CompareRidDescriptionIds(rids, {"5"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Removes RIDs that specify a different format than the m= section.
|
|
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeRemovesRidsWithInvalidCodec) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send pt=121,120\r\n"; // Should remove 121 and keep RID.
|
|
|
|
|
sdp += "a=rid:2 send pt=121\r\n"; // Should remove RID altogether.
|
|
|
|
|
sdp += "a=simulcast:send 1;2\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_TRUE(media->HasSimulcast());
|
|
|
|
|
const SimulcastDescription& simulcast = media->simulcast_description();
|
|
|
|
|
EXPECT_TRUE(simulcast.receive_layers().empty());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.send_layers().size());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.send_layers().GetAllLayers().size());
|
|
|
|
|
EXPECT_EQ("1", simulcast.send_layers()[0][0].rid);
|
|
|
|
|
EXPECT_EQ(1ul, media->streams().size());
|
|
|
|
|
const std::vector<RidDescription>& rids = media->streams()[0].rids();
|
|
|
|
|
EXPECT_EQ(1ul, rids.size());
|
|
|
|
|
EXPECT_EQ("1", rids[0].rid);
|
|
|
|
|
EXPECT_EQ(1ul, rids[0].payload_types.size());
|
|
|
|
|
EXPECT_EQ(120, rids[0].payload_types[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ignores duplicate rid lines
|
|
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeIgnoresDuplicateRidLines) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send\r\n";
|
|
|
|
|
sdp += "a=rid:2 send\r\n";
|
|
|
|
|
sdp += "a=rid:2 send\r\n";
|
|
|
|
|
sdp += "a=rid:3 send\r\n";
|
|
|
|
|
sdp += "a=rid:4 recv\r\n";
|
|
|
|
|
sdp += "a=simulcast:send 1,2;3 recv 4\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_TRUE(media->HasSimulcast());
|
|
|
|
|
const SimulcastDescription& simulcast = media->simulcast_description();
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().size());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.receive_layers().size());
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
|
|
|
|
|
EXPECT_EQ(1ul, simulcast.receive_layers().GetAllLayers().size());
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(media->streams().empty());
|
|
|
|
|
const std::vector<RidDescription>& rids = media->streams()[0].rids();
|
|
|
|
|
CompareRidDescriptionIds(rids, {"1", "3"});
|
2018-12-03 11:35:05 -08:00
|
|
|
}
|
|
|
|
|
|
2019-07-02 20:27:42 +02:00
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeRidSendDirection) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 recv\r\n";
|
|
|
|
|
sdp += "a=rid:2 recv\r\n";
|
|
|
|
|
sdp += "a=simulcast:send 1;2\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_FALSE(media->HasSimulcast());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeRidRecvDirection) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send\r\n";
|
|
|
|
|
sdp += "a=rid:2 send\r\n";
|
|
|
|
|
sdp += "a=simulcast:recv 1;2\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_FALSE(media->HasSimulcast());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, TestDeserializeIgnoresWrongRidDirectionLines) {
|
|
|
|
|
std::string sdp = kUnifiedPlanSdpFullStringNoSsrc;
|
|
|
|
|
sdp += "a=rid:1 send\r\n";
|
|
|
|
|
sdp += "a=rid:2 send\r\n";
|
|
|
|
|
sdp += "a=rid:3 send\r\n";
|
|
|
|
|
sdp += "a=rid:4 recv\r\n";
|
|
|
|
|
sdp += "a=rid:5 recv\r\n";
|
|
|
|
|
sdp += "a=rid:6 recv\r\n";
|
|
|
|
|
sdp += "a=simulcast:send 1;5;3 recv 4;2;6\r\n";
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
const cricket::ContentInfos& contents = output.description()->contents();
|
|
|
|
|
const cricket::MediaContentDescription* media =
|
|
|
|
|
contents.back().media_description();
|
|
|
|
|
EXPECT_TRUE(media->HasSimulcast());
|
|
|
|
|
const SimulcastDescription& simulcast = media->simulcast_description();
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().size());
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.receive_layers().size());
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.send_layers().GetAllLayers().size());
|
|
|
|
|
EXPECT_EQ(2ul, simulcast.receive_layers().GetAllLayers().size());
|
|
|
|
|
|
|
|
|
|
EXPECT_FALSE(media->streams().empty());
|
|
|
|
|
const std::vector<RidDescription>& rids = media->streams()[0].rids();
|
|
|
|
|
CompareRidDescriptionIds(rids, {"1", "3"});
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-03 11:35:05 -08:00
|
|
|
// Simulcast serialization integration test.
|
|
|
|
|
// This test will serialize and deserialize the description and compare.
|
|
|
|
|
// More detailed tests for parsing simulcast can be found in
|
|
|
|
|
// unit tests for SdpSerializer.
|
|
|
|
|
TEST_F(WebRtcSdpTest, SerializeSimulcast_ComplexSerialization) {
|
2018-12-11 15:30:11 -08:00
|
|
|
MakeUnifiedPlanDescription(/* use_ssrcs = */ false);
|
2018-12-03 11:35:05 -08:00
|
|
|
auto description = jdesc_.description();
|
|
|
|
|
auto media = description->GetContentDescriptionByName(kVideoContentName3);
|
2018-12-11 15:30:11 -08:00
|
|
|
ASSERT_EQ(media->streams().size(), 1ul);
|
|
|
|
|
StreamParams& send_stream = media->mutable_streams()[0];
|
|
|
|
|
std::vector<RidDescription> send_rids;
|
|
|
|
|
send_rids.push_back(RidDescription("1", RidDirection::kSend));
|
|
|
|
|
send_rids.push_back(RidDescription("2", RidDirection::kSend));
|
|
|
|
|
send_rids.push_back(RidDescription("3", RidDirection::kSend));
|
|
|
|
|
send_rids.push_back(RidDescription("4", RidDirection::kSend));
|
|
|
|
|
send_stream.set_rids(send_rids);
|
2019-07-03 12:47:54 +02:00
|
|
|
std::vector<RidDescription> receive_rids;
|
|
|
|
|
receive_rids.push_back(RidDescription("5", RidDirection::kReceive));
|
|
|
|
|
receive_rids.push_back(RidDescription("6", RidDirection::kReceive));
|
|
|
|
|
receive_rids.push_back(RidDescription("7", RidDirection::kReceive));
|
|
|
|
|
media->set_receive_rids(receive_rids);
|
2018-12-11 15:30:11 -08:00
|
|
|
|
2018-12-03 11:35:05 -08:00
|
|
|
SimulcastDescription& simulcast = media->simulcast_description();
|
|
|
|
|
simulcast.send_layers().AddLayerWithAlternatives(
|
|
|
|
|
{SimulcastLayer("2", false), SimulcastLayer("1", true)});
|
|
|
|
|
simulcast.send_layers().AddLayerWithAlternatives(
|
|
|
|
|
{SimulcastLayer("4", false), SimulcastLayer("3", false)});
|
2019-07-03 12:47:54 +02:00
|
|
|
simulcast.receive_layers().AddLayer({SimulcastLayer("5", false)});
|
|
|
|
|
simulcast.receive_layers().AddLayer({SimulcastLayer("6", false)});
|
|
|
|
|
simulcast.receive_layers().AddLayer({SimulcastLayer("7", false)});
|
2018-12-03 11:35:05 -08:00
|
|
|
|
|
|
|
|
TestSerialize(jdesc_);
|
|
|
|
|
}
|
2018-12-18 15:55:30 -08:00
|
|
|
|
|
|
|
|
// Test that the content name is empty if the media section does not have an
|
|
|
|
|
// a=mid line.
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseNoMid) {
|
|
|
|
|
std::string sdp = kSdpString;
|
|
|
|
|
Replace("a=mid:audio_content_name\r\n", "", &sdp);
|
|
|
|
|
Replace("a=mid:video_content_name\r\n", "", &sdp);
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
|
|
|
|
|
EXPECT_THAT(output.description()->contents(),
|
|
|
|
|
ElementsAre(Field("name", &cricket::ContentInfo::name, ""),
|
|
|
|
|
Field("name", &cricket::ContentInfo::name, "")));
|
|
|
|
|
}
|
2019-02-27 11:34:26 -08:00
|
|
|
|
2019-05-31 10:17:38 +00:00
|
|
|
TEST_F(WebRtcSdpTest, SerializeWithDefaultSctpProtocol) {
|
|
|
|
|
AddSctpDataChannel(false); // Don't use sctpmap
|
|
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
|
|
|
|
MakeDescriptionWithoutCandidates(&jsep_desc);
|
|
|
|
|
std::string message = webrtc::SdpSerialize(jsep_desc);
|
|
|
|
|
EXPECT_NE(std::string::npos,
|
|
|
|
|
message.find(cricket::kMediaProtocolUdpDtlsSctp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeWithAllSctpProtocols) {
|
|
|
|
|
AddSctpDataChannel(false);
|
|
|
|
|
std::string protocols[] = {cricket::kMediaProtocolDtlsSctp,
|
|
|
|
|
cricket::kMediaProtocolUdpDtlsSctp,
|
|
|
|
|
cricket::kMediaProtocolTcpDtlsSctp};
|
|
|
|
|
for (const auto& protocol : protocols) {
|
|
|
|
|
sctp_desc_->set_protocol(protocol);
|
|
|
|
|
JsepSessionDescription jsep_desc(kDummyType);
|
|
|
|
|
MakeDescriptionWithoutCandidates(&jsep_desc);
|
|
|
|
|
std::string message = webrtc::SdpSerialize(jsep_desc);
|
|
|
|
|
EXPECT_NE(std::string::npos, message.find(protocol));
|
|
|
|
|
JsepSessionDescription jsep_output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
EXPECT_TRUE(webrtc::SdpDeserialize(message, &jsep_output, &error));
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-18 14:05:07 -08:00
|
|
|
|
|
|
|
|
// According to https://tools.ietf.org/html/rfc5576#section-6.1, the CNAME
|
|
|
|
|
// attribute is mandatory, but we relax that restriction.
|
|
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithoutCname) {
|
|
|
|
|
std::string sdp_without_cname = kSdpFullString;
|
|
|
|
|
Replace("a=ssrc:1 cname:stream_1_cname\r\n", "", &sdp_without_cname);
|
|
|
|
|
JsepSessionDescription new_jdesc(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp_without_cname, &new_jdesc));
|
|
|
|
|
|
|
|
|
|
audio_desc_->mutable_streams()[0].cname = "";
|
|
|
|
|
ASSERT_TRUE(jdesc_.Initialize(desc_.Clone(), jdesc_.session_id(),
|
|
|
|
|
jdesc_.session_version()));
|
|
|
|
|
EXPECT_TRUE(CompareSessionDescription(jdesc_, new_jdesc));
|
|
|
|
|
}
|
2020-06-26 10:17:05 +02:00
|
|
|
|
2023-02-02 17:59:28 -08:00
|
|
|
TEST_F(WebRtcSdpTest,
|
|
|
|
|
DeserializeSdpWithUnrecognizedApplicationProtocolRejectsSection) {
|
|
|
|
|
const char* unsupported_application_protocols[] = {
|
|
|
|
|
"bogus/RTP/", "RTP/SAVPF", "DTLS/SCTP/RTP/", "DTLS/SCTPRTP/",
|
|
|
|
|
"obviously-bogus", "UDP/TL/RTSP/SAVPF", "UDP/TL/RTSP/S"};
|
|
|
|
|
|
|
|
|
|
for (auto proto : unsupported_application_protocols) {
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
std::string sdp = kSdpSessionString;
|
|
|
|
|
sdp.append("m=application 9 ");
|
|
|
|
|
sdp.append(proto);
|
|
|
|
|
sdp.append(" 101\r\n");
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
|
|
|
|
|
// Make sure we actually parsed a single media section
|
|
|
|
|
ASSERT_EQ(1u, jdesc_output.description()->contents().size());
|
|
|
|
|
|
|
|
|
|
// Content is not getting parsed as sctp but instead unsupported.
|
|
|
|
|
EXPECT_EQ(nullptr, jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->as_sctp());
|
|
|
|
|
EXPECT_NE(nullptr, jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->as_unsupported());
|
|
|
|
|
|
|
|
|
|
// Reject the content
|
|
|
|
|
EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-26 10:17:05 +02:00
|
|
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithUnsupportedMediaType) {
|
|
|
|
|
std::string sdp = kSdpSessionString;
|
|
|
|
|
sdp +=
|
|
|
|
|
"m=bogus 9 RTP/SAVPF 0 8\r\n"
|
2020-10-13 12:43:15 +02:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=mid:bogusmid\r\n";
|
2020-06-26 10:17:05 +02:00
|
|
|
sdp +=
|
|
|
|
|
"m=audio/something 9 RTP/SAVPF 0 8\r\n"
|
2020-10-13 12:43:15 +02:00
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=mid:somethingmid\r\n";
|
2020-06-26 10:17:05 +02:00
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
|
2020-10-13 12:43:15 +02:00
|
|
|
ASSERT_EQ(2u, jdesc_output.description()->contents().size());
|
|
|
|
|
ASSERT_NE(nullptr, jdesc_output.description()
|
|
|
|
|
->contents()[0]
|
|
|
|
|
.media_description()
|
|
|
|
|
->as_unsupported());
|
|
|
|
|
ASSERT_NE(nullptr, jdesc_output.description()
|
|
|
|
|
->contents()[1]
|
|
|
|
|
.media_description()
|
|
|
|
|
->as_unsupported());
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(jdesc_output.description()->contents()[0].rejected);
|
|
|
|
|
EXPECT_TRUE(jdesc_output.description()->contents()[1].rejected);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(jdesc_output.description()->contents()[0].name, "bogusmid");
|
|
|
|
|
EXPECT_EQ(jdesc_output.description()->contents()[1].name, "somethingmid");
|
2020-06-26 10:17:05 +02:00
|
|
|
}
|
2021-01-13 10:40:06 +01:00
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, MediaTypeProtocolMismatch) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n";
|
|
|
|
|
|
|
|
|
|
ExpectParseFailure(std::string(sdp + "m=audio 9 UDP/DTLS/SCTP 120\r\n"),
|
|
|
|
|
"m=audio");
|
|
|
|
|
ExpectParseFailure(std::string(sdp + "m=video 9 UDP/DTLS/SCTP 120\r\n"),
|
|
|
|
|
"m=video");
|
|
|
|
|
ExpectParseFailure(std::string(sdp + "m=video 9 SOMETHING 120\r\n"),
|
|
|
|
|
"m=video");
|
|
|
|
|
}
|
2021-01-29 09:29:47 +01:00
|
|
|
|
|
|
|
|
// Regression test for:
|
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1171965
|
|
|
|
|
TEST_F(WebRtcSdpTest, SctpPortInUnsupportedContent) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=o 1 DTLS/SCTP 5000\r\n"
|
|
|
|
|
"a=sctp-port\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
}
|
2021-03-03 07:44:39 +00:00
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, IllegalMidCharacterValue) {
|
|
|
|
|
std::string sdp = kSdpString;
|
|
|
|
|
// [ is an illegal token value.
|
|
|
|
|
Replace("a=mid:", "a=mid:[]", &sdp);
|
|
|
|
|
ExpectParseFailure(std::string(sdp), "a=mid:[]");
|
|
|
|
|
}
|
2021-11-25 08:57:54 +01:00
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, MaxChannels) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 11 22 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 49232 RTP/AVP 108\r\n"
|
|
|
|
|
"a=rtpmap:108 ISAC/16000/512\r\n";
|
|
|
|
|
|
|
|
|
|
ExpectParseFailure(sdp, "a=rtpmap:108 ISAC/16000/512");
|
|
|
|
|
}
|
2022-04-07 09:54:51 +00:00
|
|
|
|
2022-05-31 16:51:23 +02:00
|
|
|
TEST_F(WebRtcSdpTest, DuplicateAudioRtpmapWithConflict) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 11 22 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 49232 RTP/AVP 108\r\n"
|
|
|
|
|
"a=rtpmap:108 ISAC/16000\r\n"
|
2022-07-07 11:06:36 +02:00
|
|
|
"a=rtpmap:108 G711/16000\r\n";
|
2022-05-31 16:51:23 +02:00
|
|
|
|
2022-07-07 11:06:36 +02:00
|
|
|
ExpectParseFailure(sdp, "a=rtpmap:108 G711/16000");
|
2022-05-31 16:51:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, DuplicateVideoRtpmapWithConflict) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 11 22 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=video 49232 RTP/AVP 108\r\n"
|
|
|
|
|
"a=rtpmap:108 VP8/90000\r\n"
|
|
|
|
|
"a=rtpmap:108 VP9/90000\r\n";
|
|
|
|
|
|
|
|
|
|
ExpectParseFailure(sdp, "a=rtpmap:108 VP9/90000");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, FmtpBeforeRtpMap) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 11 22 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=video 49232 RTP/AVP 108\r\n"
|
|
|
|
|
"a=fmtp:108 profile-level=1\r\n"
|
|
|
|
|
"a=rtpmap:108 VP9/90000\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-22 09:39:19 +00:00
|
|
|
TEST_F(WebRtcSdpTest, StaticallyAssignedPayloadTypeWithDifferentCasing) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 11 22 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"m=audio 49232 RTP/AVP 18\r\n"
|
|
|
|
|
// Casing differs from statically assigned type, this should
|
|
|
|
|
// still be accepted.
|
|
|
|
|
"a=rtpmap:18 g729/8000\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription jdesc_output(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc_output));
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-07 09:54:51 +00:00
|
|
|
// This tests parsing of SDP with unknown ssrc-specific attributes.
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseIgnoreUnknownSsrcSpecificAttribute) {
|
|
|
|
|
std::string sdp = kSdpString;
|
|
|
|
|
sdp += "a=ssrc:1 mslabel:something\r\n";
|
|
|
|
|
|
|
|
|
|
JsepSessionDescription output(kDummyType);
|
|
|
|
|
SdpParseError error;
|
|
|
|
|
ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
|
|
|
|
}
|
2023-02-21 10:49:18 +01:00
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, ParseSessionLevelExtmapAttributes) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 0 3 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"a=group:BUNDLE 0\r\n"
|
|
|
|
|
"a=fingerprint:sha-1 "
|
|
|
|
|
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
|
|
|
|
|
"a=setup:actpass\r\n"
|
|
|
|
|
"a=ice-ufrag:ETEn\r\n"
|
|
|
|
|
"a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
|
|
|
|
|
"a=extmap:3 "
|
|
|
|
|
"http://www.ietf.org/id/"
|
|
|
|
|
"draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
|
|
|
|
|
"m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=sendonly\r\n"
|
|
|
|
|
"a=mid:0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n";
|
|
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
|
|
|
|
EXPECT_TRUE(SdpDeserialize(sdp, &jdesc));
|
|
|
|
|
ASSERT_EQ(1u, jdesc.description()->contents().size());
|
|
|
|
|
const auto content = jdesc.description()->contents()[0];
|
|
|
|
|
const auto* audio_description = content.media_description()->as_audio();
|
|
|
|
|
ASSERT_NE(audio_description, nullptr);
|
|
|
|
|
const auto& extensions = audio_description->rtp_header_extensions();
|
|
|
|
|
ASSERT_EQ(1u, extensions.size());
|
|
|
|
|
EXPECT_EQ(extensions[0].uri,
|
|
|
|
|
"http://www.ietf.org/id/"
|
|
|
|
|
"draft-holmer-rmcat-transport-wide-cc-extensions-01");
|
|
|
|
|
EXPECT_EQ(extensions[0].id, 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WebRtcSdpTest, RejectSessionLevelMediaLevelExtmapMixedUsage) {
|
|
|
|
|
std::string sdp =
|
|
|
|
|
"v=0\r\n"
|
|
|
|
|
"o=- 0 3 IN IP4 127.0.0.1\r\n"
|
|
|
|
|
"s=-\r\n"
|
|
|
|
|
"t=0 0\r\n"
|
|
|
|
|
"a=group:BUNDLE 0\r\n"
|
|
|
|
|
"a=fingerprint:sha-1 "
|
|
|
|
|
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
|
|
|
|
|
"a=setup:actpass\r\n"
|
|
|
|
|
"a=ice-ufrag:ETEn\r\n"
|
|
|
|
|
"a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
|
|
|
|
|
"a=extmap:3 "
|
|
|
|
|
"http://www.ietf.org/id/"
|
|
|
|
|
"draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
|
|
|
|
|
"m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
|
|
|
|
|
"a=extmap:2 "
|
|
|
|
|
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n"
|
|
|
|
|
"c=IN IP4 0.0.0.0\r\n"
|
|
|
|
|
"a=rtcp-mux\r\n"
|
|
|
|
|
"a=sendonly\r\n"
|
|
|
|
|
"a=mid:0\r\n"
|
|
|
|
|
"a=rtpmap:111 opus/48000/2\r\n";
|
|
|
|
|
JsepSessionDescription jdesc(kDummyType);
|
|
|
|
|
EXPECT_FALSE(SdpDeserialize(sdp, &jdesc));
|
|
|
|
|
}
|