Remove RTP data implementation
Bug: webrtc:6625 Change-Id: Ie68d7a938d8b7be95a01cca74a176104e4e44e1b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215321 Reviewed-by: Henrik Boström <hbos@webrtc.org> Commit-Queue: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33759}
This commit is contained in:
parent
f981cb3d2e
commit
7af57c6e48
@ -142,8 +142,6 @@ rtc_library("rtc_media_base") {
|
|||||||
"base/media_engine.h",
|
"base/media_engine.h",
|
||||||
"base/rid_description.cc",
|
"base/rid_description.cc",
|
||||||
"base/rid_description.h",
|
"base/rid_description.h",
|
||||||
"base/rtp_data_engine.cc",
|
|
||||||
"base/rtp_data_engine.h",
|
|
||||||
"base/rtp_utils.cc",
|
"base/rtp_utils.cc",
|
||||||
"base/rtp_utils.h",
|
"base/rtp_utils.h",
|
||||||
"base/stream_params.cc",
|
"base/stream_params.cc",
|
||||||
@ -628,7 +626,6 @@ if (rtc_include_tests) {
|
|||||||
sources = [
|
sources = [
|
||||||
"base/codec_unittest.cc",
|
"base/codec_unittest.cc",
|
||||||
"base/media_engine_unittest.cc",
|
"base/media_engine_unittest.cc",
|
||||||
"base/rtp_data_engine_unittest.cc",
|
|
||||||
"base/rtp_utils_unittest.cc",
|
"base/rtp_utils_unittest.cc",
|
||||||
"base/sdp_fmtp_utils_unittest.cc",
|
"base/sdp_fmtp_utils_unittest.cc",
|
||||||
"base/stream_params_unittest.cc",
|
"base/stream_params_unittest.cc",
|
||||||
|
|||||||
@ -422,93 +422,6 @@ void FakeVideoMediaChannel::ClearRecordableEncodedFrameCallback(uint32_t ssrc) {
|
|||||||
|
|
||||||
void FakeVideoMediaChannel::GenerateKeyFrame(uint32_t ssrc) {}
|
void FakeVideoMediaChannel::GenerateKeyFrame(uint32_t ssrc) {}
|
||||||
|
|
||||||
FakeDataMediaChannel::FakeDataMediaChannel(void* unused,
|
|
||||||
const DataOptions& options)
|
|
||||||
: send_blocked_(false), max_bps_(-1) {}
|
|
||||||
FakeDataMediaChannel::~FakeDataMediaChannel() {}
|
|
||||||
const std::vector<DataCodec>& FakeDataMediaChannel::recv_codecs() const {
|
|
||||||
return recv_codecs_;
|
|
||||||
}
|
|
||||||
const std::vector<DataCodec>& FakeDataMediaChannel::send_codecs() const {
|
|
||||||
return send_codecs_;
|
|
||||||
}
|
|
||||||
const std::vector<DataCodec>& FakeDataMediaChannel::codecs() const {
|
|
||||||
return send_codecs();
|
|
||||||
}
|
|
||||||
int FakeDataMediaChannel::max_bps() const {
|
|
||||||
return max_bps_;
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::SetSendParameters(const DataSendParameters& params) {
|
|
||||||
set_send_rtcp_parameters(params.rtcp);
|
|
||||||
return (SetSendCodecs(params.codecs) &&
|
|
||||||
SetMaxSendBandwidth(params.max_bandwidth_bps));
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::SetRecvParameters(const DataRecvParameters& params) {
|
|
||||||
set_recv_rtcp_parameters(params.rtcp);
|
|
||||||
return SetRecvCodecs(params.codecs);
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::SetSend(bool send) {
|
|
||||||
return set_sending(send);
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::SetReceive(bool receive) {
|
|
||||||
set_playout(receive);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::AddRecvStream(const StreamParams& sp) {
|
|
||||||
if (!RtpHelper<DataMediaChannel>::AddRecvStream(sp))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::RemoveRecvStream(uint32_t ssrc) {
|
|
||||||
if (!RtpHelper<DataMediaChannel>::RemoveRecvStream(ssrc))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::SendData(const SendDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
|
||||||
SendDataResult* result) {
|
|
||||||
if (send_blocked_) {
|
|
||||||
*result = SDR_BLOCK;
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
last_sent_data_params_ = params;
|
|
||||||
last_sent_data_ = std::string(payload.data<char>(), payload.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SendDataParams FakeDataMediaChannel::last_sent_data_params() {
|
|
||||||
return last_sent_data_params_;
|
|
||||||
}
|
|
||||||
std::string FakeDataMediaChannel::last_sent_data() {
|
|
||||||
return last_sent_data_;
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::is_send_blocked() {
|
|
||||||
return send_blocked_;
|
|
||||||
}
|
|
||||||
void FakeDataMediaChannel::set_send_blocked(bool blocked) {
|
|
||||||
send_blocked_ = blocked;
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
|
|
||||||
if (fail_set_recv_codecs()) {
|
|
||||||
// Fake the failure in SetRecvCodecs.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
recv_codecs_ = codecs;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
|
|
||||||
if (fail_set_send_codecs()) {
|
|
||||||
// Fake the failure in SetSendCodecs.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
send_codecs_ = codecs;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool FakeDataMediaChannel::SetMaxSendBandwidth(int bps) {
|
|
||||||
max_bps_ = bps;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
FakeVoiceEngine::FakeVoiceEngine() : fail_create_channel_(false) {
|
FakeVoiceEngine::FakeVoiceEngine() : fail_create_channel_(false) {
|
||||||
// Add a fake audio codec. Note that the name must not be "" as there are
|
// Add a fake audio codec. Note that the name must not be "" as there are
|
||||||
// sanity checks against that.
|
// sanity checks against that.
|
||||||
@ -668,22 +581,4 @@ void FakeMediaEngine::set_fail_create_channel(bool fail) {
|
|||||||
video_->fail_create_channel_ = fail;
|
video_->fail_create_channel_ = fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataMediaChannel* FakeDataEngine::CreateChannel(const MediaConfig& config) {
|
|
||||||
FakeDataMediaChannel* ch = new FakeDataMediaChannel(this, DataOptions());
|
|
||||||
channels_.push_back(ch);
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
FakeDataMediaChannel* FakeDataEngine::GetChannel(size_t index) {
|
|
||||||
return (channels_.size() > index) ? channels_[index] : NULL;
|
|
||||||
}
|
|
||||||
void FakeDataEngine::UnregisterChannel(DataMediaChannel* channel) {
|
|
||||||
channels_.erase(absl::c_find(channels_, channel));
|
|
||||||
}
|
|
||||||
void FakeDataEngine::SetDataCodecs(const std::vector<DataCodec>& data_codecs) {
|
|
||||||
data_codecs_ = data_codecs;
|
|
||||||
}
|
|
||||||
const std::vector<DataCodec>& FakeDataEngine::data_codecs() {
|
|
||||||
return data_codecs_;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -472,48 +472,6 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
|
|||||||
int max_bps_;
|
int max_bps_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Dummy option class, needed for the DataTraits abstraction in
|
|
||||||
// channel_unittest.c.
|
|
||||||
class DataOptions {};
|
|
||||||
|
|
||||||
class FakeDataMediaChannel : public RtpHelper<DataMediaChannel> {
|
|
||||||
public:
|
|
||||||
explicit FakeDataMediaChannel(void* unused, const DataOptions& options);
|
|
||||||
~FakeDataMediaChannel();
|
|
||||||
const std::vector<DataCodec>& recv_codecs() const;
|
|
||||||
const std::vector<DataCodec>& send_codecs() const;
|
|
||||||
const std::vector<DataCodec>& codecs() const;
|
|
||||||
int max_bps() const;
|
|
||||||
|
|
||||||
bool SetSendParameters(const DataSendParameters& params) override;
|
|
||||||
bool SetRecvParameters(const DataRecvParameters& params) override;
|
|
||||||
bool SetSend(bool send) override;
|
|
||||||
bool SetReceive(bool receive) override;
|
|
||||||
bool AddRecvStream(const StreamParams& sp) override;
|
|
||||||
bool RemoveRecvStream(uint32_t ssrc) override;
|
|
||||||
|
|
||||||
bool SendData(const SendDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
|
||||||
SendDataResult* result) override;
|
|
||||||
|
|
||||||
SendDataParams last_sent_data_params();
|
|
||||||
std::string last_sent_data();
|
|
||||||
bool is_send_blocked();
|
|
||||||
void set_send_blocked(bool blocked);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool SetRecvCodecs(const std::vector<DataCodec>& codecs);
|
|
||||||
bool SetSendCodecs(const std::vector<DataCodec>& codecs);
|
|
||||||
bool SetMaxSendBandwidth(int bps);
|
|
||||||
|
|
||||||
std::vector<DataCodec> recv_codecs_;
|
|
||||||
std::vector<DataCodec> send_codecs_;
|
|
||||||
SendDataParams last_sent_data_params_;
|
|
||||||
std::string last_sent_data_;
|
|
||||||
bool send_blocked_;
|
|
||||||
int max_bps_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FakeVoiceEngine : public VoiceEngineInterface {
|
class FakeVoiceEngine : public VoiceEngineInterface {
|
||||||
public:
|
public:
|
||||||
FakeVoiceEngine();
|
FakeVoiceEngine();
|
||||||
@ -609,25 +567,6 @@ class FakeMediaEngine : public CompositeMediaEngine {
|
|||||||
FakeVideoEngine* const video_;
|
FakeVideoEngine* const video_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Have to come afterwards due to declaration order
|
|
||||||
|
|
||||||
class FakeDataEngine : public DataEngineInterface {
|
|
||||||
public:
|
|
||||||
DataMediaChannel* CreateChannel(const MediaConfig& config) override;
|
|
||||||
|
|
||||||
FakeDataMediaChannel* GetChannel(size_t index);
|
|
||||||
|
|
||||||
void UnregisterChannel(DataMediaChannel* channel);
|
|
||||||
|
|
||||||
void SetDataCodecs(const std::vector<DataCodec>& data_codecs);
|
|
||||||
|
|
||||||
const std::vector<DataCodec>& data_codecs() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<FakeDataMediaChannel*> channels_;
|
|
||||||
std::vector<DataCodec> data_codecs_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|
||||||
#endif // MEDIA_BASE_FAKE_MEDIA_ENGINE_H_
|
#endif // MEDIA_BASE_FAKE_MEDIA_ENGINE_H_
|
||||||
|
|||||||
@ -955,11 +955,8 @@ enum DataMessageType {
|
|||||||
// signal fires, on up the chain.
|
// signal fires, on up the chain.
|
||||||
struct ReceiveDataParams {
|
struct ReceiveDataParams {
|
||||||
// The in-packet stream indentifier.
|
// The in-packet stream indentifier.
|
||||||
// RTP data channels use SSRCs, SCTP data channels use SIDs.
|
// SCTP data channels use SIDs.
|
||||||
union {
|
int sid = 0;
|
||||||
uint32_t ssrc;
|
|
||||||
int sid = 0;
|
|
||||||
};
|
|
||||||
// The type of message (binary, text, or control).
|
// The type of message (binary, text, or control).
|
||||||
DataMessageType type = DMT_TEXT;
|
DataMessageType type = DMT_TEXT;
|
||||||
// A per-stream value incremented per packet in the stream.
|
// A per-stream value incremented per packet in the stream.
|
||||||
@ -970,11 +967,7 @@ struct ReceiveDataParams {
|
|||||||
|
|
||||||
struct SendDataParams {
|
struct SendDataParams {
|
||||||
// The in-packet stream indentifier.
|
// The in-packet stream indentifier.
|
||||||
// RTP data channels use SSRCs, SCTP data channels use SIDs.
|
int sid = 0;
|
||||||
union {
|
|
||||||
uint32_t ssrc;
|
|
||||||
int sid = 0;
|
|
||||||
};
|
|
||||||
// The type of message (binary, text, or control).
|
// The type of message (binary, text, or control).
|
||||||
DataMessageType type = DMT_TEXT;
|
DataMessageType type = DMT_TEXT;
|
||||||
|
|
||||||
|
|||||||
@ -158,17 +158,9 @@ class CompositeMediaEngine : public MediaEngineInterface {
|
|||||||
|
|
||||||
enum DataChannelType {
|
enum DataChannelType {
|
||||||
DCT_NONE = 0,
|
DCT_NONE = 0,
|
||||||
DCT_RTP = 1,
|
|
||||||
DCT_SCTP = 2,
|
DCT_SCTP = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DataEngineInterface {
|
|
||||||
public:
|
|
||||||
virtual ~DataEngineInterface() {}
|
|
||||||
virtual DataMediaChannel* CreateChannel(const MediaConfig& config) = 0;
|
|
||||||
virtual const std::vector<DataCodec>& data_codecs() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
webrtc::RtpParameters CreateRtpParametersWithOneEncoding();
|
webrtc::RtpParameters CreateRtpParametersWithOneEncoding();
|
||||||
webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp);
|
webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp);
|
||||||
|
|
||||||
|
|||||||
@ -1,340 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "media/base/rtp_data_engine.h"
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "absl/strings/match.h"
|
|
||||||
#include "media/base/codec.h"
|
|
||||||
#include "media/base/media_constants.h"
|
|
||||||
#include "media/base/rtp_utils.h"
|
|
||||||
#include "media/base/stream_params.h"
|
|
||||||
#include "rtc_base/copy_on_write_buffer.h"
|
|
||||||
#include "rtc_base/data_rate_limiter.h"
|
|
||||||
#include "rtc_base/helpers.h"
|
|
||||||
#include "rtc_base/logging.h"
|
|
||||||
#include "rtc_base/sanitizer.h"
|
|
||||||
|
|
||||||
namespace cricket {
|
|
||||||
|
|
||||||
// We want to avoid IP fragmentation.
|
|
||||||
static const size_t kDataMaxRtpPacketLen = 1200U;
|
|
||||||
// We reserve space after the RTP header for future wiggle room.
|
|
||||||
static const unsigned char kReservedSpace[] = {0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
// Amount of overhead SRTP may take. We need to leave room in the
|
|
||||||
// buffer for it, otherwise SRTP will fail later. If SRTP ever uses
|
|
||||||
// more than this, we need to increase this number.
|
|
||||||
static const size_t kMaxSrtpHmacOverhead = 16;
|
|
||||||
|
|
||||||
RtpDataEngine::RtpDataEngine() {
|
|
||||||
data_codecs_.push_back(
|
|
||||||
DataCodec(kGoogleRtpDataCodecPlType, kGoogleRtpDataCodecName));
|
|
||||||
}
|
|
||||||
|
|
||||||
DataMediaChannel* RtpDataEngine::CreateChannel(const MediaConfig& config) {
|
|
||||||
return new RtpDataMediaChannel(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const DataCodec* FindCodecByName(const std::vector<DataCodec>& codecs,
|
|
||||||
const std::string& name) {
|
|
||||||
for (const DataCodec& codec : codecs) {
|
|
||||||
if (absl::EqualsIgnoreCase(name, codec.name))
|
|
||||||
return &codec;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpDataMediaChannel::RtpDataMediaChannel(const MediaConfig& config)
|
|
||||||
: DataMediaChannel(config) {
|
|
||||||
Construct();
|
|
||||||
SetPreferredDscp(rtc::DSCP_AF41);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataMediaChannel::Construct() {
|
|
||||||
sending_ = false;
|
|
||||||
receiving_ = false;
|
|
||||||
send_limiter_.reset(new rtc::DataRateLimiter(kRtpDataMaxBandwidth / 8, 1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpDataMediaChannel::~RtpDataMediaChannel() {
|
|
||||||
std::map<uint32_t, RtpClock*>::const_iterator iter;
|
|
||||||
for (iter = rtp_clock_by_send_ssrc_.begin();
|
|
||||||
iter != rtp_clock_by_send_ssrc_.end(); ++iter) {
|
|
||||||
delete iter->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RTC_NO_SANITIZE("float-cast-overflow") // bugs.webrtc.org/8204
|
|
||||||
RtpClock::Tick(double now, int* seq_num, uint32_t* timestamp) {
|
|
||||||
*seq_num = ++last_seq_num_;
|
|
||||||
*timestamp = timestamp_offset_ + static_cast<uint32_t>(now * clockrate_);
|
|
||||||
// UBSan: 5.92374e+10 is outside the range of representable values of type
|
|
||||||
// 'unsigned int'
|
|
||||||
}
|
|
||||||
|
|
||||||
const DataCodec* FindUnknownCodec(const std::vector<DataCodec>& codecs) {
|
|
||||||
DataCodec data_codec(kGoogleRtpDataCodecPlType, kGoogleRtpDataCodecName);
|
|
||||||
std::vector<DataCodec>::const_iterator iter;
|
|
||||||
for (iter = codecs.begin(); iter != codecs.end(); ++iter) {
|
|
||||||
if (!iter->Matches(data_codec)) {
|
|
||||||
return &(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DataCodec* FindKnownCodec(const std::vector<DataCodec>& codecs) {
|
|
||||||
DataCodec data_codec(kGoogleRtpDataCodecPlType, kGoogleRtpDataCodecName);
|
|
||||||
std::vector<DataCodec>::const_iterator iter;
|
|
||||||
for (iter = codecs.begin(); iter != codecs.end(); ++iter) {
|
|
||||||
if (iter->Matches(data_codec)) {
|
|
||||||
return &(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
|
|
||||||
const DataCodec* unknown_codec = FindUnknownCodec(codecs);
|
|
||||||
if (unknown_codec) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Failed to SetRecvCodecs because of unknown codec: "
|
|
||||||
<< unknown_codec->ToString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
recv_codecs_ = codecs;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
|
|
||||||
const DataCodec* known_codec = FindKnownCodec(codecs);
|
|
||||||
if (!known_codec) {
|
|
||||||
RTC_LOG(LS_WARNING)
|
|
||||||
<< "Failed to SetSendCodecs because there is no known codec.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
send_codecs_ = codecs;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::SetSendParameters(const DataSendParameters& params) {
|
|
||||||
return (SetSendCodecs(params.codecs) &&
|
|
||||||
SetMaxSendBandwidth(params.max_bandwidth_bps));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::SetRecvParameters(const DataRecvParameters& params) {
|
|
||||||
return SetRecvCodecs(params.codecs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::AddSendStream(const StreamParams& stream) {
|
|
||||||
if (!stream.has_ssrcs()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetStreamBySsrc(send_streams_, stream.first_ssrc())) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Not adding data send stream '" << stream.id
|
|
||||||
<< "' with ssrc=" << stream.first_ssrc()
|
|
||||||
<< " because stream already exists.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
send_streams_.push_back(stream);
|
|
||||||
// TODO(pthatcher): This should be per-stream, not per-ssrc.
|
|
||||||
// And we should probably allow more than one per stream.
|
|
||||||
rtp_clock_by_send_ssrc_[stream.first_ssrc()] =
|
|
||||||
new RtpClock(kDataCodecClockrate, rtc::CreateRandomNonZeroId(),
|
|
||||||
rtc::CreateRandomNonZeroId());
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Added data send stream '" << stream.id
|
|
||||||
<< "' with ssrc=" << stream.first_ssrc();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::RemoveSendStream(uint32_t ssrc) {
|
|
||||||
if (!GetStreamBySsrc(send_streams_, ssrc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveStreamBySsrc(&send_streams_, ssrc);
|
|
||||||
delete rtp_clock_by_send_ssrc_[ssrc];
|
|
||||||
rtp_clock_by_send_ssrc_.erase(ssrc);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::AddRecvStream(const StreamParams& stream) {
|
|
||||||
if (!stream.has_ssrcs()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetStreamBySsrc(recv_streams_, stream.first_ssrc())) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Not adding data recv stream '" << stream.id
|
|
||||||
<< "' with ssrc=" << stream.first_ssrc()
|
|
||||||
<< " because stream already exists.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
recv_streams_.push_back(stream);
|
|
||||||
RTC_LOG(LS_INFO) << "Added data recv stream '" << stream.id
|
|
||||||
<< "' with ssrc=" << stream.first_ssrc();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::RemoveRecvStream(uint32_t ssrc) {
|
|
||||||
RemoveStreamBySsrc(&recv_streams_, ssrc);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not implemented.
|
|
||||||
void RtpDataMediaChannel::ResetUnsignaledRecvStream() {}
|
|
||||||
void RtpDataMediaChannel::OnDemuxerCriteriaUpdatePending() {}
|
|
||||||
void RtpDataMediaChannel::OnDemuxerCriteriaUpdateComplete() {}
|
|
||||||
|
|
||||||
void RtpDataMediaChannel::OnPacketReceived(rtc::CopyOnWriteBuffer packet,
|
|
||||||
int64_t /* packet_time_us */) {
|
|
||||||
RtpHeader header;
|
|
||||||
if (!GetRtpHeader(packet.cdata(), packet.size(), &header)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t header_length;
|
|
||||||
if (!GetRtpHeaderLen(packet.cdata(), packet.size(), &header_length)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const char* data =
|
|
||||||
packet.cdata<char>() + header_length + sizeof(kReservedSpace);
|
|
||||||
size_t data_len = packet.size() - header_length - sizeof(kReservedSpace);
|
|
||||||
|
|
||||||
if (!receiving_) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Not receiving packet " << header.ssrc << ":"
|
|
||||||
<< header.seq_num << " before SetReceive(true) called.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FindCodecById(recv_codecs_, header.payload_type)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GetStreamBySsrc(recv_streams_, header.ssrc)) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Received packet for unknown ssrc: " << header.ssrc;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uncomment this for easy debugging.
|
|
||||||
// const auto* found_stream = GetStreamBySsrc(recv_streams_, header.ssrc);
|
|
||||||
// RTC_LOG(LS_INFO) << "Received packet"
|
|
||||||
// << " groupid=" << found_stream.groupid
|
|
||||||
// << ", ssrc=" << header.ssrc
|
|
||||||
// << ", seqnum=" << header.seq_num
|
|
||||||
// << ", timestamp=" << header.timestamp
|
|
||||||
// << ", len=" << data_len;
|
|
||||||
|
|
||||||
ReceiveDataParams params;
|
|
||||||
params.ssrc = header.ssrc;
|
|
||||||
params.seq_num = header.seq_num;
|
|
||||||
params.timestamp = header.timestamp;
|
|
||||||
SignalDataReceived(params, data, data_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::SetMaxSendBandwidth(int bps) {
|
|
||||||
if (bps <= 0) {
|
|
||||||
bps = kRtpDataMaxBandwidth;
|
|
||||||
}
|
|
||||||
send_limiter_.reset(new rtc::DataRateLimiter(bps / 8, 1.0));
|
|
||||||
RTC_LOG(LS_INFO) << "RtpDataMediaChannel::SetSendBandwidth to " << bps
|
|
||||||
<< "bps.";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataMediaChannel::SendData(const SendDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
|
||||||
SendDataResult* result) {
|
|
||||||
if (result) {
|
|
||||||
// If we return true, we'll set this to SDR_SUCCESS.
|
|
||||||
*result = SDR_ERROR;
|
|
||||||
}
|
|
||||||
if (!sending_) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Not sending packet with ssrc=" << params.ssrc
|
|
||||||
<< " len=" << payload.size()
|
|
||||||
<< " before SetSend(true).";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.type != cricket::DMT_TEXT) {
|
|
||||||
RTC_LOG(LS_WARNING)
|
|
||||||
<< "Not sending data because binary type is unsupported.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StreamParams* found_stream =
|
|
||||||
GetStreamBySsrc(send_streams_, params.ssrc);
|
|
||||||
if (!found_stream) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Not sending data because ssrc is unknown: "
|
|
||||||
<< params.ssrc;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DataCodec* found_codec =
|
|
||||||
FindCodecByName(send_codecs_, kGoogleRtpDataCodecName);
|
|
||||||
if (!found_codec) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Not sending data because codec is unknown: "
|
|
||||||
<< kGoogleRtpDataCodecName;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t packet_len = (kMinRtpPacketLen + sizeof(kReservedSpace) +
|
|
||||||
payload.size() + kMaxSrtpHmacOverhead);
|
|
||||||
if (packet_len > kDataMaxRtpPacketLen) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double now =
|
|
||||||
rtc::TimeMicros() / static_cast<double>(rtc::kNumMicrosecsPerSec);
|
|
||||||
|
|
||||||
if (!send_limiter_->CanUse(packet_len, now)) {
|
|
||||||
RTC_LOG(LS_VERBOSE) << "Dropped data packet of len=" << packet_len
|
|
||||||
<< "; already sent " << send_limiter_->used_in_period()
|
|
||||||
<< "/" << send_limiter_->max_per_period();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpHeader header;
|
|
||||||
header.payload_type = found_codec->id;
|
|
||||||
header.ssrc = params.ssrc;
|
|
||||||
rtp_clock_by_send_ssrc_[header.ssrc]->Tick(now, &header.seq_num,
|
|
||||||
&header.timestamp);
|
|
||||||
|
|
||||||
rtc::CopyOnWriteBuffer packet(kMinRtpPacketLen, packet_len);
|
|
||||||
if (!SetRtpHeader(packet.MutableData(), packet.size(), header)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
packet.AppendData(kReservedSpace);
|
|
||||||
packet.AppendData(payload);
|
|
||||||
|
|
||||||
RTC_LOG(LS_VERBOSE) << "Sent RTP data packet: "
|
|
||||||
" stream="
|
|
||||||
<< found_stream->id << " ssrc=" << header.ssrc
|
|
||||||
<< ", seqnum=" << header.seq_num
|
|
||||||
<< ", timestamp=" << header.timestamp
|
|
||||||
<< ", len=" << payload.size();
|
|
||||||
|
|
||||||
rtc::PacketOptions options;
|
|
||||||
options.info_signaled_after_sent.packet_type = rtc::PacketType::kData;
|
|
||||||
MediaChannel::SendPacket(&packet, options);
|
|
||||||
send_limiter_->Use(packet_len, now);
|
|
||||||
if (result) {
|
|
||||||
*result = SDR_SUCCESS;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cricket
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MEDIA_BASE_RTP_DATA_ENGINE_H_
|
|
||||||
#define MEDIA_BASE_RTP_DATA_ENGINE_H_
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "media/base/codec.h"
|
|
||||||
#include "media/base/media_channel.h"
|
|
||||||
#include "media/base/media_constants.h"
|
|
||||||
#include "media/base/media_engine.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
class DataRateLimiter;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace cricket {
|
|
||||||
|
|
||||||
class RtpDataEngine : public DataEngineInterface {
|
|
||||||
public:
|
|
||||||
RtpDataEngine();
|
|
||||||
|
|
||||||
virtual DataMediaChannel* CreateChannel(const MediaConfig& config);
|
|
||||||
|
|
||||||
virtual const std::vector<DataCodec>& data_codecs() { return data_codecs_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<DataCodec> data_codecs_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Keep track of sequence number and timestamp of an RTP stream. The
|
|
||||||
// sequence number starts with a "random" value and increments. The
|
|
||||||
// timestamp starts with a "random" value and increases monotonically
|
|
||||||
// according to the clockrate.
|
|
||||||
class RtpClock {
|
|
||||||
public:
|
|
||||||
RtpClock(int clockrate, uint16_t first_seq_num, uint32_t timestamp_offset)
|
|
||||||
: clockrate_(clockrate),
|
|
||||||
last_seq_num_(first_seq_num),
|
|
||||||
timestamp_offset_(timestamp_offset) {}
|
|
||||||
|
|
||||||
// Given the current time (in number of seconds which must be
|
|
||||||
// monotonically increasing), Return the next sequence number and
|
|
||||||
// timestamp.
|
|
||||||
void Tick(double now, int* seq_num, uint32_t* timestamp);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int clockrate_;
|
|
||||||
uint16_t last_seq_num_;
|
|
||||||
uint32_t timestamp_offset_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RtpDataMediaChannel : public DataMediaChannel {
|
|
||||||
public:
|
|
||||||
explicit RtpDataMediaChannel(const MediaConfig& config);
|
|
||||||
virtual ~RtpDataMediaChannel();
|
|
||||||
|
|
||||||
virtual bool SetSendParameters(const DataSendParameters& params);
|
|
||||||
virtual bool SetRecvParameters(const DataRecvParameters& params);
|
|
||||||
virtual bool AddSendStream(const StreamParams& sp);
|
|
||||||
virtual bool RemoveSendStream(uint32_t ssrc);
|
|
||||||
virtual bool AddRecvStream(const StreamParams& sp);
|
|
||||||
virtual bool RemoveRecvStream(uint32_t ssrc);
|
|
||||||
virtual void ResetUnsignaledRecvStream();
|
|
||||||
virtual void OnDemuxerCriteriaUpdatePending();
|
|
||||||
virtual void OnDemuxerCriteriaUpdateComplete();
|
|
||||||
virtual bool SetSend(bool send) {
|
|
||||||
sending_ = send;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool SetReceive(bool receive) {
|
|
||||||
receiving_ = receive;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual void OnPacketReceived(rtc::CopyOnWriteBuffer packet,
|
|
||||||
int64_t packet_time_us);
|
|
||||||
virtual void OnReadyToSend(bool ready) {}
|
|
||||||
virtual bool SendData(const SendDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
|
||||||
SendDataResult* result);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Construct();
|
|
||||||
bool SetMaxSendBandwidth(int bps);
|
|
||||||
bool SetSendCodecs(const std::vector<DataCodec>& codecs);
|
|
||||||
bool SetRecvCodecs(const std::vector<DataCodec>& codecs);
|
|
||||||
|
|
||||||
bool sending_;
|
|
||||||
bool receiving_;
|
|
||||||
std::vector<DataCodec> send_codecs_;
|
|
||||||
std::vector<DataCodec> recv_codecs_;
|
|
||||||
std::vector<StreamParams> send_streams_;
|
|
||||||
std::vector<StreamParams> recv_streams_;
|
|
||||||
std::map<uint32_t, RtpClock*> rtp_clock_by_send_ssrc_;
|
|
||||||
std::unique_ptr<rtc::DataRateLimiter> send_limiter_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cricket
|
|
||||||
|
|
||||||
#endif // MEDIA_BASE_RTP_DATA_ENGINE_H_
|
|
||||||
@ -1,362 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "media/base/rtp_data_engine.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "media/base/fake_network_interface.h"
|
|
||||||
#include "media/base/media_constants.h"
|
|
||||||
#include "media/base/rtp_utils.h"
|
|
||||||
#include "rtc_base/copy_on_write_buffer.h"
|
|
||||||
#include "rtc_base/fake_clock.h"
|
|
||||||
#include "rtc_base/third_party/sigslot/sigslot.h"
|
|
||||||
#include "rtc_base/time_utils.h"
|
|
||||||
#include "test/gtest.h"
|
|
||||||
|
|
||||||
class FakeDataReceiver : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
FakeDataReceiver() : has_received_data_(false) {}
|
|
||||||
|
|
||||||
void OnDataReceived(const cricket::ReceiveDataParams& params,
|
|
||||||
const char* data,
|
|
||||||
size_t len) {
|
|
||||||
has_received_data_ = true;
|
|
||||||
last_received_data_ = std::string(data, len);
|
|
||||||
last_received_data_len_ = len;
|
|
||||||
last_received_data_params_ = params;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_received_data() const { return has_received_data_; }
|
|
||||||
std::string last_received_data() const { return last_received_data_; }
|
|
||||||
size_t last_received_data_len() const { return last_received_data_len_; }
|
|
||||||
cricket::ReceiveDataParams last_received_data_params() const {
|
|
||||||
return last_received_data_params_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool has_received_data_;
|
|
||||||
std::string last_received_data_;
|
|
||||||
size_t last_received_data_len_;
|
|
||||||
cricket::ReceiveDataParams last_received_data_params_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RtpDataMediaChannelTest : public ::testing::Test {
|
|
||||||
protected:
|
|
||||||
virtual void SetUp() {
|
|
||||||
// Seed needed for each test to satisfy expectations.
|
|
||||||
iface_.reset(new cricket::FakeNetworkInterface());
|
|
||||||
dme_.reset(CreateEngine());
|
|
||||||
receiver_.reset(new FakeDataReceiver());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetNow(double now) { clock_.SetTime(webrtc::Timestamp::Seconds(now)); }
|
|
||||||
|
|
||||||
cricket::RtpDataEngine* CreateEngine() {
|
|
||||||
cricket::RtpDataEngine* dme = new cricket::RtpDataEngine();
|
|
||||||
return dme;
|
|
||||||
}
|
|
||||||
|
|
||||||
cricket::RtpDataMediaChannel* CreateChannel() {
|
|
||||||
return CreateChannel(dme_.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
cricket::RtpDataMediaChannel* CreateChannel(cricket::RtpDataEngine* dme) {
|
|
||||||
cricket::MediaConfig config;
|
|
||||||
cricket::RtpDataMediaChannel* channel =
|
|
||||||
static_cast<cricket::RtpDataMediaChannel*>(dme->CreateChannel(config));
|
|
||||||
channel->SetInterface(iface_.get());
|
|
||||||
channel->SignalDataReceived.connect(receiver_.get(),
|
|
||||||
&FakeDataReceiver::OnDataReceived);
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
FakeDataReceiver* receiver() { return receiver_.get(); }
|
|
||||||
|
|
||||||
bool HasReceivedData() { return receiver_->has_received_data(); }
|
|
||||||
|
|
||||||
std::string GetReceivedData() { return receiver_->last_received_data(); }
|
|
||||||
|
|
||||||
size_t GetReceivedDataLen() { return receiver_->last_received_data_len(); }
|
|
||||||
|
|
||||||
cricket::ReceiveDataParams GetReceivedDataParams() {
|
|
||||||
return receiver_->last_received_data_params();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasSentData(int count) { return (iface_->NumRtpPackets() > count); }
|
|
||||||
|
|
||||||
std::string GetSentData(int index) {
|
|
||||||
// Assume RTP header of length 12
|
|
||||||
std::unique_ptr<const rtc::CopyOnWriteBuffer> packet(
|
|
||||||
iface_->GetRtpPacket(index));
|
|
||||||
if (packet->size() > 12) {
|
|
||||||
return std::string(packet->data<char>() + 12, packet->size() - 12);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cricket::RtpHeader GetSentDataHeader(int index) {
|
|
||||||
std::unique_ptr<const rtc::CopyOnWriteBuffer> packet(
|
|
||||||
iface_->GetRtpPacket(index));
|
|
||||||
cricket::RtpHeader header;
|
|
||||||
GetRtpHeader(packet->data(), packet->size(), &header);
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<cricket::RtpDataEngine> dme_;
|
|
||||||
rtc::ScopedFakeClock clock_;
|
|
||||||
std::unique_ptr<cricket::FakeNetworkInterface> iface_;
|
|
||||||
std::unique_ptr<FakeDataReceiver> receiver_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(RtpDataMediaChannelTest, SetUnknownCodecs) {
|
|
||||||
std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
|
|
||||||
|
|
||||||
cricket::DataCodec known_codec;
|
|
||||||
known_codec.id = 103;
|
|
||||||
known_codec.name = "google-data";
|
|
||||||
cricket::DataCodec unknown_codec;
|
|
||||||
unknown_codec.id = 104;
|
|
||||||
unknown_codec.name = "unknown-data";
|
|
||||||
|
|
||||||
cricket::DataSendParameters send_parameters_known;
|
|
||||||
send_parameters_known.codecs.push_back(known_codec);
|
|
||||||
cricket::DataRecvParameters recv_parameters_known;
|
|
||||||
recv_parameters_known.codecs.push_back(known_codec);
|
|
||||||
|
|
||||||
cricket::DataSendParameters send_parameters_unknown;
|
|
||||||
send_parameters_unknown.codecs.push_back(unknown_codec);
|
|
||||||
cricket::DataRecvParameters recv_parameters_unknown;
|
|
||||||
recv_parameters_unknown.codecs.push_back(unknown_codec);
|
|
||||||
|
|
||||||
cricket::DataSendParameters send_parameters_mixed;
|
|
||||||
send_parameters_mixed.codecs.push_back(known_codec);
|
|
||||||
send_parameters_mixed.codecs.push_back(unknown_codec);
|
|
||||||
cricket::DataRecvParameters recv_parameters_mixed;
|
|
||||||
recv_parameters_mixed.codecs.push_back(known_codec);
|
|
||||||
recv_parameters_mixed.codecs.push_back(unknown_codec);
|
|
||||||
|
|
||||||
EXPECT_TRUE(dmc->SetSendParameters(send_parameters_known));
|
|
||||||
EXPECT_FALSE(dmc->SetSendParameters(send_parameters_unknown));
|
|
||||||
EXPECT_TRUE(dmc->SetSendParameters(send_parameters_mixed));
|
|
||||||
EXPECT_TRUE(dmc->SetRecvParameters(recv_parameters_known));
|
|
||||||
EXPECT_FALSE(dmc->SetRecvParameters(recv_parameters_unknown));
|
|
||||||
EXPECT_FALSE(dmc->SetRecvParameters(recv_parameters_mixed));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataMediaChannelTest, AddRemoveSendStream) {
|
|
||||||
std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
|
|
||||||
|
|
||||||
cricket::StreamParams stream1;
|
|
||||||
stream1.add_ssrc(41);
|
|
||||||
EXPECT_TRUE(dmc->AddSendStream(stream1));
|
|
||||||
cricket::StreamParams stream2;
|
|
||||||
stream2.add_ssrc(42);
|
|
||||||
EXPECT_TRUE(dmc->AddSendStream(stream2));
|
|
||||||
|
|
||||||
EXPECT_TRUE(dmc->RemoveSendStream(41));
|
|
||||||
EXPECT_TRUE(dmc->RemoveSendStream(42));
|
|
||||||
EXPECT_FALSE(dmc->RemoveSendStream(43));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataMediaChannelTest, AddRemoveRecvStream) {
|
|
||||||
std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
|
|
||||||
|
|
||||||
cricket::StreamParams stream1;
|
|
||||||
stream1.add_ssrc(41);
|
|
||||||
EXPECT_TRUE(dmc->AddRecvStream(stream1));
|
|
||||||
cricket::StreamParams stream2;
|
|
||||||
stream2.add_ssrc(42);
|
|
||||||
EXPECT_TRUE(dmc->AddRecvStream(stream2));
|
|
||||||
EXPECT_FALSE(dmc->AddRecvStream(stream2));
|
|
||||||
|
|
||||||
EXPECT_TRUE(dmc->RemoveRecvStream(41));
|
|
||||||
EXPECT_TRUE(dmc->RemoveRecvStream(42));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataMediaChannelTest, SendData) {
|
|
||||||
std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
|
|
||||||
|
|
||||||
cricket::SendDataParams params;
|
|
||||||
params.ssrc = 42;
|
|
||||||
unsigned char data[] = "food";
|
|
||||||
rtc::CopyOnWriteBuffer payload(data, 4);
|
|
||||||
unsigned char padded_data[] = {
|
|
||||||
0x00, 0x00, 0x00, 0x00, 'f', 'o', 'o', 'd',
|
|
||||||
};
|
|
||||||
cricket::SendDataResult result;
|
|
||||||
|
|
||||||
// Not sending
|
|
||||||
EXPECT_FALSE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_EQ(cricket::SDR_ERROR, result);
|
|
||||||
EXPECT_FALSE(HasSentData(0));
|
|
||||||
ASSERT_TRUE(dmc->SetSend(true));
|
|
||||||
|
|
||||||
// Unknown stream name.
|
|
||||||
EXPECT_FALSE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_EQ(cricket::SDR_ERROR, result);
|
|
||||||
EXPECT_FALSE(HasSentData(0));
|
|
||||||
|
|
||||||
cricket::StreamParams stream;
|
|
||||||
stream.add_ssrc(42);
|
|
||||||
ASSERT_TRUE(dmc->AddSendStream(stream));
|
|
||||||
|
|
||||||
// Unknown codec;
|
|
||||||
EXPECT_FALSE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_EQ(cricket::SDR_ERROR, result);
|
|
||||||
EXPECT_FALSE(HasSentData(0));
|
|
||||||
|
|
||||||
cricket::DataCodec codec;
|
|
||||||
codec.id = 103;
|
|
||||||
codec.name = cricket::kGoogleRtpDataCodecName;
|
|
||||||
cricket::DataSendParameters parameters;
|
|
||||||
parameters.codecs.push_back(codec);
|
|
||||||
ASSERT_TRUE(dmc->SetSendParameters(parameters));
|
|
||||||
|
|
||||||
// Length too large;
|
|
||||||
std::string x10000(10000, 'x');
|
|
||||||
EXPECT_FALSE(dmc->SendData(
|
|
||||||
params, rtc::CopyOnWriteBuffer(x10000.data(), x10000.length()), &result));
|
|
||||||
EXPECT_EQ(cricket::SDR_ERROR, result);
|
|
||||||
EXPECT_FALSE(HasSentData(0));
|
|
||||||
|
|
||||||
// Finally works!
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_EQ(cricket::SDR_SUCCESS, result);
|
|
||||||
ASSERT_TRUE(HasSentData(0));
|
|
||||||
EXPECT_EQ(sizeof(padded_data), GetSentData(0).length());
|
|
||||||
EXPECT_EQ(0, memcmp(padded_data, GetSentData(0).data(), sizeof(padded_data)));
|
|
||||||
cricket::RtpHeader header0 = GetSentDataHeader(0);
|
|
||||||
EXPECT_NE(0, header0.seq_num);
|
|
||||||
EXPECT_NE(0U, header0.timestamp);
|
|
||||||
EXPECT_EQ(header0.ssrc, 42U);
|
|
||||||
EXPECT_EQ(header0.payload_type, 103);
|
|
||||||
|
|
||||||
// Should bump timestamp by 180000 because the clock rate is 90khz.
|
|
||||||
SetNow(2);
|
|
||||||
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
ASSERT_TRUE(HasSentData(1));
|
|
||||||
EXPECT_EQ(sizeof(padded_data), GetSentData(1).length());
|
|
||||||
EXPECT_EQ(0, memcmp(padded_data, GetSentData(1).data(), sizeof(padded_data)));
|
|
||||||
cricket::RtpHeader header1 = GetSentDataHeader(1);
|
|
||||||
EXPECT_EQ(header1.ssrc, 42U);
|
|
||||||
EXPECT_EQ(header1.payload_type, 103);
|
|
||||||
EXPECT_EQ(static_cast<uint16_t>(header0.seq_num + 1),
|
|
||||||
static_cast<uint16_t>(header1.seq_num));
|
|
||||||
EXPECT_EQ(header0.timestamp + 180000, header1.timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataMediaChannelTest, SendDataRate) {
|
|
||||||
std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
|
|
||||||
|
|
||||||
ASSERT_TRUE(dmc->SetSend(true));
|
|
||||||
|
|
||||||
cricket::DataCodec codec;
|
|
||||||
codec.id = 103;
|
|
||||||
codec.name = cricket::kGoogleRtpDataCodecName;
|
|
||||||
cricket::DataSendParameters parameters;
|
|
||||||
parameters.codecs.push_back(codec);
|
|
||||||
ASSERT_TRUE(dmc->SetSendParameters(parameters));
|
|
||||||
|
|
||||||
cricket::StreamParams stream;
|
|
||||||
stream.add_ssrc(42);
|
|
||||||
ASSERT_TRUE(dmc->AddSendStream(stream));
|
|
||||||
|
|
||||||
cricket::SendDataParams params;
|
|
||||||
params.ssrc = 42;
|
|
||||||
unsigned char data[] = "food";
|
|
||||||
rtc::CopyOnWriteBuffer payload(data, 4);
|
|
||||||
cricket::SendDataResult result;
|
|
||||||
|
|
||||||
// With rtp overhead of 32 bytes, each one of our packets is 36
|
|
||||||
// bytes, or 288 bits. So, a limit of 872bps will allow 3 packets,
|
|
||||||
// but not four.
|
|
||||||
parameters.max_bandwidth_bps = 872;
|
|
||||||
ASSERT_TRUE(dmc->SetSendParameters(parameters));
|
|
||||||
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_FALSE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_FALSE(dmc->SendData(params, payload, &result));
|
|
||||||
|
|
||||||
SetNow(0.9);
|
|
||||||
EXPECT_FALSE(dmc->SendData(params, payload, &result));
|
|
||||||
|
|
||||||
SetNow(1.1);
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
SetNow(1.9);
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
|
|
||||||
SetNow(2.2);
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_TRUE(dmc->SendData(params, payload, &result));
|
|
||||||
EXPECT_FALSE(dmc->SendData(params, payload, &result));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataMediaChannelTest, ReceiveData) {
|
|
||||||
// PT= 103, SN=2, TS=3, SSRC = 4, data = "abcde"
|
|
||||||
unsigned char data[] = {0x80, 0x67, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 'a', 'b', 'c', 'd', 'e'};
|
|
||||||
rtc::CopyOnWriteBuffer packet(data, sizeof(data));
|
|
||||||
|
|
||||||
std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
|
|
||||||
|
|
||||||
// SetReceived not called.
|
|
||||||
dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
|
|
||||||
EXPECT_FALSE(HasReceivedData());
|
|
||||||
|
|
||||||
dmc->SetReceive(true);
|
|
||||||
|
|
||||||
// Unknown payload id
|
|
||||||
dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
|
|
||||||
EXPECT_FALSE(HasReceivedData());
|
|
||||||
|
|
||||||
cricket::DataCodec codec;
|
|
||||||
codec.id = 103;
|
|
||||||
codec.name = cricket::kGoogleRtpDataCodecName;
|
|
||||||
cricket::DataRecvParameters parameters;
|
|
||||||
parameters.codecs.push_back(codec);
|
|
||||||
ASSERT_TRUE(dmc->SetRecvParameters(parameters));
|
|
||||||
|
|
||||||
// Unknown stream
|
|
||||||
dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
|
|
||||||
EXPECT_FALSE(HasReceivedData());
|
|
||||||
|
|
||||||
cricket::StreamParams stream;
|
|
||||||
stream.add_ssrc(42);
|
|
||||||
ASSERT_TRUE(dmc->AddRecvStream(stream));
|
|
||||||
|
|
||||||
// Finally works!
|
|
||||||
dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
|
|
||||||
EXPECT_TRUE(HasReceivedData());
|
|
||||||
EXPECT_EQ("abcde", GetReceivedData());
|
|
||||||
EXPECT_EQ(5U, GetReceivedDataLen());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataMediaChannelTest, InvalidRtpPackets) {
|
|
||||||
unsigned char data[] = {0x80, 0x65, 0x00, 0x02};
|
|
||||||
rtc::CopyOnWriteBuffer packet(data, sizeof(data));
|
|
||||||
|
|
||||||
std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
|
|
||||||
|
|
||||||
// Too short
|
|
||||||
dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
|
|
||||||
EXPECT_FALSE(HasReceivedData());
|
|
||||||
}
|
|
||||||
@ -190,8 +190,6 @@ rtc_library("peerconnection") {
|
|||||||
"rtc_stats_collector.h",
|
"rtc_stats_collector.h",
|
||||||
"rtc_stats_traversal.cc",
|
"rtc_stats_traversal.cc",
|
||||||
"rtc_stats_traversal.h",
|
"rtc_stats_traversal.h",
|
||||||
"rtp_data_channel.cc",
|
|
||||||
"rtp_data_channel.h",
|
|
||||||
"sctp_data_channel.cc",
|
"sctp_data_channel.cc",
|
||||||
"sctp_data_channel.h",
|
"sctp_data_channel.h",
|
||||||
"sdp_offer_answer.cc", # TODO: Make separate target when not circular
|
"sdp_offer_answer.cc", # TODO: Make separate target when not circular
|
||||||
|
|||||||
239
pc/channel.cc
239
pc/channel.cc
@ -1281,243 +1281,4 @@ bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RtpDataChannel::RtpDataChannel(rtc::Thread* worker_thread,
|
|
||||||
rtc::Thread* network_thread,
|
|
||||||
rtc::Thread* signaling_thread,
|
|
||||||
std::unique_ptr<DataMediaChannel> media_channel,
|
|
||||||
const std::string& content_name,
|
|
||||||
bool srtp_required,
|
|
||||||
webrtc::CryptoOptions crypto_options,
|
|
||||||
UniqueRandomIdGenerator* ssrc_generator)
|
|
||||||
: BaseChannel(worker_thread,
|
|
||||||
network_thread,
|
|
||||||
signaling_thread,
|
|
||||||
std::move(media_channel),
|
|
||||||
content_name,
|
|
||||||
srtp_required,
|
|
||||||
crypto_options,
|
|
||||||
ssrc_generator) {}
|
|
||||||
|
|
||||||
RtpDataChannel::~RtpDataChannel() {
|
|
||||||
TRACE_EVENT0("webrtc", "RtpDataChannel::~RtpDataChannel");
|
|
||||||
// this can't be done in the base class, since it calls a virtual
|
|
||||||
DisableMedia_w();
|
|
||||||
Deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport) {
|
|
||||||
BaseChannel::Init_w(rtp_transport);
|
|
||||||
media_channel()->SignalDataReceived.connect(this,
|
|
||||||
&RtpDataChannel::OnDataReceived);
|
|
||||||
media_channel()->SignalReadyToSend.connect(
|
|
||||||
this, &RtpDataChannel::OnDataChannelReadyToSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataChannel::SendData(const SendDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
|
||||||
SendDataResult* result) {
|
|
||||||
DataMediaChannel* mc = media_channel();
|
|
||||||
return InvokeOnWorker<bool>(RTC_FROM_HERE, [mc, ¶ms, &payload, result] {
|
|
||||||
return mc->SendData(params, payload, result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataChannel::CheckDataChannelTypeFromContent(
|
|
||||||
const MediaContentDescription* content,
|
|
||||||
std::string* error_desc) {
|
|
||||||
if (!content->as_rtp_data()) {
|
|
||||||
if (content->as_sctp()) {
|
|
||||||
SafeSetError("Data channel type mismatch. Expected RTP, got SCTP.",
|
|
||||||
error_desc);
|
|
||||||
} else {
|
|
||||||
SafeSetError("Data channel is not RTP or SCTP.", error_desc);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content,
|
|
||||||
SdpType type,
|
|
||||||
std::string* error_desc) {
|
|
||||||
TRACE_EVENT0("webrtc", "RtpDataChannel::SetLocalContent_w");
|
|
||||||
RTC_DCHECK_RUN_ON(worker_thread());
|
|
||||||
RTC_LOG(LS_INFO) << "Setting local data description for " << ToString();
|
|
||||||
|
|
||||||
RTC_DCHECK(content);
|
|
||||||
if (!content) {
|
|
||||||
SafeSetError("Can't find data content in local description.", error_desc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CheckDataChannelTypeFromContent(content, error_desc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const RtpDataContentDescription* data = content->as_rtp_data();
|
|
||||||
|
|
||||||
RtpHeaderExtensions rtp_header_extensions =
|
|
||||||
GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
|
|
||||||
|
|
||||||
DataRecvParameters recv_params = last_recv_params_;
|
|
||||||
RtpParametersFromMediaDescription(
|
|
||||||
data, rtp_header_extensions,
|
|
||||||
webrtc::RtpTransceiverDirectionHasRecv(data->direction()), &recv_params);
|
|
||||||
if (!media_channel()->SetRecvParameters(recv_params)) {
|
|
||||||
SafeSetError(
|
|
||||||
"Failed to set remote data description recv parameters for m-section "
|
|
||||||
"with mid='" +
|
|
||||||
content_name() + "'.",
|
|
||||||
error_desc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (const DataCodec& codec : data->codecs()) {
|
|
||||||
MaybeAddHandledPayloadType(codec.id);
|
|
||||||
}
|
|
||||||
// Need to re-register the sink to update the handled payload.
|
|
||||||
if (!RegisterRtpDemuxerSink_w()) {
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to set up data demuxing for " << ToString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_recv_params_ = recv_params;
|
|
||||||
|
|
||||||
// TODO(pthatcher): Move local streams into DataSendParameters, and
|
|
||||||
// only give it to the media channel once we have a remote
|
|
||||||
// description too (without a remote description, we won't be able
|
|
||||||
// to send them anyway).
|
|
||||||
if (!UpdateLocalStreams_w(data->streams(), type, error_desc)) {
|
|
||||||
SafeSetError(
|
|
||||||
"Failed to set local data description streams for m-section with "
|
|
||||||
"mid='" +
|
|
||||||
content_name() + "'.",
|
|
||||||
error_desc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_local_content_direction(content->direction());
|
|
||||||
UpdateMediaSendRecvState_w();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content,
|
|
||||||
SdpType type,
|
|
||||||
std::string* error_desc) {
|
|
||||||
TRACE_EVENT0("webrtc", "RtpDataChannel::SetRemoteContent_w");
|
|
||||||
RTC_DCHECK_RUN_ON(worker_thread());
|
|
||||||
RTC_LOG(LS_INFO) << "Setting remote data description for " << ToString();
|
|
||||||
|
|
||||||
RTC_DCHECK(content);
|
|
||||||
if (!content) {
|
|
||||||
SafeSetError("Can't find data content in remote description.", error_desc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CheckDataChannelTypeFromContent(content, error_desc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RtpDataContentDescription* data = content->as_rtp_data();
|
|
||||||
|
|
||||||
// If the remote data doesn't have codecs, it must be empty, so ignore it.
|
|
||||||
if (!data->has_codecs()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpHeaderExtensions rtp_header_extensions =
|
|
||||||
GetFilteredRtpHeaderExtensions(data->rtp_header_extensions());
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Setting remote data description for " << ToString();
|
|
||||||
DataSendParameters send_params = last_send_params_;
|
|
||||||
RtpSendParametersFromMediaDescription<DataCodec>(
|
|
||||||
data, rtp_header_extensions,
|
|
||||||
webrtc::RtpTransceiverDirectionHasRecv(data->direction()), &send_params);
|
|
||||||
if (!media_channel()->SetSendParameters(send_params)) {
|
|
||||||
SafeSetError(
|
|
||||||
"Failed to set remote data description send parameters for m-section "
|
|
||||||
"with mid='" +
|
|
||||||
content_name() + "'.",
|
|
||||||
error_desc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
last_send_params_ = send_params;
|
|
||||||
|
|
||||||
// TODO(pthatcher): Move remote streams into DataRecvParameters,
|
|
||||||
// and only give it to the media channel once we have a local
|
|
||||||
// description too (without a local description, we won't be able to
|
|
||||||
// recv them anyway).
|
|
||||||
if (!UpdateRemoteStreams_w(data->streams(), type, error_desc)) {
|
|
||||||
SafeSetError(
|
|
||||||
"Failed to set remote data description streams for m-section with "
|
|
||||||
"mid='" +
|
|
||||||
content_name() + "'.",
|
|
||||||
error_desc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_remote_content_direction(content->direction());
|
|
||||||
UpdateMediaSendRecvState_w();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::UpdateMediaSendRecvState_w() {
|
|
||||||
// Render incoming data if we're the active call, and we have the local
|
|
||||||
// content. We receive data on the default channel and multiplexed streams.
|
|
||||||
RTC_DCHECK_RUN_ON(worker_thread());
|
|
||||||
bool recv = IsReadyToReceiveMedia_w();
|
|
||||||
if (!media_channel()->SetReceive(recv)) {
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to SetReceive on data channel: " << ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send outgoing data if we're the active call, we have the remote content,
|
|
||||||
// and we have had some form of connectivity.
|
|
||||||
bool send = IsReadyToSendMedia_w();
|
|
||||||
if (!media_channel()->SetSend(send)) {
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to SetSend on data channel: " << ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger SignalReadyToSendData asynchronously.
|
|
||||||
OnDataChannelReadyToSend(send);
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send
|
|
||||||
<< " for " << ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::OnMessage(rtc::Message* pmsg) {
|
|
||||||
switch (pmsg->message_id) {
|
|
||||||
case MSG_READYTOSENDDATA: {
|
|
||||||
DataChannelReadyToSendMessageData* data =
|
|
||||||
static_cast<DataChannelReadyToSendMessageData*>(pmsg->pdata);
|
|
||||||
ready_to_send_data_ = data->data();
|
|
||||||
SignalReadyToSendData(ready_to_send_data_);
|
|
||||||
delete data;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MSG_DATARECEIVED: {
|
|
||||||
DataReceivedMessageData* data =
|
|
||||||
static_cast<DataReceivedMessageData*>(pmsg->pdata);
|
|
||||||
SignalDataReceived(data->params, data->payload);
|
|
||||||
delete data;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
BaseChannel::OnMessage(pmsg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::OnDataReceived(const ReceiveDataParams& params,
|
|
||||||
const char* data,
|
|
||||||
size_t len) {
|
|
||||||
DataReceivedMessageData* msg = new DataReceivedMessageData(params, data, len);
|
|
||||||
signaling_thread()->Post(RTC_FROM_HERE, this, MSG_DATARECEIVED, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::OnDataChannelReadyToSend(bool writable) {
|
|
||||||
// This is usded for congestion control to indicate that the stream is ready
|
|
||||||
// to send by the MediaChannel, as opposed to OnReadyToSend, which indicates
|
|
||||||
// that the transport channel is ready.
|
|
||||||
signaling_thread()->Post(RTC_FROM_HERE, this, MSG_READYTOSENDDATA,
|
|
||||||
new DataChannelReadyToSendMessageData(writable));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
98
pc/channel.h
98
pc/channel.h
@ -471,104 +471,6 @@ class VideoChannel : public BaseChannel {
|
|||||||
VideoRecvParameters last_recv_params_;
|
VideoRecvParameters last_recv_params_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// RtpDataChannel is a specialization for data.
|
|
||||||
class RtpDataChannel : public BaseChannel {
|
|
||||||
public:
|
|
||||||
RtpDataChannel(rtc::Thread* worker_thread,
|
|
||||||
rtc::Thread* network_thread,
|
|
||||||
rtc::Thread* signaling_thread,
|
|
||||||
std::unique_ptr<DataMediaChannel> channel,
|
|
||||||
const std::string& content_name,
|
|
||||||
bool srtp_required,
|
|
||||||
webrtc::CryptoOptions crypto_options,
|
|
||||||
rtc::UniqueRandomIdGenerator* ssrc_generator);
|
|
||||||
~RtpDataChannel();
|
|
||||||
// TODO(zhihuang): Remove this once the RtpTransport can be shared between
|
|
||||||
// BaseChannels.
|
|
||||||
void Init_w(DtlsTransportInternal* rtp_dtls_transport,
|
|
||||||
DtlsTransportInternal* rtcp_dtls_transport,
|
|
||||||
rtc::PacketTransportInternal* rtp_packet_transport,
|
|
||||||
rtc::PacketTransportInternal* rtcp_packet_transport);
|
|
||||||
void Init_w(webrtc::RtpTransportInternal* rtp_transport) override;
|
|
||||||
|
|
||||||
virtual bool SendData(const SendDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
|
||||||
SendDataResult* result);
|
|
||||||
|
|
||||||
// Should be called on the signaling thread only.
|
|
||||||
bool ready_to_send_data() const { return ready_to_send_data_; }
|
|
||||||
|
|
||||||
sigslot::signal2<const ReceiveDataParams&, const rtc::CopyOnWriteBuffer&>
|
|
||||||
SignalDataReceived;
|
|
||||||
// Signal for notifying when the channel becomes ready to send data.
|
|
||||||
// That occurs when the channel is enabled, the transport is writable,
|
|
||||||
// both local and remote descriptions are set, and the channel is unblocked.
|
|
||||||
sigslot::signal1<bool> SignalReadyToSendData;
|
|
||||||
cricket::MediaType media_type() const override {
|
|
||||||
return cricket::MEDIA_TYPE_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// downcasts a MediaChannel.
|
|
||||||
DataMediaChannel* media_channel() const override {
|
|
||||||
return static_cast<DataMediaChannel*>(BaseChannel::media_channel());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct SendDataMessageData : public rtc::MessageData {
|
|
||||||
SendDataMessageData(const SendDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer* payload,
|
|
||||||
SendDataResult* result)
|
|
||||||
: params(params), payload(payload), result(result), succeeded(false) {}
|
|
||||||
|
|
||||||
const SendDataParams& params;
|
|
||||||
const rtc::CopyOnWriteBuffer* payload;
|
|
||||||
SendDataResult* result;
|
|
||||||
bool succeeded;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DataReceivedMessageData : public rtc::MessageData {
|
|
||||||
// We copy the data because the data will become invalid after we
|
|
||||||
// handle DataMediaChannel::SignalDataReceived but before we fire
|
|
||||||
// SignalDataReceived.
|
|
||||||
DataReceivedMessageData(const ReceiveDataParams& params,
|
|
||||||
const char* data,
|
|
||||||
size_t len)
|
|
||||||
: params(params), payload(data, len) {}
|
|
||||||
const ReceiveDataParams params;
|
|
||||||
const rtc::CopyOnWriteBuffer payload;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef rtc::TypedMessageData<bool> DataChannelReadyToSendMessageData;
|
|
||||||
|
|
||||||
// overrides from BaseChannel
|
|
||||||
// Checks that data channel type is RTP.
|
|
||||||
bool CheckDataChannelTypeFromContent(const MediaContentDescription* content,
|
|
||||||
std::string* error_desc);
|
|
||||||
bool SetLocalContent_w(const MediaContentDescription* content,
|
|
||||||
webrtc::SdpType type,
|
|
||||||
std::string* error_desc) override;
|
|
||||||
bool SetRemoteContent_w(const MediaContentDescription* content,
|
|
||||||
webrtc::SdpType type,
|
|
||||||
std::string* error_desc) override;
|
|
||||||
void UpdateMediaSendRecvState_w() override;
|
|
||||||
|
|
||||||
void OnMessage(rtc::Message* pmsg) override;
|
|
||||||
void OnDataReceived(const ReceiveDataParams& params,
|
|
||||||
const char* data,
|
|
||||||
size_t len);
|
|
||||||
void OnDataChannelReadyToSend(bool writable);
|
|
||||||
|
|
||||||
bool ready_to_send_data_ = false;
|
|
||||||
|
|
||||||
// Last DataSendParameters sent down to the media_channel() via
|
|
||||||
// SetSendParameters.
|
|
||||||
DataSendParameters last_send_params_;
|
|
||||||
// Last DataRecvParameters sent down to the media_channel() via
|
|
||||||
// SetRecvParameters.
|
|
||||||
DataRecvParameters last_recv_params_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|
||||||
#endif // PC_CHANNEL_H_
|
#endif // PC_CHANNEL_H_
|
||||||
|
|||||||
@ -28,35 +28,29 @@ namespace cricket {
|
|||||||
// static
|
// static
|
||||||
std::unique_ptr<ChannelManager> ChannelManager::Create(
|
std::unique_ptr<ChannelManager> ChannelManager::Create(
|
||||||
std::unique_ptr<MediaEngineInterface> media_engine,
|
std::unique_ptr<MediaEngineInterface> media_engine,
|
||||||
std::unique_ptr<DataEngineInterface> data_engine,
|
|
||||||
bool enable_rtx,
|
bool enable_rtx,
|
||||||
rtc::Thread* worker_thread,
|
rtc::Thread* worker_thread,
|
||||||
rtc::Thread* network_thread) {
|
rtc::Thread* network_thread) {
|
||||||
RTC_DCHECK_RUN_ON(worker_thread);
|
RTC_DCHECK_RUN_ON(worker_thread);
|
||||||
RTC_DCHECK(network_thread);
|
RTC_DCHECK(network_thread);
|
||||||
RTC_DCHECK(worker_thread);
|
RTC_DCHECK(worker_thread);
|
||||||
RTC_DCHECK(data_engine);
|
|
||||||
|
|
||||||
if (media_engine)
|
if (media_engine)
|
||||||
media_engine->Init();
|
media_engine->Init();
|
||||||
|
|
||||||
return absl::WrapUnique(new ChannelManager(std::move(media_engine),
|
return absl::WrapUnique(new ChannelManager(
|
||||||
std::move(data_engine), enable_rtx,
|
std::move(media_engine), enable_rtx, worker_thread, network_thread));
|
||||||
worker_thread, network_thread));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelManager::ChannelManager(
|
ChannelManager::ChannelManager(
|
||||||
std::unique_ptr<MediaEngineInterface> media_engine,
|
std::unique_ptr<MediaEngineInterface> media_engine,
|
||||||
std::unique_ptr<DataEngineInterface> data_engine,
|
|
||||||
bool enable_rtx,
|
bool enable_rtx,
|
||||||
rtc::Thread* worker_thread,
|
rtc::Thread* worker_thread,
|
||||||
rtc::Thread* network_thread)
|
rtc::Thread* network_thread)
|
||||||
: media_engine_(std::move(media_engine)),
|
: media_engine_(std::move(media_engine)),
|
||||||
data_engine_(std::move(data_engine)),
|
|
||||||
worker_thread_(worker_thread),
|
worker_thread_(worker_thread),
|
||||||
network_thread_(network_thread),
|
network_thread_(network_thread),
|
||||||
enable_rtx_(enable_rtx) {
|
enable_rtx_(enable_rtx) {
|
||||||
RTC_DCHECK(data_engine_);
|
|
||||||
RTC_DCHECK(worker_thread_);
|
RTC_DCHECK(worker_thread_);
|
||||||
RTC_DCHECK(network_thread_);
|
RTC_DCHECK(network_thread_);
|
||||||
RTC_DCHECK_RUN_ON(worker_thread_);
|
RTC_DCHECK_RUN_ON(worker_thread_);
|
||||||
@ -116,11 +110,6 @@ void ChannelManager::GetSupportedVideoReceiveCodecs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelManager::GetSupportedDataCodecs(
|
|
||||||
std::vector<DataCodec>* codecs) const {
|
|
||||||
*codecs = data_engine_->data_codecs();
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpHeaderExtensions ChannelManager::GetDefaultEnabledAudioRtpHeaderExtensions()
|
RtpHeaderExtensions ChannelManager::GetDefaultEnabledAudioRtpHeaderExtensions()
|
||||||
const {
|
const {
|
||||||
if (!media_engine_)
|
if (!media_engine_)
|
||||||
@ -273,61 +262,6 @@ void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
RtpDataChannel* ChannelManager::CreateRtpDataChannel(
|
|
||||||
const MediaConfig& media_config,
|
|
||||||
webrtc::RtpTransportInternal* rtp_transport,
|
|
||||||
rtc::Thread* signaling_thread,
|
|
||||||
const std::string& content_name,
|
|
||||||
bool srtp_required,
|
|
||||||
const webrtc::CryptoOptions& crypto_options,
|
|
||||||
rtc::UniqueRandomIdGenerator* ssrc_generator) {
|
|
||||||
if (!worker_thread_->IsCurrent()) {
|
|
||||||
return worker_thread_->Invoke<RtpDataChannel*>(RTC_FROM_HERE, [&] {
|
|
||||||
return CreateRtpDataChannel(media_config, rtp_transport, signaling_thread,
|
|
||||||
content_name, srtp_required, crypto_options,
|
|
||||||
ssrc_generator);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
RTC_DCHECK_RUN_ON(worker_thread_);
|
|
||||||
|
|
||||||
// This is ok to alloc from a thread other than the worker thread.
|
|
||||||
DataMediaChannel* media_channel = data_engine_->CreateChannel(media_config);
|
|
||||||
if (!media_channel) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Failed to create RTP data channel.";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto data_channel = std::make_unique<RtpDataChannel>(
|
|
||||||
worker_thread_, network_thread_, signaling_thread,
|
|
||||||
absl::WrapUnique(media_channel), content_name, srtp_required,
|
|
||||||
crypto_options, ssrc_generator);
|
|
||||||
|
|
||||||
// Media Transports are not supported with Rtp Data Channel.
|
|
||||||
data_channel->Init_w(rtp_transport);
|
|
||||||
|
|
||||||
RtpDataChannel* data_channel_ptr = data_channel.get();
|
|
||||||
data_channels_.push_back(std::move(data_channel));
|
|
||||||
return data_channel_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChannelManager::DestroyRtpDataChannel(RtpDataChannel* data_channel) {
|
|
||||||
TRACE_EVENT0("webrtc", "ChannelManager::DestroyRtpDataChannel");
|
|
||||||
RTC_DCHECK(data_channel);
|
|
||||||
|
|
||||||
if (!worker_thread_->IsCurrent()) {
|
|
||||||
worker_thread_->Invoke<void>(
|
|
||||||
RTC_FROM_HERE, [&] { return DestroyRtpDataChannel(data_channel); });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RTC_DCHECK_RUN_ON(worker_thread_);
|
|
||||||
|
|
||||||
data_channels_.erase(absl::c_find_if(
|
|
||||||
data_channels_, [&](const std::unique_ptr<RtpDataChannel>& p) {
|
|
||||||
return p.get() == data_channel;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChannelManager::StartAecDump(webrtc::FileWrapper file,
|
bool ChannelManager::StartAecDump(webrtc::FileWrapper file,
|
||||||
int64_t max_size_bytes) {
|
int64_t max_size_bytes) {
|
||||||
RTC_DCHECK_RUN_ON(worker_thread_);
|
RTC_DCHECK_RUN_ON(worker_thread_);
|
||||||
|
|||||||
@ -50,7 +50,6 @@ class ChannelManager final {
|
|||||||
// will own that reference and media engine initialization
|
// will own that reference and media engine initialization
|
||||||
static std::unique_ptr<ChannelManager> Create(
|
static std::unique_ptr<ChannelManager> Create(
|
||||||
std::unique_ptr<MediaEngineInterface> media_engine,
|
std::unique_ptr<MediaEngineInterface> media_engine,
|
||||||
std::unique_ptr<DataEngineInterface> data_engine,
|
|
||||||
bool enable_rtx,
|
bool enable_rtx,
|
||||||
rtc::Thread* worker_thread,
|
rtc::Thread* worker_thread,
|
||||||
rtc::Thread* network_thread);
|
rtc::Thread* network_thread);
|
||||||
@ -110,17 +109,6 @@ class ChannelManager final {
|
|||||||
// Destroys a video channel created by CreateVideoChannel.
|
// Destroys a video channel created by CreateVideoChannel.
|
||||||
void DestroyVideoChannel(VideoChannel* video_channel);
|
void DestroyVideoChannel(VideoChannel* video_channel);
|
||||||
|
|
||||||
RtpDataChannel* CreateRtpDataChannel(
|
|
||||||
const MediaConfig& media_config,
|
|
||||||
webrtc::RtpTransportInternal* rtp_transport,
|
|
||||||
rtc::Thread* signaling_thread,
|
|
||||||
const std::string& content_name,
|
|
||||||
bool srtp_required,
|
|
||||||
const webrtc::CryptoOptions& crypto_options,
|
|
||||||
rtc::UniqueRandomIdGenerator* ssrc_generator);
|
|
||||||
// Destroys a data channel created by CreateRtpDataChannel.
|
|
||||||
void DestroyRtpDataChannel(RtpDataChannel* data_channel);
|
|
||||||
|
|
||||||
// Starts AEC dump using existing file, with a specified maximum file size in
|
// Starts AEC dump using existing file, with a specified maximum file size in
|
||||||
// bytes. When the limit is reached, logging will stop and the file will be
|
// bytes. When the limit is reached, logging will stop and the file will be
|
||||||
// closed. If max_size_bytes is set to <= 0, no limit will be used.
|
// closed. If max_size_bytes is set to <= 0, no limit will be used.
|
||||||
@ -131,13 +119,11 @@ class ChannelManager final {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ChannelManager(std::unique_ptr<MediaEngineInterface> media_engine,
|
ChannelManager(std::unique_ptr<MediaEngineInterface> media_engine,
|
||||||
std::unique_ptr<DataEngineInterface> data_engine,
|
|
||||||
bool enable_rtx,
|
bool enable_rtx,
|
||||||
rtc::Thread* worker_thread,
|
rtc::Thread* worker_thread,
|
||||||
rtc::Thread* network_thread);
|
rtc::Thread* network_thread);
|
||||||
|
|
||||||
const std::unique_ptr<MediaEngineInterface> media_engine_; // Nullable.
|
const std::unique_ptr<MediaEngineInterface> media_engine_; // Nullable.
|
||||||
const std::unique_ptr<DataEngineInterface> data_engine_; // Non-null.
|
|
||||||
rtc::Thread* const worker_thread_;
|
rtc::Thread* const worker_thread_;
|
||||||
rtc::Thread* const network_thread_;
|
rtc::Thread* const network_thread_;
|
||||||
|
|
||||||
@ -146,8 +132,6 @@ class ChannelManager final {
|
|||||||
RTC_GUARDED_BY(worker_thread_);
|
RTC_GUARDED_BY(worker_thread_);
|
||||||
std::vector<std::unique_ptr<VideoChannel>> video_channels_
|
std::vector<std::unique_ptr<VideoChannel>> video_channels_
|
||||||
RTC_GUARDED_BY(worker_thread_);
|
RTC_GUARDED_BY(worker_thread_);
|
||||||
std::vector<std::unique_ptr<RtpDataChannel>> data_channels_
|
|
||||||
RTC_GUARDED_BY(worker_thread_);
|
|
||||||
|
|
||||||
const bool enable_rtx_;
|
const bool enable_rtx_;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -58,7 +58,6 @@ class ChannelManagerTest : public ::testing::Test {
|
|||||||
video_bitrate_allocator_factory_(
|
video_bitrate_allocator_factory_(
|
||||||
webrtc::CreateBuiltinVideoBitrateAllocatorFactory()),
|
webrtc::CreateBuiltinVideoBitrateAllocatorFactory()),
|
||||||
cm_(cricket::ChannelManager::Create(CreateFakeMediaEngine(),
|
cm_(cricket::ChannelManager::Create(CreateFakeMediaEngine(),
|
||||||
std::make_unique<FakeDataEngine>(),
|
|
||||||
false,
|
false,
|
||||||
worker_,
|
worker_,
|
||||||
network_.get())),
|
network_.get())),
|
||||||
@ -80,14 +79,8 @@ class ChannelManagerTest : public ::testing::Test {
|
|||||||
webrtc::CryptoOptions(), &ssrc_generator_, VideoOptions(),
|
webrtc::CryptoOptions(), &ssrc_generator_, VideoOptions(),
|
||||||
video_bitrate_allocator_factory_.get());
|
video_bitrate_allocator_factory_.get());
|
||||||
EXPECT_TRUE(video_channel != nullptr);
|
EXPECT_TRUE(video_channel != nullptr);
|
||||||
cricket::RtpDataChannel* rtp_data_channel = cm_->CreateRtpDataChannel(
|
|
||||||
cricket::MediaConfig(), rtp_transport, rtc::Thread::Current(),
|
|
||||||
cricket::CN_DATA, kDefaultSrtpRequired, webrtc::CryptoOptions(),
|
|
||||||
&ssrc_generator_);
|
|
||||||
EXPECT_TRUE(rtp_data_channel != nullptr);
|
|
||||||
cm_->DestroyVideoChannel(video_channel);
|
cm_->DestroyVideoChannel(video_channel);
|
||||||
cm_->DestroyVoiceChannel(voice_channel);
|
cm_->DestroyVoiceChannel(voice_channel);
|
||||||
cm_->DestroyRtpDataChannel(rtp_data_channel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<rtc::Thread> network_;
|
std::unique_ptr<rtc::Thread> network_;
|
||||||
@ -112,7 +105,6 @@ TEST_F(ChannelManagerTest, SetVideoRtxEnabled) {
|
|||||||
|
|
||||||
// Enable and check.
|
// Enable and check.
|
||||||
cm_ = cricket::ChannelManager::Create(CreateFakeMediaEngine(),
|
cm_ = cricket::ChannelManager::Create(CreateFakeMediaEngine(),
|
||||||
std::make_unique<FakeDataEngine>(),
|
|
||||||
true, worker_, network_.get());
|
true, worker_, network_.get());
|
||||||
cm_->GetSupportedVideoSendCodecs(&send_codecs);
|
cm_->GetSupportedVideoSendCodecs(&send_codecs);
|
||||||
EXPECT_TRUE(ContainsMatchingCodec(send_codecs, rtx_codec));
|
EXPECT_TRUE(ContainsMatchingCodec(send_codecs, rtx_codec));
|
||||||
@ -121,7 +113,6 @@ TEST_F(ChannelManagerTest, SetVideoRtxEnabled) {
|
|||||||
|
|
||||||
// Disable and check.
|
// Disable and check.
|
||||||
cm_ = cricket::ChannelManager::Create(CreateFakeMediaEngine(),
|
cm_ = cricket::ChannelManager::Create(CreateFakeMediaEngine(),
|
||||||
std::make_unique<FakeDataEngine>(),
|
|
||||||
false, worker_, network_.get());
|
false, worker_, network_.get());
|
||||||
cm_->GetSupportedVideoSendCodecs(&send_codecs);
|
cm_->GetSupportedVideoSendCodecs(&send_codecs);
|
||||||
EXPECT_FALSE(ContainsMatchingCodec(send_codecs, rtx_codec));
|
EXPECT_FALSE(ContainsMatchingCodec(send_codecs, rtx_codec));
|
||||||
|
|||||||
@ -93,13 +93,6 @@ class VideoTraits : public Traits<cricket::VideoChannel,
|
|||||||
cricket::VideoMediaInfo,
|
cricket::VideoMediaInfo,
|
||||||
cricket::VideoOptions> {};
|
cricket::VideoOptions> {};
|
||||||
|
|
||||||
class DataTraits : public Traits<cricket::RtpDataChannel,
|
|
||||||
cricket::FakeDataMediaChannel,
|
|
||||||
cricket::RtpDataContentDescription,
|
|
||||||
cricket::RtpDataCodec,
|
|
||||||
cricket::DataMediaInfo,
|
|
||||||
cricket::DataOptions> {};
|
|
||||||
|
|
||||||
// Base class for Voice/Video/RtpDataChannel tests
|
// Base class for Voice/Video/RtpDataChannel tests
|
||||||
template <class T>
|
template <class T>
|
||||||
class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
|
class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
|
||||||
@ -2274,220 +2267,5 @@ TEST_F(VideoChannelDoubleThreadTest, SocketOptionsMergedOnSetTransport) {
|
|||||||
Base::SocketOptionsMergedOnSetTransport();
|
Base::SocketOptionsMergedOnSetTransport();
|
||||||
}
|
}
|
||||||
|
|
||||||
// RtpDataChannelSingleThreadTest
|
|
||||||
class RtpDataChannelSingleThreadTest : public ChannelTest<DataTraits> {
|
|
||||||
public:
|
|
||||||
typedef ChannelTest<DataTraits> Base;
|
|
||||||
RtpDataChannelSingleThreadTest()
|
|
||||||
: Base(true, kDataPacket, kRtcpReport, NetworkIsWorker::Yes) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// RtpDataChannelDoubleThreadTest
|
|
||||||
class RtpDataChannelDoubleThreadTest : public ChannelTest<DataTraits> {
|
|
||||||
public:
|
|
||||||
typedef ChannelTest<DataTraits> Base;
|
|
||||||
RtpDataChannelDoubleThreadTest()
|
|
||||||
: Base(true, kDataPacket, kRtcpReport, NetworkIsWorker::No) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Override to avoid engine channel parameter.
|
|
||||||
template <>
|
|
||||||
std::unique_ptr<cricket::RtpDataChannel> ChannelTest<DataTraits>::CreateChannel(
|
|
||||||
rtc::Thread* worker_thread,
|
|
||||||
rtc::Thread* network_thread,
|
|
||||||
std::unique_ptr<cricket::FakeDataMediaChannel> ch,
|
|
||||||
webrtc::RtpTransportInternal* rtp_transport,
|
|
||||||
int flags) {
|
|
||||||
rtc::Thread* signaling_thread = rtc::Thread::Current();
|
|
||||||
auto channel = std::make_unique<cricket::RtpDataChannel>(
|
|
||||||
worker_thread, network_thread, signaling_thread, std::move(ch),
|
|
||||||
cricket::CN_DATA, (flags & DTLS) != 0, webrtc::CryptoOptions(),
|
|
||||||
&ssrc_generator_);
|
|
||||||
channel->Init_w(rtp_transport);
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void ChannelTest<DataTraits>::CreateContent(
|
|
||||||
int flags,
|
|
||||||
const cricket::AudioCodec& audio_codec,
|
|
||||||
const cricket::VideoCodec& video_codec,
|
|
||||||
cricket::RtpDataContentDescription* data) {
|
|
||||||
data->AddCodec(kGoogleDataCodec);
|
|
||||||
data->set_rtcp_mux((flags & RTCP_MUX) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void ChannelTest<DataTraits>::CopyContent(
|
|
||||||
const cricket::RtpDataContentDescription& source,
|
|
||||||
cricket::RtpDataContentDescription* data) {
|
|
||||||
*data = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
bool ChannelTest<DataTraits>::CodecMatches(const cricket::DataCodec& c1,
|
|
||||||
const cricket::DataCodec& c2) {
|
|
||||||
return c1.name == c2.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void ChannelTest<DataTraits>::AddLegacyStreamInContent(
|
|
||||||
uint32_t ssrc,
|
|
||||||
int flags,
|
|
||||||
cricket::RtpDataContentDescription* data) {
|
|
||||||
data->AddLegacyStream(ssrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestInit) {
|
|
||||||
Base::TestInit();
|
|
||||||
EXPECT_FALSE(media_channel1_->IsStreamMuted(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestDeinit) {
|
|
||||||
Base::TestDeinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestSetContents) {
|
|
||||||
Base::TestSetContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestSetContentsNullOffer) {
|
|
||||||
Base::TestSetContentsNullOffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestSetContentsRtcpMux) {
|
|
||||||
Base::TestSetContentsRtcpMux();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestChangeStreamParamsInContent) {
|
|
||||||
Base::TestChangeStreamParamsInContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestPlayoutAndSendingStates) {
|
|
||||||
Base::TestPlayoutAndSendingStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestMediaContentDirection) {
|
|
||||||
Base::TestMediaContentDirection();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestCallSetup) {
|
|
||||||
Base::TestCallSetup();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestCallTeardownRtcpMux) {
|
|
||||||
Base::TestCallTeardownRtcpMux();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestOnTransportReadyToSend) {
|
|
||||||
Base::TestOnTransportReadyToSend();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, SendRtpToRtp) {
|
|
||||||
Base::SendRtpToRtp();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, SendRtpToRtpOnThread) {
|
|
||||||
Base::SendRtpToRtpOnThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, SendWithWritabilityLoss) {
|
|
||||||
Base::SendWithWritabilityLoss();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, SocketOptionsMergedOnSetTransport) {
|
|
||||||
Base::SocketOptionsMergedOnSetTransport();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelSingleThreadTest, TestSendData) {
|
|
||||||
CreateChannels(0, 0);
|
|
||||||
EXPECT_TRUE(SendInitiate());
|
|
||||||
EXPECT_TRUE(SendAccept());
|
|
||||||
|
|
||||||
cricket::SendDataParams params;
|
|
||||||
params.ssrc = 42;
|
|
||||||
unsigned char data[] = {'f', 'o', 'o'};
|
|
||||||
rtc::CopyOnWriteBuffer payload(data, 3);
|
|
||||||
cricket::SendDataResult result;
|
|
||||||
ASSERT_TRUE(media_channel1_->SendData(params, payload, &result));
|
|
||||||
EXPECT_EQ(params.ssrc, media_channel1_->last_sent_data_params().ssrc);
|
|
||||||
EXPECT_EQ("foo", media_channel1_->last_sent_data());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestInit) {
|
|
||||||
Base::TestInit();
|
|
||||||
EXPECT_FALSE(media_channel1_->IsStreamMuted(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestDeinit) {
|
|
||||||
Base::TestDeinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestSetContents) {
|
|
||||||
Base::TestSetContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestSetContentsNullOffer) {
|
|
||||||
Base::TestSetContentsNullOffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestSetContentsRtcpMux) {
|
|
||||||
Base::TestSetContentsRtcpMux();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestChangeStreamParamsInContent) {
|
|
||||||
Base::TestChangeStreamParamsInContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestPlayoutAndSendingStates) {
|
|
||||||
Base::TestPlayoutAndSendingStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestMediaContentDirection) {
|
|
||||||
Base::TestMediaContentDirection();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestCallSetup) {
|
|
||||||
Base::TestCallSetup();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestCallTeardownRtcpMux) {
|
|
||||||
Base::TestCallTeardownRtcpMux();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestOnTransportReadyToSend) {
|
|
||||||
Base::TestOnTransportReadyToSend();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, SendRtpToRtp) {
|
|
||||||
Base::SendRtpToRtp();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, SendRtpToRtpOnThread) {
|
|
||||||
Base::SendRtpToRtpOnThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, SendWithWritabilityLoss) {
|
|
||||||
Base::SendWithWritabilityLoss();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, SocketOptionsMergedOnSetTransport) {
|
|
||||||
Base::SocketOptionsMergedOnSetTransport();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RtpDataChannelDoubleThreadTest, TestSendData) {
|
|
||||||
CreateChannels(0, 0);
|
|
||||||
EXPECT_TRUE(SendInitiate());
|
|
||||||
EXPECT_TRUE(SendAccept());
|
|
||||||
|
|
||||||
cricket::SendDataParams params;
|
|
||||||
params.ssrc = 42;
|
|
||||||
unsigned char data[] = {'f', 'o', 'o'};
|
|
||||||
rtc::CopyOnWriteBuffer payload(data, 3);
|
|
||||||
cricket::SendDataResult result;
|
|
||||||
ASSERT_TRUE(media_channel1_->SendData(params, payload, &result));
|
|
||||||
EXPECT_EQ(params.ssrc, media_channel1_->last_sent_data_params().ssrc);
|
|
||||||
EXPECT_EQ("foo", media_channel1_->last_sent_data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(pthatcher): TestSetReceiver?
|
// TODO(pthatcher): TestSetReceiver?
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "api/transport/field_trial_based_config.h"
|
#include "api/transport/field_trial_based_config.h"
|
||||||
#include "media/base/rtp_data_engine.h"
|
|
||||||
#include "media/sctp/sctp_transport_factory.h"
|
#include "media/sctp/sctp_transport_factory.h"
|
||||||
#include "rtc_base/helpers.h"
|
#include "rtc_base/helpers.h"
|
||||||
#include "rtc_base/ref_counted_object.h"
|
#include "rtc_base/ref_counted_object.h"
|
||||||
@ -127,8 +126,7 @@ ConnectionContext::ConnectionContext(
|
|||||||
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&]() {
|
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&]() {
|
||||||
channel_manager_ = cricket::ChannelManager::Create(
|
channel_manager_ = cricket::ChannelManager::Create(
|
||||||
std::move(dependencies->media_engine),
|
std::move(dependencies->media_engine),
|
||||||
std::make_unique<cricket::RtpDataEngine>(), /*enable_rtx=*/true,
|
/*enable_rtx=*/true, worker_thread(), network_thread());
|
||||||
worker_thread(), network_thread());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set warning levels on the threads, to give warnings when response
|
// Set warning levels on the threads, to give warnings when response
|
||||||
|
|||||||
@ -28,7 +28,7 @@ namespace webrtc {
|
|||||||
|
|
||||||
bool DataChannelController::HasDataChannels() const {
|
bool DataChannelController::HasDataChannels() const {
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
|
return !sctp_data_channels_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataChannelController::SendData(const cricket::SendDataParams& params,
|
bool DataChannelController::SendData(const cricket::SendDataParams& params,
|
||||||
@ -36,40 +36,10 @@ bool DataChannelController::SendData(const cricket::SendDataParams& params,
|
|||||||
cricket::SendDataResult* result) {
|
cricket::SendDataResult* result) {
|
||||||
if (data_channel_transport())
|
if (data_channel_transport())
|
||||||
return DataChannelSendData(params, payload, result);
|
return DataChannelSendData(params, payload, result);
|
||||||
if (rtp_data_channel())
|
|
||||||
return rtp_data_channel()->SendData(params, payload, result);
|
|
||||||
RTC_LOG(LS_ERROR) << "SendData called before transport is ready";
|
RTC_LOG(LS_ERROR) << "SendData called before transport is ready";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataChannelController::ConnectDataChannel(
|
|
||||||
RtpDataChannel* webrtc_data_channel) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
||||||
if (!rtp_data_channel()) {
|
|
||||||
// Don't log an error here, because DataChannels are expected to call
|
|
||||||
// ConnectDataChannel in this state. It's the only way to initially tell
|
|
||||||
// whether or not the underlying transport is ready.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rtp_data_channel()->SignalReadyToSendData.connect(
|
|
||||||
webrtc_data_channel, &RtpDataChannel::OnChannelReady);
|
|
||||||
rtp_data_channel()->SignalDataReceived.connect(
|
|
||||||
webrtc_data_channel, &RtpDataChannel::OnDataReceived);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataChannelController::DisconnectDataChannel(
|
|
||||||
RtpDataChannel* webrtc_data_channel) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
||||||
if (!rtp_data_channel()) {
|
|
||||||
RTC_LOG(LS_ERROR)
|
|
||||||
<< "DisconnectDataChannel called when rtp_data_channel_ is NULL.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rtp_data_channel()->SignalReadyToSendData.disconnect(webrtc_data_channel);
|
|
||||||
rtp_data_channel()->SignalDataReceived.disconnect(webrtc_data_channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DataChannelController::ConnectDataChannel(
|
bool DataChannelController::ConnectDataChannel(
|
||||||
SctpDataChannel* webrtc_data_channel) {
|
SctpDataChannel* webrtc_data_channel) {
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
@ -126,8 +96,7 @@ void DataChannelController::RemoveSctpDataStream(int sid) {
|
|||||||
|
|
||||||
bool DataChannelController::ReadyToSendData() const {
|
bool DataChannelController::ReadyToSendData() const {
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
return (rtp_data_channel() && rtp_data_channel()->ready_to_send_data()) ||
|
return (data_channel_transport() && data_channel_transport_ready_to_send_);
|
||||||
(data_channel_transport() && data_channel_transport_ready_to_send_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataChannelController::OnDataReceived(
|
void DataChannelController::OnDataReceived(
|
||||||
@ -258,10 +227,10 @@ bool DataChannelController::HandleOpenMessage_s(
|
|||||||
// be created.
|
// be created.
|
||||||
std::string label;
|
std::string label;
|
||||||
InternalDataChannelInit config;
|
InternalDataChannelInit config;
|
||||||
config.id = params.ssrc;
|
config.id = params.sid;
|
||||||
if (!ParseDataChannelOpenMessage(buffer, &label, &config)) {
|
if (!ParseDataChannelOpenMessage(buffer, &label, &config)) {
|
||||||
RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for ssrc "
|
RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
|
||||||
<< params.ssrc;
|
<< params.sid;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
config.open_handshake_role = InternalDataChannelInit::kAcker;
|
config.open_handshake_role = InternalDataChannelInit::kAcker;
|
||||||
@ -304,38 +273,11 @@ DataChannelController::InternalCreateDataChannelWithProxy(
|
|||||||
if (channel) {
|
if (channel) {
|
||||||
return SctpDataChannel::CreateProxy(channel);
|
return SctpDataChannel::CreateProxy(channel);
|
||||||
}
|
}
|
||||||
} else if (data_channel_type() == cricket::DCT_RTP) {
|
|
||||||
rtc::scoped_refptr<RtpDataChannel> channel =
|
|
||||||
InternalCreateRtpDataChannel(label, config);
|
|
||||||
if (channel) {
|
|
||||||
return RtpDataChannel::CreateProxy(channel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc::scoped_refptr<RtpDataChannel>
|
|
||||||
DataChannelController::InternalCreateRtpDataChannel(
|
|
||||||
const std::string& label,
|
|
||||||
const DataChannelInit* config) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
||||||
DataChannelInit new_config = config ? (*config) : DataChannelInit();
|
|
||||||
rtc::scoped_refptr<RtpDataChannel> channel(
|
|
||||||
RtpDataChannel::Create(this, label, new_config, signaling_thread()));
|
|
||||||
if (!channel) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
|
|
||||||
RTC_LOG(LS_ERROR) << "DataChannel with label " << channel->label()
|
|
||||||
<< " already exists.";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
rtp_data_channels_[channel->label()] = channel;
|
|
||||||
SignalRtpDataChannelCreated_(channel.get());
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc::scoped_refptr<SctpDataChannel>
|
rtc::scoped_refptr<SctpDataChannel>
|
||||||
DataChannelController::InternalCreateSctpDataChannel(
|
DataChannelController::InternalCreateSctpDataChannel(
|
||||||
const std::string& label,
|
const std::string& label,
|
||||||
@ -416,14 +358,8 @@ void DataChannelController::OnSctpDataChannelClosed(SctpDataChannel* channel) {
|
|||||||
|
|
||||||
void DataChannelController::OnTransportChannelClosed() {
|
void DataChannelController::OnTransportChannelClosed() {
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
// Use a temporary copy of the RTP/SCTP DataChannel list because the
|
// Use a temporary copy of the SCTP DataChannel list because the
|
||||||
// DataChannel may callback to us and try to modify the list.
|
// DataChannel may callback to us and try to modify the list.
|
||||||
std::map<std::string, rtc::scoped_refptr<RtpDataChannel>> temp_rtp_dcs;
|
|
||||||
temp_rtp_dcs.swap(rtp_data_channels_);
|
|
||||||
for (const auto& kv : temp_rtp_dcs) {
|
|
||||||
kv.second->OnTransportChannelClosed();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<rtc::scoped_refptr<SctpDataChannel>> temp_sctp_dcs;
|
std::vector<rtc::scoped_refptr<SctpDataChannel>> temp_sctp_dcs;
|
||||||
temp_sctp_dcs.swap(sctp_data_channels_);
|
temp_sctp_dcs.swap(sctp_data_channels_);
|
||||||
for (const auto& channel : temp_sctp_dcs) {
|
for (const auto& channel : temp_sctp_dcs) {
|
||||||
@ -441,58 +377,6 @@ SctpDataChannel* DataChannelController::FindDataChannelBySid(int sid) const {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataChannelController::UpdateLocalRtpDataChannels(
|
|
||||||
const cricket::StreamParamsVec& streams) {
|
|
||||||
std::vector<std::string> existing_channels;
|
|
||||||
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
||||||
// Find new and active data channels.
|
|
||||||
for (const cricket::StreamParams& params : streams) {
|
|
||||||
// |it->sync_label| is actually the data channel label. The reason is that
|
|
||||||
// we use the same naming of data channels as we do for
|
|
||||||
// MediaStreams and Tracks.
|
|
||||||
// For MediaStreams, the sync_label is the MediaStream label and the
|
|
||||||
// track label is the same as |streamid|.
|
|
||||||
const std::string& channel_label = params.first_stream_id();
|
|
||||||
auto data_channel_it = rtp_data_channels()->find(channel_label);
|
|
||||||
if (data_channel_it == rtp_data_channels()->end()) {
|
|
||||||
RTC_LOG(LS_ERROR) << "channel label not found";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Set the SSRC the data channel should use for sending.
|
|
||||||
data_channel_it->second->SetSendSsrc(params.first_ssrc());
|
|
||||||
existing_channels.push_back(data_channel_it->first);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateClosingRtpDataChannels(existing_channels, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataChannelController::UpdateRemoteRtpDataChannels(
|
|
||||||
const cricket::StreamParamsVec& streams) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
||||||
|
|
||||||
std::vector<std::string> existing_channels;
|
|
||||||
|
|
||||||
// Find new and active data channels.
|
|
||||||
for (const cricket::StreamParams& params : streams) {
|
|
||||||
// The data channel label is either the mslabel or the SSRC if the mslabel
|
|
||||||
// does not exist. Ex a=ssrc:444330170 mslabel:test1.
|
|
||||||
std::string label = params.first_stream_id().empty()
|
|
||||||
? rtc::ToString(params.first_ssrc())
|
|
||||||
: params.first_stream_id();
|
|
||||||
auto data_channel_it = rtp_data_channels()->find(label);
|
|
||||||
if (data_channel_it == rtp_data_channels()->end()) {
|
|
||||||
// This is a new data channel.
|
|
||||||
CreateRemoteRtpDataChannel(label, params.first_ssrc());
|
|
||||||
} else {
|
|
||||||
data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
|
|
||||||
}
|
|
||||||
existing_channels.push_back(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateClosingRtpDataChannels(existing_channels, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
cricket::DataChannelType DataChannelController::data_channel_type() const {
|
cricket::DataChannelType DataChannelController::data_channel_type() const {
|
||||||
// TODO(bugs.webrtc.org/9987): Should be restricted to the signaling thread.
|
// TODO(bugs.webrtc.org/9987): Should be restricted to the signaling thread.
|
||||||
// RTC_DCHECK_RUN_ON(signaling_thread());
|
// RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
@ -505,19 +389,6 @@ void DataChannelController::set_data_channel_type(
|
|||||||
data_channel_type_ = type;
|
data_channel_type_ = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
cricket::RtpDataChannel* DataChannelController::rtp_data_channel() const {
|
|
||||||
// TODO(bugs.webrtc.org/9987): Only allow this accessor to be called on the
|
|
||||||
// network thread.
|
|
||||||
// RTC_DCHECK_RUN_ON(network_thread());
|
|
||||||
return rtp_data_channel_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataChannelController::set_rtp_data_channel(
|
|
||||||
cricket::RtpDataChannel* channel) {
|
|
||||||
RTC_DCHECK_RUN_ON(network_thread());
|
|
||||||
rtp_data_channel_ = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataChannelTransportInterface* DataChannelController::data_channel_transport()
|
DataChannelTransportInterface* DataChannelController::data_channel_transport()
|
||||||
const {
|
const {
|
||||||
// TODO(bugs.webrtc.org/11547): Only allow this accessor to be called on the
|
// TODO(bugs.webrtc.org/11547): Only allow this accessor to be called on the
|
||||||
@ -532,56 +403,6 @@ void DataChannelController::set_data_channel_transport(
|
|||||||
data_channel_transport_ = transport;
|
data_channel_transport_ = transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, rtc::scoped_refptr<RtpDataChannel>>*
|
|
||||||
DataChannelController::rtp_data_channels() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
||||||
return &rtp_data_channels_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataChannelController::UpdateClosingRtpDataChannels(
|
|
||||||
const std::vector<std::string>& active_channels,
|
|
||||||
bool is_local_update) {
|
|
||||||
auto it = rtp_data_channels_.begin();
|
|
||||||
while (it != rtp_data_channels_.end()) {
|
|
||||||
RtpDataChannel* data_channel = it->second;
|
|
||||||
if (absl::c_linear_search(active_channels, data_channel->label())) {
|
|
||||||
++it;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_local_update) {
|
|
||||||
data_channel->SetSendSsrc(0);
|
|
||||||
} else {
|
|
||||||
data_channel->RemotePeerRequestClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data_channel->state() == RtpDataChannel::kClosed) {
|
|
||||||
rtp_data_channels_.erase(it);
|
|
||||||
it = rtp_data_channels_.begin();
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataChannelController::CreateRemoteRtpDataChannel(const std::string& label,
|
|
||||||
uint32_t remote_ssrc) {
|
|
||||||
if (data_channel_type() != cricket::DCT_RTP) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rtc::scoped_refptr<RtpDataChannel> channel(
|
|
||||||
InternalCreateRtpDataChannel(label, nullptr));
|
|
||||||
if (!channel.get()) {
|
|
||||||
RTC_LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
|
|
||||||
"CreateDataChannel failed.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
channel->SetReceiveSsrc(remote_ssrc);
|
|
||||||
rtc::scoped_refptr<DataChannelInterface> proxy_channel =
|
|
||||||
RtpDataChannel::CreateProxy(std::move(channel));
|
|
||||||
pc_->Observer()->OnDataChannel(std::move(proxy_channel));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DataChannelController::DataChannelSendData(
|
bool DataChannelController::DataChannelSendData(
|
||||||
const cricket::SendDataParams& params,
|
const cricket::SendDataParams& params,
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
const rtc::CopyOnWriteBuffer& payload,
|
||||||
|
|||||||
@ -27,7 +27,6 @@
|
|||||||
#include "media/base/stream_params.h"
|
#include "media/base/stream_params.h"
|
||||||
#include "pc/channel.h"
|
#include "pc/channel.h"
|
||||||
#include "pc/data_channel_utils.h"
|
#include "pc/data_channel_utils.h"
|
||||||
#include "pc/rtp_data_channel.h"
|
|
||||||
#include "pc/sctp_data_channel.h"
|
#include "pc/sctp_data_channel.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/copy_on_write_buffer.h"
|
#include "rtc_base/copy_on_write_buffer.h"
|
||||||
@ -41,8 +40,7 @@ namespace webrtc {
|
|||||||
|
|
||||||
class PeerConnection;
|
class PeerConnection;
|
||||||
|
|
||||||
class DataChannelController : public RtpDataChannelProviderInterface,
|
class DataChannelController : public SctpDataChannelProviderInterface,
|
||||||
public SctpDataChannelProviderInterface,
|
|
||||||
public DataChannelSink {
|
public DataChannelSink {
|
||||||
public:
|
public:
|
||||||
explicit DataChannelController(PeerConnection* pc) : pc_(pc) {}
|
explicit DataChannelController(PeerConnection* pc) : pc_(pc) {}
|
||||||
@ -53,13 +51,11 @@ class DataChannelController : public RtpDataChannelProviderInterface,
|
|||||||
DataChannelController(DataChannelController&&) = delete;
|
DataChannelController(DataChannelController&&) = delete;
|
||||||
DataChannelController& operator=(DataChannelController&& other) = delete;
|
DataChannelController& operator=(DataChannelController&& other) = delete;
|
||||||
|
|
||||||
// Implements RtpDataChannelProviderInterface/
|
// Implements
|
||||||
// SctpDataChannelProviderInterface.
|
// SctpDataChannelProviderInterface.
|
||||||
bool SendData(const cricket::SendDataParams& params,
|
bool SendData(const cricket::SendDataParams& params,
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
const rtc::CopyOnWriteBuffer& payload,
|
||||||
cricket::SendDataResult* result) override;
|
cricket::SendDataResult* result) override;
|
||||||
bool ConnectDataChannel(RtpDataChannel* webrtc_data_channel) override;
|
|
||||||
void DisconnectDataChannel(RtpDataChannel* webrtc_data_channel) override;
|
|
||||||
bool ConnectDataChannel(SctpDataChannel* webrtc_data_channel) override;
|
bool ConnectDataChannel(SctpDataChannel* webrtc_data_channel) override;
|
||||||
void DisconnectDataChannel(SctpDataChannel* webrtc_data_channel) override;
|
void DisconnectDataChannel(SctpDataChannel* webrtc_data_channel) override;
|
||||||
void AddSctpDataStream(int sid) override;
|
void AddSctpDataStream(int sid) override;
|
||||||
@ -104,28 +100,13 @@ class DataChannelController : public RtpDataChannelProviderInterface,
|
|||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
return !sctp_data_channels_.empty();
|
return !sctp_data_channels_.empty();
|
||||||
}
|
}
|
||||||
bool HasRtpDataChannels() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
||||||
return !rtp_data_channels_.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateLocalRtpDataChannels(const cricket::StreamParamsVec& streams);
|
|
||||||
void UpdateRemoteRtpDataChannels(const cricket::StreamParamsVec& streams);
|
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
cricket::DataChannelType data_channel_type() const;
|
cricket::DataChannelType data_channel_type() const;
|
||||||
void set_data_channel_type(cricket::DataChannelType type);
|
void set_data_channel_type(cricket::DataChannelType type);
|
||||||
cricket::RtpDataChannel* rtp_data_channel() const;
|
|
||||||
void set_rtp_data_channel(cricket::RtpDataChannel* channel);
|
|
||||||
DataChannelTransportInterface* data_channel_transport() const;
|
DataChannelTransportInterface* data_channel_transport() const;
|
||||||
void set_data_channel_transport(DataChannelTransportInterface* transport);
|
void set_data_channel_transport(DataChannelTransportInterface* transport);
|
||||||
const std::map<std::string, rtc::scoped_refptr<RtpDataChannel>>*
|
|
||||||
rtp_data_channels() const;
|
|
||||||
|
|
||||||
sigslot::signal1<RtpDataChannel*>& SignalRtpDataChannelCreated() {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
||||||
return SignalRtpDataChannelCreated_;
|
|
||||||
}
|
|
||||||
sigslot::signal1<SctpDataChannel*>& SignalSctpDataChannelCreated() {
|
sigslot::signal1<SctpDataChannel*>& SignalSctpDataChannelCreated() {
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
return SignalSctpDataChannelCreated_;
|
return SignalSctpDataChannelCreated_;
|
||||||
@ -136,10 +117,6 @@ class DataChannelController : public RtpDataChannelProviderInterface,
|
|||||||
void OnSctpDataChannelClosed(SctpDataChannel* channel);
|
void OnSctpDataChannelClosed(SctpDataChannel* channel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rtc::scoped_refptr<RtpDataChannel> InternalCreateRtpDataChannel(
|
|
||||||
const std::string& label,
|
|
||||||
const DataChannelInit* config) /* RTC_RUN_ON(signaling_thread()) */;
|
|
||||||
|
|
||||||
rtc::scoped_refptr<SctpDataChannel> InternalCreateSctpDataChannel(
|
rtc::scoped_refptr<SctpDataChannel> InternalCreateSctpDataChannel(
|
||||||
const std::string& label,
|
const std::string& label,
|
||||||
const InternalDataChannelInit*
|
const InternalDataChannelInit*
|
||||||
@ -155,14 +132,6 @@ class DataChannelController : public RtpDataChannelProviderInterface,
|
|||||||
const InternalDataChannelInit& config)
|
const InternalDataChannelInit& config)
|
||||||
RTC_RUN_ON(signaling_thread());
|
RTC_RUN_ON(signaling_thread());
|
||||||
|
|
||||||
void CreateRemoteRtpDataChannel(const std::string& label,
|
|
||||||
uint32_t remote_ssrc)
|
|
||||||
RTC_RUN_ON(signaling_thread());
|
|
||||||
|
|
||||||
void UpdateClosingRtpDataChannels(
|
|
||||||
const std::vector<std::string>& active_channels,
|
|
||||||
bool is_local_update) RTC_RUN_ON(signaling_thread());
|
|
||||||
|
|
||||||
// Called from SendData when data_channel_transport() is true.
|
// Called from SendData when data_channel_transport() is true.
|
||||||
bool DataChannelSendData(const cricket::SendDataParams& params,
|
bool DataChannelSendData(const cricket::SendDataParams& params,
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
const rtc::CopyOnWriteBuffer& payload,
|
||||||
@ -175,13 +144,7 @@ class DataChannelController : public RtpDataChannelProviderInterface,
|
|||||||
rtc::Thread* network_thread() const;
|
rtc::Thread* network_thread() const;
|
||||||
rtc::Thread* signaling_thread() const;
|
rtc::Thread* signaling_thread() const;
|
||||||
|
|
||||||
// Specifies which kind of data channel is allowed. This is controlled
|
// Specifies whether or not SCTP data channels are allowed.
|
||||||
// by the chrome command-line flag and constraints:
|
|
||||||
// 1. If chrome command-line switch 'enable-sctp-data-channels' is enabled,
|
|
||||||
// constraint kEnableDtlsSrtp is true, and constaint kEnableRtpDataChannels is
|
|
||||||
// not set or false, SCTP is allowed (DCT_SCTP);
|
|
||||||
// 2. If constraint kEnableRtpDataChannels is true, RTP is allowed (DCT_RTP);
|
|
||||||
// 3. If both 1&2 are false, data channel is not allowed (DCT_NONE).
|
|
||||||
cricket::DataChannelType data_channel_type_ =
|
cricket::DataChannelType data_channel_type_ =
|
||||||
cricket::DCT_NONE; // TODO(bugs.webrtc.org/9987): Accessed on both
|
cricket::DCT_NONE; // TODO(bugs.webrtc.org/9987): Accessed on both
|
||||||
// signaling and network thread.
|
// signaling and network thread.
|
||||||
@ -197,22 +160,12 @@ class DataChannelController : public RtpDataChannelProviderInterface,
|
|||||||
bool data_channel_transport_ready_to_send_
|
bool data_channel_transport_ready_to_send_
|
||||||
RTC_GUARDED_BY(signaling_thread()) = false;
|
RTC_GUARDED_BY(signaling_thread()) = false;
|
||||||
|
|
||||||
// |rtp_data_channel_| is used if in RTP data channel mode,
|
|
||||||
// |data_channel_transport_| when using SCTP.
|
|
||||||
// TODO(bugs.webrtc.org/9987): Accessed on both signaling and network
|
|
||||||
// thread.
|
|
||||||
cricket::RtpDataChannel* rtp_data_channel_ = nullptr;
|
|
||||||
|
|
||||||
SctpSidAllocator sid_allocator_ /* RTC_GUARDED_BY(signaling_thread()) */;
|
SctpSidAllocator sid_allocator_ /* RTC_GUARDED_BY(signaling_thread()) */;
|
||||||
std::vector<rtc::scoped_refptr<SctpDataChannel>> sctp_data_channels_
|
std::vector<rtc::scoped_refptr<SctpDataChannel>> sctp_data_channels_
|
||||||
RTC_GUARDED_BY(signaling_thread());
|
RTC_GUARDED_BY(signaling_thread());
|
||||||
std::vector<rtc::scoped_refptr<SctpDataChannel>> sctp_data_channels_to_free_
|
std::vector<rtc::scoped_refptr<SctpDataChannel>> sctp_data_channels_to_free_
|
||||||
RTC_GUARDED_BY(signaling_thread());
|
RTC_GUARDED_BY(signaling_thread());
|
||||||
|
|
||||||
// Map of label -> DataChannel
|
|
||||||
std::map<std::string, rtc::scoped_refptr<RtpDataChannel>> rtp_data_channels_
|
|
||||||
RTC_GUARDED_BY(signaling_thread());
|
|
||||||
|
|
||||||
// Signals from |data_channel_transport_|. These are invoked on the
|
// Signals from |data_channel_transport_|. These are invoked on the
|
||||||
// signaling thread.
|
// signaling thread.
|
||||||
// TODO(bugs.webrtc.org/11547): These '_s' signals likely all belong on the
|
// TODO(bugs.webrtc.org/11547): These '_s' signals likely all belong on the
|
||||||
@ -228,8 +181,6 @@ class DataChannelController : public RtpDataChannelProviderInterface,
|
|||||||
sigslot::signal1<int> SignalDataChannelTransportChannelClosed_s
|
sigslot::signal1<int> SignalDataChannelTransportChannelClosed_s
|
||||||
RTC_GUARDED_BY(signaling_thread());
|
RTC_GUARDED_BY(signaling_thread());
|
||||||
|
|
||||||
sigslot::signal1<RtpDataChannel*> SignalRtpDataChannelCreated_
|
|
||||||
RTC_GUARDED_BY(signaling_thread());
|
|
||||||
sigslot::signal1<SctpDataChannel*> SignalSctpDataChannelCreated_
|
sigslot::signal1<SctpDataChannel*> SignalSctpDataChannelCreated_
|
||||||
RTC_GUARDED_BY(signaling_thread());
|
RTC_GUARDED_BY(signaling_thread());
|
||||||
|
|
||||||
|
|||||||
@ -553,11 +553,10 @@ TEST_F(DataChannelIntegrationTestUnifiedPlan,
|
|||||||
callee()->AddAudioVideoTracks();
|
callee()->AddAudioVideoTracks();
|
||||||
caller()->CreateAndSetAndSignalOffer();
|
caller()->CreateAndSetAndSignalOffer();
|
||||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||||
network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
|
ASSERT_TRUE_WAIT(caller()->pc()->GetSctpTransport(), kDefaultTimeout);
|
||||||
ASSERT_EQ_WAIT(SctpTransportState::kConnected,
|
ASSERT_EQ_WAIT(SctpTransportState::kConnected,
|
||||||
caller()->pc()->GetSctpTransport()->Information().state(),
|
caller()->pc()->GetSctpTransport()->Information().state(),
|
||||||
kDefaultTimeout);
|
kDefaultTimeout);
|
||||||
});
|
|
||||||
ASSERT_TRUE_WAIT(callee()->data_channel(), kDefaultTimeout);
|
ASSERT_TRUE_WAIT(callee()->data_channel(), kDefaultTimeout);
|
||||||
ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
|
ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -287,8 +287,7 @@ TEST_F(SctpDataChannelTest, OpenMessageSent) {
|
|||||||
SetChannelReady();
|
SetChannelReady();
|
||||||
EXPECT_GE(webrtc_data_channel_->id(), 0);
|
EXPECT_GE(webrtc_data_channel_->id(), 0);
|
||||||
EXPECT_EQ(cricket::DMT_CONTROL, provider_->last_send_data_params().type);
|
EXPECT_EQ(cricket::DMT_CONTROL, provider_->last_send_data_params().type);
|
||||||
EXPECT_EQ(provider_->last_send_data_params().ssrc,
|
EXPECT_EQ(provider_->last_send_data_params().sid, webrtc_data_channel_->id());
|
||||||
static_cast<uint32_t>(webrtc_data_channel_->id()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SctpDataChannelTest, QueuedOpenMessageSent) {
|
TEST_F(SctpDataChannelTest, QueuedOpenMessageSent) {
|
||||||
@ -297,8 +296,7 @@ TEST_F(SctpDataChannelTest, QueuedOpenMessageSent) {
|
|||||||
provider_->set_send_blocked(false);
|
provider_->set_send_blocked(false);
|
||||||
|
|
||||||
EXPECT_EQ(cricket::DMT_CONTROL, provider_->last_send_data_params().type);
|
EXPECT_EQ(cricket::DMT_CONTROL, provider_->last_send_data_params().type);
|
||||||
EXPECT_EQ(provider_->last_send_data_params().ssrc,
|
EXPECT_EQ(provider_->last_send_data_params().sid, webrtc_data_channel_->id());
|
||||||
static_cast<uint32_t>(webrtc_data_channel_->id()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that the DataChannel created after transport gets ready can enter OPEN
|
// Tests that the DataChannel created after transport gets ready can enter OPEN
|
||||||
@ -334,7 +332,7 @@ TEST_F(SctpDataChannelTest, SendUnorderedAfterReceivesOpenAck) {
|
|||||||
|
|
||||||
// Emulates receiving an OPEN_ACK message.
|
// Emulates receiving an OPEN_ACK message.
|
||||||
cricket::ReceiveDataParams params;
|
cricket::ReceiveDataParams params;
|
||||||
params.ssrc = init.id;
|
params.sid = init.id;
|
||||||
params.type = cricket::DMT_CONTROL;
|
params.type = cricket::DMT_CONTROL;
|
||||||
rtc::CopyOnWriteBuffer payload;
|
rtc::CopyOnWriteBuffer payload;
|
||||||
webrtc::WriteDataChannelOpenAckMessage(&payload);
|
webrtc::WriteDataChannelOpenAckMessage(&payload);
|
||||||
@ -360,7 +358,7 @@ TEST_F(SctpDataChannelTest, SendUnorderedAfterReceiveData) {
|
|||||||
|
|
||||||
// Emulates receiving a DATA message.
|
// Emulates receiving a DATA message.
|
||||||
cricket::ReceiveDataParams params;
|
cricket::ReceiveDataParams params;
|
||||||
params.ssrc = init.id;
|
params.sid = init.id;
|
||||||
params.type = cricket::DMT_TEXT;
|
params.type = cricket::DMT_TEXT;
|
||||||
webrtc::DataBuffer buffer("data");
|
webrtc::DataBuffer buffer("data");
|
||||||
dc->OnDataReceived(params, buffer.data);
|
dc->OnDataReceived(params, buffer.data);
|
||||||
@ -406,39 +404,39 @@ TEST_F(SctpDataChannelTest, QueuedCloseFlushes) {
|
|||||||
EXPECT_EQ(cricket::DMT_TEXT, provider_->last_send_data_params().type);
|
EXPECT_EQ(cricket::DMT_TEXT, provider_->last_send_data_params().type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that messages are sent with the right ssrc.
|
// Tests that messages are sent with the right id.
|
||||||
TEST_F(SctpDataChannelTest, SendDataSsrc) {
|
TEST_F(SctpDataChannelTest, SendDataId) {
|
||||||
webrtc_data_channel_->SetSctpSid(1);
|
webrtc_data_channel_->SetSctpSid(1);
|
||||||
SetChannelReady();
|
SetChannelReady();
|
||||||
webrtc::DataBuffer buffer("data");
|
webrtc::DataBuffer buffer("data");
|
||||||
EXPECT_TRUE(webrtc_data_channel_->Send(buffer));
|
EXPECT_TRUE(webrtc_data_channel_->Send(buffer));
|
||||||
EXPECT_EQ(1U, provider_->last_send_data_params().ssrc);
|
EXPECT_EQ(1, provider_->last_send_data_params().sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that the incoming messages with wrong ssrcs are rejected.
|
// Tests that the incoming messages with wrong ids are rejected.
|
||||||
TEST_F(SctpDataChannelTest, ReceiveDataWithInvalidSsrc) {
|
TEST_F(SctpDataChannelTest, ReceiveDataWithInvalidId) {
|
||||||
webrtc_data_channel_->SetSctpSid(1);
|
webrtc_data_channel_->SetSctpSid(1);
|
||||||
SetChannelReady();
|
SetChannelReady();
|
||||||
|
|
||||||
AddObserver();
|
AddObserver();
|
||||||
|
|
||||||
cricket::ReceiveDataParams params;
|
cricket::ReceiveDataParams params;
|
||||||
params.ssrc = 0;
|
params.sid = 0;
|
||||||
webrtc::DataBuffer buffer("abcd");
|
webrtc::DataBuffer buffer("abcd");
|
||||||
webrtc_data_channel_->OnDataReceived(params, buffer.data);
|
webrtc_data_channel_->OnDataReceived(params, buffer.data);
|
||||||
|
|
||||||
EXPECT_EQ(0U, observer_->messages_received());
|
EXPECT_EQ(0U, observer_->messages_received());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that the incoming messages with right ssrcs are acceted.
|
// Tests that the incoming messages with right ids are accepted.
|
||||||
TEST_F(SctpDataChannelTest, ReceiveDataWithValidSsrc) {
|
TEST_F(SctpDataChannelTest, ReceiveDataWithValidId) {
|
||||||
webrtc_data_channel_->SetSctpSid(1);
|
webrtc_data_channel_->SetSctpSid(1);
|
||||||
SetChannelReady();
|
SetChannelReady();
|
||||||
|
|
||||||
AddObserver();
|
AddObserver();
|
||||||
|
|
||||||
cricket::ReceiveDataParams params;
|
cricket::ReceiveDataParams params;
|
||||||
params.ssrc = 1;
|
params.sid = 1;
|
||||||
webrtc::DataBuffer buffer("abcd");
|
webrtc::DataBuffer buffer("abcd");
|
||||||
|
|
||||||
webrtc_data_channel_->OnDataReceived(params, buffer.data);
|
webrtc_data_channel_->OnDataReceived(params, buffer.data);
|
||||||
@ -459,7 +457,7 @@ TEST_F(SctpDataChannelTest, NoMsgSentIfNegotiatedAndNotFromOpenMsg) {
|
|||||||
rtc::Thread::Current(), rtc::Thread::Current());
|
rtc::Thread::Current(), rtc::Thread::Current());
|
||||||
|
|
||||||
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
|
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
|
||||||
EXPECT_EQ(0U, provider_->last_send_data_params().ssrc);
|
EXPECT_EQ(0, provider_->last_send_data_params().sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that DataChannel::messages_received() and DataChannel::bytes_received()
|
// Tests that DataChannel::messages_received() and DataChannel::bytes_received()
|
||||||
@ -477,7 +475,7 @@ TEST_F(SctpDataChannelTest, VerifyMessagesAndBytesReceived) {
|
|||||||
|
|
||||||
webrtc_data_channel_->SetSctpSid(1);
|
webrtc_data_channel_->SetSctpSid(1);
|
||||||
cricket::ReceiveDataParams params;
|
cricket::ReceiveDataParams params;
|
||||||
params.ssrc = 1;
|
params.sid = 1;
|
||||||
|
|
||||||
// Default values.
|
// Default values.
|
||||||
EXPECT_EQ(0U, webrtc_data_channel_->messages_received());
|
EXPECT_EQ(0U, webrtc_data_channel_->messages_received());
|
||||||
@ -524,8 +522,7 @@ TEST_F(SctpDataChannelTest, OpenAckSentIfCreatedFromOpenMessage) {
|
|||||||
|
|
||||||
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
|
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
|
||||||
|
|
||||||
EXPECT_EQ(static_cast<unsigned int>(config.id),
|
EXPECT_EQ(config.id, provider_->last_send_data_params().sid);
|
||||||
provider_->last_send_data_params().ssrc);
|
|
||||||
EXPECT_EQ(cricket::DMT_CONTROL, provider_->last_send_data_params().type);
|
EXPECT_EQ(cricket::DMT_CONTROL, provider_->last_send_data_params().type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,7 +581,7 @@ TEST_F(SctpDataChannelTest, ClosedWhenReceivedBufferFull) {
|
|||||||
memset(buffer.MutableData(), 0, buffer.size());
|
memset(buffer.MutableData(), 0, buffer.size());
|
||||||
|
|
||||||
cricket::ReceiveDataParams params;
|
cricket::ReceiveDataParams params;
|
||||||
params.ssrc = 0;
|
params.sid = 0;
|
||||||
|
|
||||||
// Receiving data without having an observer will overflow the buffer.
|
// Receiving data without having an observer will overflow the buffer.
|
||||||
for (size_t i = 0; i < 16 * 1024 + 1; ++i) {
|
for (size_t i = 0; i < 16 * 1024 + 1; ++i) {
|
||||||
|
|||||||
@ -1380,14 +1380,6 @@ void MediaDescriptionOptions::AddVideoSender(
|
|||||||
num_sim_layers);
|
num_sim_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaDescriptionOptions::AddRtpDataChannel(const std::string& track_id,
|
|
||||||
const std::string& stream_id) {
|
|
||||||
RTC_DCHECK(type == MEDIA_TYPE_DATA);
|
|
||||||
// TODO(steveanton): Is it the case that RtpDataChannel will never have more
|
|
||||||
// than one stream?
|
|
||||||
AddSenderInternal(track_id, {stream_id}, {}, SimulcastLayerList(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaDescriptionOptions::AddSenderInternal(
|
void MediaDescriptionOptions::AddSenderInternal(
|
||||||
const std::string& track_id,
|
const std::string& track_id,
|
||||||
const std::vector<std::string>& stream_ids,
|
const std::vector<std::string>& stream_ids,
|
||||||
@ -1428,7 +1420,6 @@ MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
|
|||||||
channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
|
channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
|
||||||
channel_manager->GetSupportedVideoSendCodecs(&video_send_codecs_);
|
channel_manager->GetSupportedVideoSendCodecs(&video_send_codecs_);
|
||||||
channel_manager->GetSupportedVideoReceiveCodecs(&video_recv_codecs_);
|
channel_manager->GetSupportedVideoReceiveCodecs(&video_recv_codecs_);
|
||||||
channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
|
|
||||||
ComputeAudioCodecsIntersectionAndUnion();
|
ComputeAudioCodecsIntersectionAndUnion();
|
||||||
ComputeVideoCodecsIntersectionAndUnion();
|
ComputeVideoCodecsIntersectionAndUnion();
|
||||||
}
|
}
|
||||||
@ -1521,12 +1512,8 @@ std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
|
|||||||
|
|
||||||
AudioCodecs offer_audio_codecs;
|
AudioCodecs offer_audio_codecs;
|
||||||
VideoCodecs offer_video_codecs;
|
VideoCodecs offer_video_codecs;
|
||||||
RtpDataCodecs offer_rtp_data_codecs;
|
GetCodecsForOffer(current_active_contents, &offer_audio_codecs,
|
||||||
GetCodecsForOffer(
|
&offer_video_codecs);
|
||||||
current_active_contents, &offer_audio_codecs, &offer_video_codecs,
|
|
||||||
session_options.data_channel_type == DataChannelType::DCT_SCTP
|
|
||||||
? nullptr
|
|
||||||
: &offer_rtp_data_codecs);
|
|
||||||
if (!session_options.vad_enabled) {
|
if (!session_options.vad_enabled) {
|
||||||
// If application doesn't want CN codecs in offer.
|
// If application doesn't want CN codecs in offer.
|
||||||
StripCNCodecs(&offer_audio_codecs);
|
StripCNCodecs(&offer_audio_codecs);
|
||||||
@ -1574,8 +1561,8 @@ std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
|
|||||||
case MEDIA_TYPE_DATA:
|
case MEDIA_TYPE_DATA:
|
||||||
if (!AddDataContentForOffer(media_description_options, session_options,
|
if (!AddDataContentForOffer(media_description_options, session_options,
|
||||||
current_content, current_description,
|
current_content, current_description,
|
||||||
offer_rtp_data_codecs, ¤t_streams,
|
¤t_streams, offer.get(),
|
||||||
offer.get(), &ice_credentials)) {
|
&ice_credentials)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1673,9 +1660,8 @@ MediaSessionDescriptionFactory::CreateAnswer(
|
|||||||
// sections.
|
// sections.
|
||||||
AudioCodecs answer_audio_codecs;
|
AudioCodecs answer_audio_codecs;
|
||||||
VideoCodecs answer_video_codecs;
|
VideoCodecs answer_video_codecs;
|
||||||
RtpDataCodecs answer_rtp_data_codecs;
|
|
||||||
GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
|
GetCodecsForAnswer(current_active_contents, *offer, &answer_audio_codecs,
|
||||||
&answer_video_codecs, &answer_rtp_data_codecs);
|
&answer_video_codecs);
|
||||||
|
|
||||||
if (!session_options.vad_enabled) {
|
if (!session_options.vad_enabled) {
|
||||||
// If application doesn't want CN codecs in answer.
|
// If application doesn't want CN codecs in answer.
|
||||||
@ -1732,11 +1718,11 @@ MediaSessionDescriptionFactory::CreateAnswer(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MEDIA_TYPE_DATA:
|
case MEDIA_TYPE_DATA:
|
||||||
if (!AddDataContentForAnswer(
|
if (!AddDataContentForAnswer(media_description_options, session_options,
|
||||||
media_description_options, session_options, offer_content,
|
offer_content, offer, current_content,
|
||||||
offer, current_content, current_description,
|
current_description,
|
||||||
bundle_transport.get(), answer_rtp_data_codecs,
|
bundle_transport.get(), ¤t_streams,
|
||||||
¤t_streams, answer.get(), &ice_credentials)) {
|
answer.get(), &ice_credentials)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1899,7 +1885,6 @@ void MergeCodecsFromDescription(
|
|||||||
const std::vector<const ContentInfo*>& current_active_contents,
|
const std::vector<const ContentInfo*>& current_active_contents,
|
||||||
AudioCodecs* audio_codecs,
|
AudioCodecs* audio_codecs,
|
||||||
VideoCodecs* video_codecs,
|
VideoCodecs* video_codecs,
|
||||||
RtpDataCodecs* rtp_data_codecs,
|
|
||||||
UsedPayloadTypes* used_pltypes) {
|
UsedPayloadTypes* used_pltypes) {
|
||||||
for (const ContentInfo* content : current_active_contents) {
|
for (const ContentInfo* content : current_active_contents) {
|
||||||
if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
|
if (IsMediaContentOfType(content, MEDIA_TYPE_AUDIO)) {
|
||||||
@ -1910,14 +1895,6 @@ void MergeCodecsFromDescription(
|
|||||||
const VideoContentDescription* video =
|
const VideoContentDescription* video =
|
||||||
content->media_description()->as_video();
|
content->media_description()->as_video();
|
||||||
MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
|
MergeCodecs<VideoCodec>(video->codecs(), video_codecs, used_pltypes);
|
||||||
} else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
|
|
||||||
const RtpDataContentDescription* data =
|
|
||||||
content->media_description()->as_rtp_data();
|
|
||||||
if (data) {
|
|
||||||
// Only relevant for RTP datachannels
|
|
||||||
MergeCodecs<RtpDataCodec>(data->codecs(), rtp_data_codecs,
|
|
||||||
used_pltypes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1931,22 +1908,17 @@ void MergeCodecsFromDescription(
|
|||||||
void MediaSessionDescriptionFactory::GetCodecsForOffer(
|
void MediaSessionDescriptionFactory::GetCodecsForOffer(
|
||||||
const std::vector<const ContentInfo*>& current_active_contents,
|
const std::vector<const ContentInfo*>& current_active_contents,
|
||||||
AudioCodecs* audio_codecs,
|
AudioCodecs* audio_codecs,
|
||||||
VideoCodecs* video_codecs,
|
VideoCodecs* video_codecs) const {
|
||||||
RtpDataCodecs* rtp_data_codecs) const {
|
|
||||||
// First - get all codecs from the current description if the media type
|
// First - get all codecs from the current description if the media type
|
||||||
// is used. Add them to |used_pltypes| so the payload type is not reused if a
|
// is used. Add them to |used_pltypes| so the payload type is not reused if a
|
||||||
// new media type is added.
|
// new media type is added.
|
||||||
UsedPayloadTypes used_pltypes;
|
UsedPayloadTypes used_pltypes;
|
||||||
MergeCodecsFromDescription(current_active_contents, audio_codecs,
|
MergeCodecsFromDescription(current_active_contents, audio_codecs,
|
||||||
video_codecs, rtp_data_codecs, &used_pltypes);
|
video_codecs, &used_pltypes);
|
||||||
|
|
||||||
// Add our codecs that are not in the current description.
|
// Add our codecs that are not in the current description.
|
||||||
MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
|
MergeCodecs<AudioCodec>(all_audio_codecs_, audio_codecs, &used_pltypes);
|
||||||
MergeCodecs<VideoCodec>(all_video_codecs_, video_codecs, &used_pltypes);
|
MergeCodecs<VideoCodec>(all_video_codecs_, video_codecs, &used_pltypes);
|
||||||
// Only allocate a payload type for rtp datachannels when using rtp data
|
|
||||||
// channels.
|
|
||||||
if (rtp_data_codecs)
|
|
||||||
MergeCodecs<DataCodec>(rtp_data_codecs_, rtp_data_codecs, &used_pltypes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting codecs for an answer involves these steps:
|
// Getting codecs for an answer involves these steps:
|
||||||
@ -1960,19 +1932,17 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer(
|
|||||||
const std::vector<const ContentInfo*>& current_active_contents,
|
const std::vector<const ContentInfo*>& current_active_contents,
|
||||||
const SessionDescription& remote_offer,
|
const SessionDescription& remote_offer,
|
||||||
AudioCodecs* audio_codecs,
|
AudioCodecs* audio_codecs,
|
||||||
VideoCodecs* video_codecs,
|
VideoCodecs* video_codecs) const {
|
||||||
RtpDataCodecs* rtp_data_codecs) const {
|
|
||||||
// First - get all codecs from the current description if the media type
|
// First - get all codecs from the current description if the media type
|
||||||
// is used. Add them to |used_pltypes| so the payload type is not reused if a
|
// is used. Add them to |used_pltypes| so the payload type is not reused if a
|
||||||
// new media type is added.
|
// new media type is added.
|
||||||
UsedPayloadTypes used_pltypes;
|
UsedPayloadTypes used_pltypes;
|
||||||
MergeCodecsFromDescription(current_active_contents, audio_codecs,
|
MergeCodecsFromDescription(current_active_contents, audio_codecs,
|
||||||
video_codecs, rtp_data_codecs, &used_pltypes);
|
video_codecs, &used_pltypes);
|
||||||
|
|
||||||
// Second - filter out codecs that we don't support at all and should ignore.
|
// Second - filter out codecs that we don't support at all and should ignore.
|
||||||
AudioCodecs filtered_offered_audio_codecs;
|
AudioCodecs filtered_offered_audio_codecs;
|
||||||
VideoCodecs filtered_offered_video_codecs;
|
VideoCodecs filtered_offered_video_codecs;
|
||||||
RtpDataCodecs filtered_offered_rtp_data_codecs;
|
|
||||||
for (const ContentInfo& content : remote_offer.contents()) {
|
for (const ContentInfo& content : remote_offer.contents()) {
|
||||||
if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
|
if (IsMediaContentOfType(&content, MEDIA_TYPE_AUDIO)) {
|
||||||
const AudioContentDescription* audio =
|
const AudioContentDescription* audio =
|
||||||
@ -1998,22 +1968,6 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer(
|
|||||||
filtered_offered_video_codecs.push_back(offered_video_codec);
|
filtered_offered_video_codecs.push_back(offered_video_codec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
|
|
||||||
const RtpDataContentDescription* data =
|
|
||||||
content.media_description()->as_rtp_data();
|
|
||||||
if (data) {
|
|
||||||
// RTP data. This part is inactive for SCTP data.
|
|
||||||
for (const RtpDataCodec& offered_rtp_data_codec : data->codecs()) {
|
|
||||||
if (!FindMatchingCodec<RtpDataCodec>(
|
|
||||||
data->codecs(), filtered_offered_rtp_data_codecs,
|
|
||||||
offered_rtp_data_codec, nullptr) &&
|
|
||||||
FindMatchingCodec<RtpDataCodec>(data->codecs(), rtp_data_codecs_,
|
|
||||||
offered_rtp_data_codec,
|
|
||||||
nullptr)) {
|
|
||||||
filtered_offered_rtp_data_codecs.push_back(offered_rtp_data_codec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2023,8 +1977,6 @@ void MediaSessionDescriptionFactory::GetCodecsForAnswer(
|
|||||||
&used_pltypes);
|
&used_pltypes);
|
||||||
MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
|
MergeCodecs<VideoCodec>(filtered_offered_video_codecs, video_codecs,
|
||||||
&used_pltypes);
|
&used_pltypes);
|
||||||
MergeCodecs<DataCodec>(filtered_offered_rtp_data_codecs, rtp_data_codecs,
|
|
||||||
&used_pltypes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaSessionDescriptionFactory::AudioVideoRtpHeaderExtensions
|
MediaSessionDescriptionFactory::AudioVideoRtpHeaderExtensions
|
||||||
@ -2333,7 +2285,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
|
bool MediaSessionDescriptionFactory::AddDataContentForOffer(
|
||||||
const MediaDescriptionOptions& media_description_options,
|
const MediaDescriptionOptions& media_description_options,
|
||||||
const MediaSessionOptions& session_options,
|
const MediaSessionOptions& session_options,
|
||||||
const ContentInfo* current_content,
|
const ContentInfo* current_content,
|
||||||
@ -2378,73 +2330,6 @@ bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
|
|
||||||
const MediaDescriptionOptions& media_description_options,
|
|
||||||
const MediaSessionOptions& session_options,
|
|
||||||
const ContentInfo* current_content,
|
|
||||||
const SessionDescription* current_description,
|
|
||||||
const RtpDataCodecs& rtp_data_codecs,
|
|
||||||
StreamParamsVec* current_streams,
|
|
||||||
SessionDescription* desc,
|
|
||||||
IceCredentialsIterator* ice_credentials) const {
|
|
||||||
auto data = std::make_unique<RtpDataContentDescription>();
|
|
||||||
bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
|
|
||||||
|
|
||||||
cricket::SecurePolicy sdes_policy =
|
|
||||||
IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
|
|
||||||
: secure();
|
|
||||||
std::vector<std::string> crypto_suites;
|
|
||||||
GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
|
|
||||||
&crypto_suites);
|
|
||||||
if (!CreateMediaContentOffer(media_description_options, session_options,
|
|
||||||
rtp_data_codecs, sdes_policy,
|
|
||||||
GetCryptos(current_content), crypto_suites,
|
|
||||||
RtpHeaderExtensions(), ssrc_generator_,
|
|
||||||
current_streams, data.get())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->set_bandwidth(kRtpDataMaxBandwidth);
|
|
||||||
SetMediaProtocol(secure_transport, data.get());
|
|
||||||
desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
|
|
||||||
media_description_options.stopped, std::move(data));
|
|
||||||
if (!AddTransportOffer(media_description_options.mid,
|
|
||||||
media_description_options.transport_options,
|
|
||||||
current_description, desc, ice_credentials)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MediaSessionDescriptionFactory::AddDataContentForOffer(
|
|
||||||
const MediaDescriptionOptions& media_description_options,
|
|
||||||
const MediaSessionOptions& session_options,
|
|
||||||
const ContentInfo* current_content,
|
|
||||||
const SessionDescription* current_description,
|
|
||||||
const RtpDataCodecs& rtp_data_codecs,
|
|
||||||
StreamParamsVec* current_streams,
|
|
||||||
SessionDescription* desc,
|
|
||||||
IceCredentialsIterator* ice_credentials) const {
|
|
||||||
bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
|
|
||||||
// If the DataChannel type is not specified, use the DataChannel type in
|
|
||||||
// the current description.
|
|
||||||
if (session_options.data_channel_type == DCT_NONE && current_content) {
|
|
||||||
RTC_CHECK(IsMediaContentOfType(current_content, MEDIA_TYPE_DATA));
|
|
||||||
is_sctp = (current_content->media_description()->protocol() ==
|
|
||||||
kMediaProtocolSctp);
|
|
||||||
}
|
|
||||||
if (is_sctp) {
|
|
||||||
return AddSctpDataContentForOffer(
|
|
||||||
media_description_options, session_options, current_content,
|
|
||||||
current_description, current_streams, desc, ice_credentials);
|
|
||||||
} else {
|
|
||||||
return AddRtpDataContentForOffer(media_description_options, session_options,
|
|
||||||
current_content, current_description,
|
|
||||||
rtp_data_codecs, current_streams, desc,
|
|
||||||
ice_credentials);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MediaSessionDescriptionFactory::AddUnsupportedContentForOffer(
|
bool MediaSessionDescriptionFactory::AddUnsupportedContentForOffer(
|
||||||
const MediaDescriptionOptions& media_description_options,
|
const MediaDescriptionOptions& media_description_options,
|
||||||
const MediaSessionOptions& session_options,
|
const MediaSessionOptions& session_options,
|
||||||
@ -2718,7 +2603,6 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
|
|||||||
const ContentInfo* current_content,
|
const ContentInfo* current_content,
|
||||||
const SessionDescription* current_description,
|
const SessionDescription* current_description,
|
||||||
const TransportInfo* bundle_transport,
|
const TransportInfo* bundle_transport,
|
||||||
const RtpDataCodecs& rtp_data_codecs,
|
|
||||||
StreamParamsVec* current_streams,
|
StreamParamsVec* current_streams,
|
||||||
SessionDescription* answer,
|
SessionDescription* answer,
|
||||||
IceCredentialsIterator* ice_credentials) const {
|
IceCredentialsIterator* ice_credentials) const {
|
||||||
@ -2766,25 +2650,7 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
|
|||||||
bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
|
bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
|
||||||
data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
|
data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
|
||||||
} else {
|
} else {
|
||||||
// RTP offer
|
RTC_NOTREACHED() << "Non-SCTP data content found";
|
||||||
data_answer = std::make_unique<RtpDataContentDescription>();
|
|
||||||
|
|
||||||
const RtpDataContentDescription* offer_data_description =
|
|
||||||
offer_content->media_description()->as_rtp_data();
|
|
||||||
RTC_CHECK(offer_data_description);
|
|
||||||
if (!SetCodecsInAnswer(offer_data_description, rtp_data_codecs,
|
|
||||||
media_description_options, session_options,
|
|
||||||
ssrc_generator_, current_streams,
|
|
||||||
data_answer->as_rtp_data())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!CreateMediaContentAnswer(
|
|
||||||
offer_data_description, media_description_options, session_options,
|
|
||||||
sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
|
|
||||||
ssrc_generator_, enable_encrypted_rtp_header_extensions_,
|
|
||||||
current_streams, bundle_enabled, data_answer.get())) {
|
|
||||||
return false; // Fails the session setup.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool secure = bundle_transport ? bundle_transport->description.secure()
|
bool secure = bundle_transport ? bundle_transport->description.secure()
|
||||||
@ -2800,13 +2666,6 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rejected && session_options.data_channel_type == DCT_RTP) {
|
|
||||||
data_answer->set_bandwidth(kRtpDataMaxBandwidth);
|
|
||||||
} else {
|
|
||||||
// RFC 3264
|
|
||||||
// The answer MUST contain the same number of m-lines as the offer.
|
|
||||||
RTC_LOG(LS_INFO) << "Data is not supported in the answer.";
|
|
||||||
}
|
|
||||||
answer->AddContent(media_description_options.mid, offer_content->type,
|
answer->AddContent(media_description_options.mid, offer_content->type,
|
||||||
rejected, std::move(data_answer));
|
rejected, std::move(data_answer));
|
||||||
return true;
|
return true;
|
||||||
@ -2991,12 +2850,6 @@ const VideoContentDescription* GetFirstVideoContentDescription(
|
|||||||
return desc ? desc->as_video() : nullptr;
|
return desc ? desc->as_video() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RtpDataContentDescription* GetFirstRtpDataContentDescription(
|
|
||||||
const SessionDescription* sdesc) {
|
|
||||||
auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
|
|
||||||
return desc ? desc->as_rtp_data() : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SctpDataContentDescription* GetFirstSctpDataContentDescription(
|
const SctpDataContentDescription* GetFirstSctpDataContentDescription(
|
||||||
const SessionDescription* sdesc) {
|
const SessionDescription* sdesc) {
|
||||||
auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
|
auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
|
||||||
@ -3069,12 +2922,6 @@ VideoContentDescription* GetFirstVideoContentDescription(
|
|||||||
return desc ? desc->as_video() : nullptr;
|
return desc ? desc->as_video() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
RtpDataContentDescription* GetFirstRtpDataContentDescription(
|
|
||||||
SessionDescription* sdesc) {
|
|
||||||
auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
|
|
||||||
return desc ? desc->as_rtp_data() : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SctpDataContentDescription* GetFirstSctpDataContentDescription(
|
SctpDataContentDescription* GetFirstSctpDataContentDescription(
|
||||||
SessionDescription* sdesc) {
|
SessionDescription* sdesc) {
|
||||||
auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
|
auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
|
||||||
|
|||||||
@ -73,10 +73,6 @@ struct MediaDescriptionOptions {
|
|||||||
const SimulcastLayerList& simulcast_layers,
|
const SimulcastLayerList& simulcast_layers,
|
||||||
int num_sim_layers);
|
int num_sim_layers);
|
||||||
|
|
||||||
// Internally just uses sender_options.
|
|
||||||
void AddRtpDataChannel(const std::string& track_id,
|
|
||||||
const std::string& stream_id);
|
|
||||||
|
|
||||||
MediaType type;
|
MediaType type;
|
||||||
std::string mid;
|
std::string mid;
|
||||||
webrtc::RtpTransceiverDirection direction;
|
webrtc::RtpTransceiverDirection direction;
|
||||||
@ -162,10 +158,6 @@ class MediaSessionDescriptionFactory {
|
|||||||
const VideoCodecs& recv_codecs);
|
const VideoCodecs& recv_codecs);
|
||||||
RtpHeaderExtensions filtered_rtp_header_extensions(
|
RtpHeaderExtensions filtered_rtp_header_extensions(
|
||||||
RtpHeaderExtensions extensions) const;
|
RtpHeaderExtensions extensions) const;
|
||||||
const RtpDataCodecs& rtp_data_codecs() const { return rtp_data_codecs_; }
|
|
||||||
void set_rtp_data_codecs(const RtpDataCodecs& codecs) {
|
|
||||||
rtp_data_codecs_ = codecs;
|
|
||||||
}
|
|
||||||
SecurePolicy secure() const { return secure_; }
|
SecurePolicy secure() const { return secure_; }
|
||||||
void set_secure(SecurePolicy s) { secure_ = s; }
|
void set_secure(SecurePolicy s) { secure_ = s; }
|
||||||
|
|
||||||
@ -204,14 +196,12 @@ class MediaSessionDescriptionFactory {
|
|||||||
void GetCodecsForOffer(
|
void GetCodecsForOffer(
|
||||||
const std::vector<const ContentInfo*>& current_active_contents,
|
const std::vector<const ContentInfo*>& current_active_contents,
|
||||||
AudioCodecs* audio_codecs,
|
AudioCodecs* audio_codecs,
|
||||||
VideoCodecs* video_codecs,
|
VideoCodecs* video_codecs) const;
|
||||||
RtpDataCodecs* rtp_data_codecs) const;
|
|
||||||
void GetCodecsForAnswer(
|
void GetCodecsForAnswer(
|
||||||
const std::vector<const ContentInfo*>& current_active_contents,
|
const std::vector<const ContentInfo*>& current_active_contents,
|
||||||
const SessionDescription& remote_offer,
|
const SessionDescription& remote_offer,
|
||||||
AudioCodecs* audio_codecs,
|
AudioCodecs* audio_codecs,
|
||||||
VideoCodecs* video_codecs,
|
VideoCodecs* video_codecs) const;
|
||||||
RtpDataCodecs* rtp_data_codecs) const;
|
|
||||||
AudioVideoRtpHeaderExtensions GetOfferedRtpHeaderExtensionsWithIds(
|
AudioVideoRtpHeaderExtensions GetOfferedRtpHeaderExtensionsWithIds(
|
||||||
const std::vector<const ContentInfo*>& current_active_contents,
|
const std::vector<const ContentInfo*>& current_active_contents,
|
||||||
bool extmap_allow_mixed,
|
bool extmap_allow_mixed,
|
||||||
@ -261,32 +251,11 @@ class MediaSessionDescriptionFactory {
|
|||||||
SessionDescription* desc,
|
SessionDescription* desc,
|
||||||
IceCredentialsIterator* ice_credentials) const;
|
IceCredentialsIterator* ice_credentials) const;
|
||||||
|
|
||||||
bool AddSctpDataContentForOffer(
|
|
||||||
const MediaDescriptionOptions& media_description_options,
|
|
||||||
const MediaSessionOptions& session_options,
|
|
||||||
const ContentInfo* current_content,
|
|
||||||
const SessionDescription* current_description,
|
|
||||||
StreamParamsVec* current_streams,
|
|
||||||
SessionDescription* desc,
|
|
||||||
IceCredentialsIterator* ice_credentials) const;
|
|
||||||
bool AddRtpDataContentForOffer(
|
|
||||||
const MediaDescriptionOptions& media_description_options,
|
|
||||||
const MediaSessionOptions& session_options,
|
|
||||||
const ContentInfo* current_content,
|
|
||||||
const SessionDescription* current_description,
|
|
||||||
const RtpDataCodecs& rtp_data_codecs,
|
|
||||||
StreamParamsVec* current_streams,
|
|
||||||
SessionDescription* desc,
|
|
||||||
IceCredentialsIterator* ice_credentials) const;
|
|
||||||
// This function calls either AddRtpDataContentForOffer or
|
|
||||||
// AddSctpDataContentForOffer depending on protocol.
|
|
||||||
// The codecs argument is ignored for SCTP.
|
|
||||||
bool AddDataContentForOffer(
|
bool AddDataContentForOffer(
|
||||||
const MediaDescriptionOptions& media_description_options,
|
const MediaDescriptionOptions& media_description_options,
|
||||||
const MediaSessionOptions& session_options,
|
const MediaSessionOptions& session_options,
|
||||||
const ContentInfo* current_content,
|
const ContentInfo* current_content,
|
||||||
const SessionDescription* current_description,
|
const SessionDescription* current_description,
|
||||||
const RtpDataCodecs& rtp_data_codecs,
|
|
||||||
StreamParamsVec* current_streams,
|
StreamParamsVec* current_streams,
|
||||||
SessionDescription* desc,
|
SessionDescription* desc,
|
||||||
IceCredentialsIterator* ice_credentials) const;
|
IceCredentialsIterator* ice_credentials) const;
|
||||||
@ -335,7 +304,6 @@ class MediaSessionDescriptionFactory {
|
|||||||
const ContentInfo* current_content,
|
const ContentInfo* current_content,
|
||||||
const SessionDescription* current_description,
|
const SessionDescription* current_description,
|
||||||
const TransportInfo* bundle_transport,
|
const TransportInfo* bundle_transport,
|
||||||
const RtpDataCodecs& rtp_data_codecs,
|
|
||||||
StreamParamsVec* current_streams,
|
StreamParamsVec* current_streams,
|
||||||
SessionDescription* answer,
|
SessionDescription* answer,
|
||||||
IceCredentialsIterator* ice_credentials) const;
|
IceCredentialsIterator* ice_credentials) const;
|
||||||
@ -368,7 +336,6 @@ class MediaSessionDescriptionFactory {
|
|||||||
VideoCodecs video_sendrecv_codecs_;
|
VideoCodecs video_sendrecv_codecs_;
|
||||||
// Union of send and recv.
|
// Union of send and recv.
|
||||||
VideoCodecs all_video_codecs_;
|
VideoCodecs all_video_codecs_;
|
||||||
RtpDataCodecs rtp_data_codecs_;
|
|
||||||
// This object is not owned by the channel so it must outlive it.
|
// This object is not owned by the channel so it must outlive it.
|
||||||
rtc::UniqueRandomIdGenerator* const ssrc_generator_;
|
rtc::UniqueRandomIdGenerator* const ssrc_generator_;
|
||||||
bool enable_encrypted_rtp_header_extensions_ = false;
|
bool enable_encrypted_rtp_header_extensions_ = false;
|
||||||
@ -398,8 +365,6 @@ const AudioContentDescription* GetFirstAudioContentDescription(
|
|||||||
const SessionDescription* sdesc);
|
const SessionDescription* sdesc);
|
||||||
const VideoContentDescription* GetFirstVideoContentDescription(
|
const VideoContentDescription* GetFirstVideoContentDescription(
|
||||||
const SessionDescription* sdesc);
|
const SessionDescription* sdesc);
|
||||||
const RtpDataContentDescription* GetFirstRtpDataContentDescription(
|
|
||||||
const SessionDescription* sdesc);
|
|
||||||
const SctpDataContentDescription* GetFirstSctpDataContentDescription(
|
const SctpDataContentDescription* GetFirstSctpDataContentDescription(
|
||||||
const SessionDescription* sdesc);
|
const SessionDescription* sdesc);
|
||||||
// Non-const versions of the above functions.
|
// Non-const versions of the above functions.
|
||||||
@ -417,8 +382,6 @@ AudioContentDescription* GetFirstAudioContentDescription(
|
|||||||
SessionDescription* sdesc);
|
SessionDescription* sdesc);
|
||||||
VideoContentDescription* GetFirstVideoContentDescription(
|
VideoContentDescription* GetFirstVideoContentDescription(
|
||||||
SessionDescription* sdesc);
|
SessionDescription* sdesc);
|
||||||
RtpDataContentDescription* GetFirstRtpDataContentDescription(
|
|
||||||
SessionDescription* sdesc);
|
|
||||||
SctpDataContentDescription* GetFirstSctpDataContentDescription(
|
SctpDataContentDescription* GetFirstSctpDataContentDescription(
|
||||||
SessionDescription* sdesc);
|
SessionDescription* sdesc);
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,6 @@ using cricket::CryptoParamsVec;
|
|||||||
using cricket::GetFirstAudioContent;
|
using cricket::GetFirstAudioContent;
|
||||||
using cricket::GetFirstAudioContentDescription;
|
using cricket::GetFirstAudioContentDescription;
|
||||||
using cricket::GetFirstDataContent;
|
using cricket::GetFirstDataContent;
|
||||||
using cricket::GetFirstRtpDataContentDescription;
|
|
||||||
using cricket::GetFirstVideoContent;
|
using cricket::GetFirstVideoContent;
|
||||||
using cricket::GetFirstVideoContentDescription;
|
using cricket::GetFirstVideoContentDescription;
|
||||||
using cricket::kAutoBandwidth;
|
using cricket::kAutoBandwidth;
|
||||||
@ -65,8 +64,6 @@ using cricket::MediaSessionOptions;
|
|||||||
using cricket::MediaType;
|
using cricket::MediaType;
|
||||||
using cricket::RidDescription;
|
using cricket::RidDescription;
|
||||||
using cricket::RidDirection;
|
using cricket::RidDirection;
|
||||||
using cricket::RtpDataCodec;
|
|
||||||
using cricket::RtpDataContentDescription;
|
|
||||||
using cricket::SctpDataContentDescription;
|
using cricket::SctpDataContentDescription;
|
||||||
using cricket::SEC_DISABLED;
|
using cricket::SEC_DISABLED;
|
||||||
using cricket::SEC_ENABLED;
|
using cricket::SEC_ENABLED;
|
||||||
@ -133,15 +130,6 @@ static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
|
|||||||
|
|
||||||
static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
|
static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
|
||||||
|
|
||||||
static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
|
|
||||||
RtpDataCodec(99, "utf8-text")};
|
|
||||||
|
|
||||||
static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
|
|
||||||
RtpDataCodec(127, "utf8-text")};
|
|
||||||
|
|
||||||
static const RtpDataCodec kDataCodecsAnswer[] = {
|
|
||||||
RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
|
|
||||||
|
|
||||||
static const RtpExtension kAudioRtpExtension1[] = {
|
static const RtpExtension kAudioRtpExtension1[] = {
|
||||||
RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
|
RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
|
||||||
RtpExtension("http://google.com/testing/audio_something", 10),
|
RtpExtension("http://google.com/testing/audio_something", 10),
|
||||||
@ -260,9 +248,6 @@ static const char kVideoTrack2[] = "video_2";
|
|||||||
static const char kAudioTrack1[] = "audio_1";
|
static const char kAudioTrack1[] = "audio_1";
|
||||||
static const char kAudioTrack2[] = "audio_2";
|
static const char kAudioTrack2[] = "audio_2";
|
||||||
static const char kAudioTrack3[] = "audio_3";
|
static const char kAudioTrack3[] = "audio_3";
|
||||||
static const char kDataTrack1[] = "data_1";
|
|
||||||
static const char kDataTrack2[] = "data_2";
|
|
||||||
static const char kDataTrack3[] = "data_3";
|
|
||||||
|
|
||||||
static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
|
static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
|
||||||
"RTP/SAVPF"};
|
"RTP/SAVPF"};
|
||||||
@ -369,10 +354,6 @@ static void AttachSenderToMediaDescriptionOptions(
|
|||||||
it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
|
it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
|
||||||
num_sim_layer);
|
num_sim_layer);
|
||||||
break;
|
break;
|
||||||
case MEDIA_TYPE_DATA:
|
|
||||||
RTC_CHECK(stream_ids.size() == 1U);
|
|
||||||
it->AddRtpDataChannel(track_id, stream_ids[0]);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
RTC_NOTREACHED();
|
RTC_NOTREACHED();
|
||||||
}
|
}
|
||||||
@ -437,12 +418,10 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test {
|
|||||||
MAKE_VECTOR(kAudioCodecs1));
|
MAKE_VECTOR(kAudioCodecs1));
|
||||||
f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
|
f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
|
||||||
MAKE_VECTOR(kVideoCodecs1));
|
MAKE_VECTOR(kVideoCodecs1));
|
||||||
f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
|
|
||||||
f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
|
f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
|
||||||
MAKE_VECTOR(kAudioCodecs2));
|
MAKE_VECTOR(kAudioCodecs2));
|
||||||
f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
|
f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
|
||||||
MAKE_VECTOR(kVideoCodecs2));
|
MAKE_VECTOR(kVideoCodecs2));
|
||||||
f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
|
|
||||||
tdf1_.set_certificate(rtc::RTCCertificate::Create(
|
tdf1_.set_certificate(rtc::RTCCertificate::Create(
|
||||||
std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
|
std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
|
||||||
tdf2_.set_certificate(rtc::RTCCertificate::Create(
|
tdf2_.set_certificate(rtc::RTCCertificate::Create(
|
||||||
@ -604,8 +583,6 @@ class MediaSessionDescriptionFactoryTest : public ::testing::Test {
|
|||||||
f1_.set_secure(SEC_ENABLED);
|
f1_.set_secure(SEC_ENABLED);
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
std::unique_ptr<SessionDescription> ref_desc;
|
std::unique_ptr<SessionDescription> ref_desc;
|
||||||
std::unique_ptr<SessionDescription> desc;
|
std::unique_ptr<SessionDescription> desc;
|
||||||
if (offer) {
|
if (offer) {
|
||||||
@ -862,30 +839,21 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
|
|||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
|
TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
|
||||||
const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
|
const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
|
||||||
const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
|
const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
|
||||||
const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
|
|
||||||
ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
|
ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
|
||||||
ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
|
|
||||||
|
|
||||||
MediaSessionOptions opts;
|
MediaSessionOptions opts;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
|
|
||||||
opts.bundle_enabled = true;
|
opts.bundle_enabled = true;
|
||||||
std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
|
std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
|
||||||
const VideoContentDescription* vcd =
|
const VideoContentDescription* vcd =
|
||||||
GetFirstVideoContentDescription(offer.get());
|
GetFirstVideoContentDescription(offer.get());
|
||||||
const AudioContentDescription* acd =
|
const AudioContentDescription* acd =
|
||||||
GetFirstAudioContentDescription(offer.get());
|
GetFirstAudioContentDescription(offer.get());
|
||||||
const RtpDataContentDescription* dcd =
|
|
||||||
GetFirstRtpDataContentDescription(offer.get());
|
|
||||||
ASSERT_TRUE(NULL != vcd);
|
ASSERT_TRUE(NULL != vcd);
|
||||||
ASSERT_TRUE(NULL != acd);
|
ASSERT_TRUE(NULL != acd);
|
||||||
ASSERT_TRUE(NULL != dcd);
|
|
||||||
EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
|
EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
|
||||||
EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
|
|
||||||
EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
|
|
||||||
EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
|
EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
|
||||||
EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
|
EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
|
||||||
EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test creating an updated offer with bundle, audio, video and data
|
// Test creating an updated offer with bundle, audio, video and data
|
||||||
@ -909,8 +877,6 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
|
|
||||||
MediaSessionOptions updated_opts;
|
MediaSessionOptions updated_opts;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&updated_opts);
|
|
||||||
updated_opts.bundle_enabled = true;
|
updated_opts.bundle_enabled = true;
|
||||||
std::unique_ptr<SessionDescription> updated_offer(
|
std::unique_ptr<SessionDescription> updated_offer(
|
||||||
f1_.CreateOffer(updated_opts, answer.get()));
|
f1_.CreateOffer(updated_opts, answer.get()));
|
||||||
@ -919,51 +885,13 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
GetFirstAudioContentDescription(updated_offer.get());
|
GetFirstAudioContentDescription(updated_offer.get());
|
||||||
const VideoContentDescription* vcd =
|
const VideoContentDescription* vcd =
|
||||||
GetFirstVideoContentDescription(updated_offer.get());
|
GetFirstVideoContentDescription(updated_offer.get());
|
||||||
const RtpDataContentDescription* dcd =
|
|
||||||
GetFirstRtpDataContentDescription(updated_offer.get());
|
|
||||||
EXPECT_TRUE(NULL != vcd);
|
EXPECT_TRUE(NULL != vcd);
|
||||||
EXPECT_TRUE(NULL != acd);
|
EXPECT_TRUE(NULL != acd);
|
||||||
EXPECT_TRUE(NULL != dcd);
|
|
||||||
|
|
||||||
ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
|
ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
|
||||||
EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
|
EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
|
||||||
ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
|
ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
|
||||||
EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
|
EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
|
||||||
ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a RTP data offer, and ensure it matches what we expect.
|
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
|
|
||||||
MediaSessionOptions opts;
|
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
|
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
|
|
||||||
f1_.set_secure(SEC_ENABLED);
|
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
|
||||||
ASSERT_TRUE(offer.get() != NULL);
|
|
||||||
const ContentInfo* ac = offer->GetContentByName("audio");
|
|
||||||
const ContentInfo* dc = offer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
|
|
||||||
EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
|
|
||||||
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
|
||||||
const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
|
|
||||||
EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
|
|
||||||
EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
|
|
||||||
EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
|
|
||||||
EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
|
|
||||||
ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
|
|
||||||
EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
|
|
||||||
EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
|
|
||||||
EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
|
|
||||||
dcd->bandwidth()); // default bandwidth (auto)
|
|
||||||
EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
|
|
||||||
ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an SCTP data offer with bundle without error.
|
// Create an SCTP data offer with bundle without error.
|
||||||
@ -1350,74 +1278,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
|
|||||||
TestVideoGcmCipher(false, true);
|
TestVideoGcmCipher(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
|
|
||||||
MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
|
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
|
|
||||||
f1_.set_secure(SEC_ENABLED);
|
|
||||||
f2_.set_secure(SEC_ENABLED);
|
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
|
||||||
ASSERT_TRUE(offer.get() != NULL);
|
|
||||||
std::unique_ptr<SessionDescription> answer =
|
|
||||||
f2_.CreateAnswer(offer.get(), opts, NULL);
|
|
||||||
const ContentInfo* ac = answer->GetContentByName("audio");
|
|
||||||
const ContentInfo* dc = answer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
|
|
||||||
EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
|
|
||||||
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
|
||||||
const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
|
|
||||||
EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
|
|
||||||
EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
|
|
||||||
EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
|
|
||||||
EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
|
|
||||||
ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
|
|
||||||
EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
|
|
||||||
EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
|
|
||||||
EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
|
|
||||||
ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
|
|
||||||
MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
|
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
|
|
||||||
opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
|
|
||||||
f1_.set_secure(SEC_ENABLED);
|
|
||||||
f2_.set_secure(SEC_ENABLED);
|
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
|
||||||
ASSERT_TRUE(offer.get() != NULL);
|
|
||||||
for (cricket::ContentInfo& content : offer->contents()) {
|
|
||||||
auto cryptos = content.media_description()->cryptos();
|
|
||||||
PreferGcmCryptoParameters(&cryptos);
|
|
||||||
content.media_description()->set_cryptos(cryptos);
|
|
||||||
}
|
|
||||||
std::unique_ptr<SessionDescription> answer =
|
|
||||||
f2_.CreateAnswer(offer.get(), opts, NULL);
|
|
||||||
const ContentInfo* ac = answer->GetContentByName("audio");
|
|
||||||
const ContentInfo* dc = answer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
|
|
||||||
EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
|
|
||||||
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
|
||||||
const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
|
|
||||||
EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
|
|
||||||
EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
|
|
||||||
EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
|
|
||||||
EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
|
|
||||||
ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
|
|
||||||
EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
|
|
||||||
EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
|
|
||||||
EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
|
|
||||||
ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
|
|
||||||
EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
|
|
||||||
}
|
|
||||||
|
|
||||||
// The use_sctpmap flag should be set in an Sctp DataContentDescription by
|
// The use_sctpmap flag should be set in an Sctp DataContentDescription by
|
||||||
// default. The answer's use_sctpmap flag should match the offer's.
|
// default. The answer's use_sctpmap flag should match the offer's.
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
|
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
|
||||||
@ -1621,35 +1481,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
|
|||||||
RtpTransceiverDirection::kInactive);
|
RtpTransceiverDirection::kInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that a data content with an unknown protocol is rejected in an answer.
|
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest,
|
|
||||||
CreateDataAnswerToOfferWithUnknownProtocol) {
|
|
||||||
MediaSessionOptions opts;
|
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
|
|
||||||
f1_.set_secure(SEC_ENABLED);
|
|
||||||
f2_.set_secure(SEC_ENABLED);
|
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
|
||||||
ContentInfo* dc_offer = offer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(dc_offer != NULL);
|
|
||||||
RtpDataContentDescription* dcd_offer =
|
|
||||||
dc_offer->media_description()->as_rtp_data();
|
|
||||||
ASSERT_TRUE(dcd_offer != NULL);
|
|
||||||
// Offer must be acceptable as an RTP protocol in order to be set.
|
|
||||||
std::string protocol = "RTP/a weird unknown protocol";
|
|
||||||
dcd_offer->set_protocol(protocol);
|
|
||||||
|
|
||||||
std::unique_ptr<SessionDescription> answer =
|
|
||||||
f2_.CreateAnswer(offer.get(), opts, NULL);
|
|
||||||
|
|
||||||
const ContentInfo* dc_answer = answer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(dc_answer != NULL);
|
|
||||||
EXPECT_TRUE(dc_answer->rejected);
|
|
||||||
const RtpDataContentDescription* dcd_answer =
|
|
||||||
dc_answer->media_description()->as_rtp_data();
|
|
||||||
ASSERT_TRUE(dcd_answer != NULL);
|
|
||||||
EXPECT_EQ(protocol, dcd_answer->protocol());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
|
// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
|
TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
|
||||||
MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
|
MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
|
||||||
@ -2169,36 +2000,28 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
TestCreateAnswerWithoutLegacyStreams) {
|
TestCreateAnswerWithoutLegacyStreams) {
|
||||||
MediaSessionOptions opts;
|
MediaSessionOptions opts;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
|
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
||||||
ASSERT_TRUE(offer.get() != NULL);
|
ASSERT_TRUE(offer.get() != NULL);
|
||||||
std::unique_ptr<SessionDescription> answer =
|
std::unique_ptr<SessionDescription> answer =
|
||||||
f2_.CreateAnswer(offer.get(), opts, NULL);
|
f2_.CreateAnswer(offer.get(), opts, NULL);
|
||||||
const ContentInfo* ac = answer->GetContentByName("audio");
|
const ContentInfo* ac = answer->GetContentByName("audio");
|
||||||
const ContentInfo* vc = answer->GetContentByName("video");
|
const ContentInfo* vc = answer->GetContentByName("video");
|
||||||
const ContentInfo* dc = answer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
ASSERT_TRUE(ac != NULL);
|
||||||
ASSERT_TRUE(vc != NULL);
|
ASSERT_TRUE(vc != NULL);
|
||||||
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
||||||
const VideoContentDescription* vcd = vc->media_description()->as_video();
|
const VideoContentDescription* vcd = vc->media_description()->as_video();
|
||||||
const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
|
|
||||||
|
|
||||||
EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
|
EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
|
||||||
EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
|
EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
|
||||||
EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a typical video answer, and ensure it matches what we expect.
|
// Create a typical video answer, and ensure it matches what we expect.
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
|
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
|
||||||
MediaSessionOptions offer_opts;
|
MediaSessionOptions offer_opts;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
|
AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
|
|
||||||
&offer_opts);
|
|
||||||
|
|
||||||
MediaSessionOptions answer_opts;
|
MediaSessionOptions answer_opts;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
|
AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
|
|
||||||
&answer_opts);
|
|
||||||
|
|
||||||
std::unique_ptr<SessionDescription> offer;
|
std::unique_ptr<SessionDescription> offer;
|
||||||
std::unique_ptr<SessionDescription> answer;
|
std::unique_ptr<SessionDescription> answer;
|
||||||
@ -2209,16 +2032,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
|
|||||||
answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
||||||
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
|
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
|
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
|
|
||||||
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
|
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
|
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
|
|
||||||
EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
|
EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
|
||||||
EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
|
EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
|
||||||
EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
|
|
||||||
EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
|
EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
|
||||||
EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
|
EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
|
||||||
EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
|
|
||||||
|
|
||||||
offer_opts.rtcp_mux_enabled = true;
|
offer_opts.rtcp_mux_enabled = true;
|
||||||
answer_opts.rtcp_mux_enabled = false;
|
answer_opts.rtcp_mux_enabled = false;
|
||||||
@ -2226,16 +2045,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
|
|||||||
answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
||||||
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
|
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
|
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
|
|
||||||
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
|
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
|
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
|
|
||||||
EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
|
EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
|
||||||
EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
|
EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
|
||||||
EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
|
|
||||||
EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
|
|
||||||
|
|
||||||
offer_opts.rtcp_mux_enabled = false;
|
offer_opts.rtcp_mux_enabled = false;
|
||||||
answer_opts.rtcp_mux_enabled = true;
|
answer_opts.rtcp_mux_enabled = true;
|
||||||
@ -2243,16 +2058,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
|
|||||||
answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
||||||
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
|
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
|
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
|
|
||||||
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
|
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
|
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
|
|
||||||
EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
|
|
||||||
EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
|
|
||||||
|
|
||||||
offer_opts.rtcp_mux_enabled = false;
|
offer_opts.rtcp_mux_enabled = false;
|
||||||
answer_opts.rtcp_mux_enabled = false;
|
answer_opts.rtcp_mux_enabled = false;
|
||||||
@ -2260,16 +2071,12 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
|
|||||||
answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
||||||
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
|
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
|
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
|
|
||||||
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
|
ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
|
ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
|
||||||
ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
|
|
||||||
EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
|
|
||||||
EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
|
EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
|
||||||
EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an audio-only answer to a video offer.
|
// Create an audio-only answer to a video offer.
|
||||||
@ -2295,55 +2102,27 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
|
|||||||
EXPECT_TRUE(vc->rejected);
|
EXPECT_TRUE(vc->rejected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an audio-only answer to an offer with data.
|
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
|
|
||||||
MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
|
|
||||||
opts.data_channel_type = cricket::DCT_RTP;
|
|
||||||
AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
|
|
||||||
RtpTransceiverDirection::kRecvOnly, kActive,
|
|
||||||
&opts);
|
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
|
||||||
ASSERT_TRUE(offer.get() != NULL);
|
|
||||||
|
|
||||||
opts.media_description_options[1].stopped = true;
|
|
||||||
std::unique_ptr<SessionDescription> answer =
|
|
||||||
f2_.CreateAnswer(offer.get(), opts, NULL);
|
|
||||||
const ContentInfo* ac = answer->GetContentByName("audio");
|
|
||||||
const ContentInfo* dc = answer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
ASSERT_TRUE(dc->media_description() != NULL);
|
|
||||||
EXPECT_TRUE(dc->rejected);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an answer that rejects the contents which are rejected in the offer.
|
// Create an answer that rejects the contents which are rejected in the offer.
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest,
|
TEST_F(MediaSessionDescriptionFactoryTest,
|
||||||
CreateAnswerToOfferWithRejectedMedia) {
|
CreateAnswerToOfferWithRejectedMedia) {
|
||||||
MediaSessionOptions opts;
|
MediaSessionOptions opts;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
|
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
||||||
ASSERT_TRUE(offer.get() != NULL);
|
ASSERT_TRUE(offer.get() != NULL);
|
||||||
ContentInfo* ac = offer->GetContentByName("audio");
|
ContentInfo* ac = offer->GetContentByName("audio");
|
||||||
ContentInfo* vc = offer->GetContentByName("video");
|
ContentInfo* vc = offer->GetContentByName("video");
|
||||||
ContentInfo* dc = offer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
ASSERT_TRUE(ac != NULL);
|
||||||
ASSERT_TRUE(vc != NULL);
|
ASSERT_TRUE(vc != NULL);
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
ac->rejected = true;
|
ac->rejected = true;
|
||||||
vc->rejected = true;
|
vc->rejected = true;
|
||||||
dc->rejected = true;
|
|
||||||
std::unique_ptr<SessionDescription> answer =
|
std::unique_ptr<SessionDescription> answer =
|
||||||
f2_.CreateAnswer(offer.get(), opts, NULL);
|
f2_.CreateAnswer(offer.get(), opts, NULL);
|
||||||
ac = answer->GetContentByName("audio");
|
ac = answer->GetContentByName("audio");
|
||||||
vc = answer->GetContentByName("video");
|
vc = answer->GetContentByName("video");
|
||||||
dc = answer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
ASSERT_TRUE(ac != NULL);
|
||||||
ASSERT_TRUE(vc != NULL);
|
ASSERT_TRUE(vc != NULL);
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
EXPECT_TRUE(ac->rejected);
|
EXPECT_TRUE(ac->rejected);
|
||||||
EXPECT_TRUE(vc->rejected);
|
EXPECT_TRUE(vc->rejected);
|
||||||
EXPECT_TRUE(dc->rejected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest,
|
TEST_F(MediaSessionDescriptionFactoryTest,
|
||||||
@ -2458,7 +2237,6 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
// Create an audio and video offer with:
|
// Create an audio and video offer with:
|
||||||
// - one video track
|
// - one video track
|
||||||
// - two audio tracks
|
// - two audio tracks
|
||||||
// - two data tracks
|
|
||||||
// and ensure it matches what we expect. Also updates the initial offer by
|
// and ensure it matches what we expect. Also updates the initial offer by
|
||||||
// adding a new video track and replaces one of the audio tracks.
|
// adding a new video track and replaces one of the audio tracks.
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
|
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
|
||||||
@ -2471,25 +2249,16 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
|
|||||||
AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
|
AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
|
||||||
{kMediaStream1}, 1, &opts);
|
{kMediaStream1}, 1, &opts);
|
||||||
|
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
|
|
||||||
AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
|
|
||||||
{kMediaStream1}, 1, &opts);
|
|
||||||
AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
|
|
||||||
{kMediaStream1}, 1, &opts);
|
|
||||||
|
|
||||||
f1_.set_secure(SEC_ENABLED);
|
f1_.set_secure(SEC_ENABLED);
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
|
||||||
|
|
||||||
ASSERT_TRUE(offer.get() != NULL);
|
ASSERT_TRUE(offer.get() != NULL);
|
||||||
const ContentInfo* ac = offer->GetContentByName("audio");
|
const ContentInfo* ac = offer->GetContentByName("audio");
|
||||||
const ContentInfo* vc = offer->GetContentByName("video");
|
const ContentInfo* vc = offer->GetContentByName("video");
|
||||||
const ContentInfo* dc = offer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
ASSERT_TRUE(ac != NULL);
|
||||||
ASSERT_TRUE(vc != NULL);
|
ASSERT_TRUE(vc != NULL);
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
||||||
const VideoContentDescription* vcd = vc->media_description()->as_video();
|
const VideoContentDescription* vcd = vc->media_description()->as_video();
|
||||||
const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
|
EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
|
||||||
EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
|
EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
|
||||||
|
|
||||||
@ -2518,25 +2287,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
|
|||||||
EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
|
EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
|
||||||
EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
|
EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
|
||||||
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
|
|
||||||
EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
|
|
||||||
ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
|
|
||||||
const StreamParamsVec& data_streams = dcd->streams();
|
|
||||||
ASSERT_EQ(2U, data_streams.size());
|
|
||||||
EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
|
|
||||||
EXPECT_EQ(kDataTrack1, data_streams[0].id);
|
|
||||||
ASSERT_EQ(1U, data_streams[0].ssrcs.size());
|
|
||||||
EXPECT_NE(0U, data_streams[0].ssrcs[0]);
|
|
||||||
EXPECT_EQ(kDataTrack2, data_streams[1].id);
|
|
||||||
ASSERT_EQ(1U, data_streams[1].ssrcs.size());
|
|
||||||
EXPECT_NE(0U, data_streams[1].ssrcs[0]);
|
|
||||||
|
|
||||||
EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
|
|
||||||
dcd->bandwidth()); // default bandwidth (auto)
|
|
||||||
EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
|
|
||||||
ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
|
|
||||||
// Update the offer. Add a new video track that is not synched to the
|
// Update the offer. Add a new video track that is not synched to the
|
||||||
// other tracks and replace audio track 2 with audio track 3.
|
// other tracks and replace audio track 2 with audio track 3.
|
||||||
AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
|
AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
|
||||||
@ -2544,38 +2294,27 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
|
|||||||
DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
|
DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
|
||||||
AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
|
AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
|
||||||
{kMediaStream1}, 1, &opts);
|
{kMediaStream1}, 1, &opts);
|
||||||
DetachSenderFromMediaSection("data", kDataTrack2, &opts);
|
|
||||||
AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
|
|
||||||
{kMediaStream1}, 1, &opts);
|
|
||||||
std::unique_ptr<SessionDescription> updated_offer(
|
std::unique_ptr<SessionDescription> updated_offer(
|
||||||
f1_.CreateOffer(opts, offer.get()));
|
f1_.CreateOffer(opts, offer.get()));
|
||||||
|
|
||||||
ASSERT_TRUE(updated_offer.get() != NULL);
|
ASSERT_TRUE(updated_offer.get() != NULL);
|
||||||
ac = updated_offer->GetContentByName("audio");
|
ac = updated_offer->GetContentByName("audio");
|
||||||
vc = updated_offer->GetContentByName("video");
|
vc = updated_offer->GetContentByName("video");
|
||||||
dc = updated_offer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
ASSERT_TRUE(ac != NULL);
|
||||||
ASSERT_TRUE(vc != NULL);
|
ASSERT_TRUE(vc != NULL);
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
const AudioContentDescription* updated_acd =
|
const AudioContentDescription* updated_acd =
|
||||||
ac->media_description()->as_audio();
|
ac->media_description()->as_audio();
|
||||||
const VideoContentDescription* updated_vcd =
|
const VideoContentDescription* updated_vcd =
|
||||||
vc->media_description()->as_video();
|
vc->media_description()->as_video();
|
||||||
const RtpDataContentDescription* updated_dcd =
|
|
||||||
dc->media_description()->as_rtp_data();
|
|
||||||
|
|
||||||
EXPECT_EQ(acd->type(), updated_acd->type());
|
EXPECT_EQ(acd->type(), updated_acd->type());
|
||||||
EXPECT_EQ(acd->codecs(), updated_acd->codecs());
|
EXPECT_EQ(acd->codecs(), updated_acd->codecs());
|
||||||
EXPECT_EQ(vcd->type(), updated_vcd->type());
|
EXPECT_EQ(vcd->type(), updated_vcd->type());
|
||||||
EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
|
EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
|
||||||
EXPECT_EQ(dcd->type(), updated_dcd->type());
|
|
||||||
EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
|
|
||||||
ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
|
ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
|
||||||
EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
|
EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
|
||||||
ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
|
ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
|
||||||
EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
|
EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
|
||||||
ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
|
|
||||||
|
|
||||||
const StreamParamsVec& updated_audio_streams = updated_acd->streams();
|
const StreamParamsVec& updated_audio_streams = updated_acd->streams();
|
||||||
ASSERT_EQ(2U, updated_audio_streams.size());
|
ASSERT_EQ(2U, updated_audio_streams.size());
|
||||||
@ -2591,18 +2330,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
|
|||||||
EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
|
EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
|
||||||
// All the media streams in one PeerConnection share one RTCP CNAME.
|
// All the media streams in one PeerConnection share one RTCP CNAME.
|
||||||
EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
|
EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
|
||||||
|
|
||||||
const StreamParamsVec& updated_data_streams = updated_dcd->streams();
|
|
||||||
ASSERT_EQ(2U, updated_data_streams.size());
|
|
||||||
EXPECT_EQ(data_streams[0], updated_data_streams[0]);
|
|
||||||
EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
|
|
||||||
ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
|
|
||||||
EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
|
|
||||||
EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
|
|
||||||
// The stream correctly got the CNAME from the MediaSessionOptions.
|
|
||||||
// The Expected RTCP CNAME is the default one as we are using the default
|
|
||||||
// MediaSessionOptions.
|
|
||||||
EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an offer with simulcast video stream.
|
// Create an offer with simulcast video stream.
|
||||||
@ -2805,10 +2532,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
|
|||||||
AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
|
AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
|
||||||
RtpTransceiverDirection::kRecvOnly, kActive,
|
RtpTransceiverDirection::kRecvOnly, kActive,
|
||||||
&offer_opts);
|
&offer_opts);
|
||||||
offer_opts.data_channel_type = cricket::DCT_RTP;
|
|
||||||
AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
|
|
||||||
RtpTransceiverDirection::kRecvOnly, kActive,
|
|
||||||
&offer_opts);
|
|
||||||
f1_.set_secure(SEC_ENABLED);
|
f1_.set_secure(SEC_ENABLED);
|
||||||
f2_.set_secure(SEC_ENABLED);
|
f2_.set_secure(SEC_ENABLED);
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
|
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
|
||||||
@ -2827,31 +2550,18 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
|
|||||||
AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
|
AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
|
||||||
{kMediaStream1}, 1, &answer_opts);
|
{kMediaStream1}, 1, &answer_opts);
|
||||||
|
|
||||||
AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
|
|
||||||
RtpTransceiverDirection::kSendRecv, kActive,
|
|
||||||
&answer_opts);
|
|
||||||
AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
|
|
||||||
{kMediaStream1}, 1, &answer_opts);
|
|
||||||
AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
|
|
||||||
{kMediaStream1}, 1, &answer_opts);
|
|
||||||
answer_opts.data_channel_type = cricket::DCT_RTP;
|
|
||||||
|
|
||||||
std::unique_ptr<SessionDescription> answer =
|
std::unique_ptr<SessionDescription> answer =
|
||||||
f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
f2_.CreateAnswer(offer.get(), answer_opts, NULL);
|
||||||
|
|
||||||
ASSERT_TRUE(answer.get() != NULL);
|
ASSERT_TRUE(answer.get() != NULL);
|
||||||
const ContentInfo* ac = answer->GetContentByName("audio");
|
const ContentInfo* ac = answer->GetContentByName("audio");
|
||||||
const ContentInfo* vc = answer->GetContentByName("video");
|
const ContentInfo* vc = answer->GetContentByName("video");
|
||||||
const ContentInfo* dc = answer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
ASSERT_TRUE(ac != NULL);
|
||||||
ASSERT_TRUE(vc != NULL);
|
ASSERT_TRUE(vc != NULL);
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
const AudioContentDescription* acd = ac->media_description()->as_audio();
|
||||||
const VideoContentDescription* vcd = vc->media_description()->as_video();
|
const VideoContentDescription* vcd = vc->media_description()->as_video();
|
||||||
const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
|
|
||||||
ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
|
ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
|
||||||
ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
|
ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
|
||||||
ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
|
EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
|
||||||
EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
|
EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
|
||||||
@ -2879,59 +2589,33 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
|
|||||||
EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
|
EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
|
||||||
EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
|
EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
|
||||||
|
|
||||||
EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
|
|
||||||
EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
|
|
||||||
|
|
||||||
const StreamParamsVec& data_streams = dcd->streams();
|
|
||||||
ASSERT_EQ(2U, data_streams.size());
|
|
||||||
EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
|
|
||||||
EXPECT_EQ(kDataTrack1, data_streams[0].id);
|
|
||||||
ASSERT_EQ(1U, data_streams[0].ssrcs.size());
|
|
||||||
EXPECT_NE(0U, data_streams[0].ssrcs[0]);
|
|
||||||
EXPECT_EQ(kDataTrack2, data_streams[1].id);
|
|
||||||
ASSERT_EQ(1U, data_streams[1].ssrcs.size());
|
|
||||||
EXPECT_NE(0U, data_streams[1].ssrcs[0]);
|
|
||||||
|
|
||||||
EXPECT_EQ(cricket::kRtpDataMaxBandwidth,
|
|
||||||
dcd->bandwidth()); // default bandwidth (auto)
|
|
||||||
EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
|
|
||||||
|
|
||||||
// Update the answer. Add a new video track that is not synched to the
|
// Update the answer. Add a new video track that is not synched to the
|
||||||
// other tracks and remove 1 audio track.
|
// other tracks and remove 1 audio track.
|
||||||
AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
|
AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
|
||||||
{kMediaStream2}, 1, &answer_opts);
|
{kMediaStream2}, 1, &answer_opts);
|
||||||
DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
|
DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
|
||||||
DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
|
|
||||||
std::unique_ptr<SessionDescription> updated_answer(
|
std::unique_ptr<SessionDescription> updated_answer(
|
||||||
f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
|
f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
|
||||||
|
|
||||||
ASSERT_TRUE(updated_answer.get() != NULL);
|
ASSERT_TRUE(updated_answer.get() != NULL);
|
||||||
ac = updated_answer->GetContentByName("audio");
|
ac = updated_answer->GetContentByName("audio");
|
||||||
vc = updated_answer->GetContentByName("video");
|
vc = updated_answer->GetContentByName("video");
|
||||||
dc = updated_answer->GetContentByName("data");
|
|
||||||
ASSERT_TRUE(ac != NULL);
|
ASSERT_TRUE(ac != NULL);
|
||||||
ASSERT_TRUE(vc != NULL);
|
ASSERT_TRUE(vc != NULL);
|
||||||
ASSERT_TRUE(dc != NULL);
|
|
||||||
const AudioContentDescription* updated_acd =
|
const AudioContentDescription* updated_acd =
|
||||||
ac->media_description()->as_audio();
|
ac->media_description()->as_audio();
|
||||||
const VideoContentDescription* updated_vcd =
|
const VideoContentDescription* updated_vcd =
|
||||||
vc->media_description()->as_video();
|
vc->media_description()->as_video();
|
||||||
const RtpDataContentDescription* updated_dcd =
|
|
||||||
dc->media_description()->as_rtp_data();
|
|
||||||
|
|
||||||
ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
|
ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
|
||||||
EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
|
EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
|
||||||
ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
|
ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
|
||||||
EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
|
EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
|
||||||
ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
|
|
||||||
EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
|
|
||||||
|
|
||||||
EXPECT_EQ(acd->type(), updated_acd->type());
|
EXPECT_EQ(acd->type(), updated_acd->type());
|
||||||
EXPECT_EQ(acd->codecs(), updated_acd->codecs());
|
EXPECT_EQ(acd->codecs(), updated_acd->codecs());
|
||||||
EXPECT_EQ(vcd->type(), updated_vcd->type());
|
EXPECT_EQ(vcd->type(), updated_vcd->type());
|
||||||
EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
|
EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
|
||||||
EXPECT_EQ(dcd->type(), updated_dcd->type());
|
|
||||||
EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
|
|
||||||
|
|
||||||
const StreamParamsVec& updated_audio_streams = updated_acd->streams();
|
const StreamParamsVec& updated_audio_streams = updated_acd->streams();
|
||||||
ASSERT_EQ(1U, updated_audio_streams.size());
|
ASSERT_EQ(1U, updated_audio_streams.size());
|
||||||
@ -2943,10 +2627,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
|
|||||||
EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
|
EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
|
||||||
// All media streams in one PeerConnection share one CNAME.
|
// All media streams in one PeerConnection share one CNAME.
|
||||||
EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
|
EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
|
||||||
|
|
||||||
const StreamParamsVec& updated_data_streams = updated_dcd->streams();
|
|
||||||
ASSERT_EQ(1U, updated_data_streams.size());
|
|
||||||
EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an updated offer after creating an answer to the original offer and
|
// Create an updated offer after creating an answer to the original offer and
|
||||||
@ -3790,8 +3470,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
|
|||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
|
TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
TestTransportInfo(true, options, false);
|
TestTransportInfo(true, options, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3799,16 +3477,12 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
TestTransportInfoOfferMultimediaCurrent) {
|
TestTransportInfoOfferMultimediaCurrent) {
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
TestTransportInfo(true, options, true);
|
TestTransportInfo(true, options, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
|
TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
options.bundle_enabled = true;
|
options.bundle_enabled = true;
|
||||||
TestTransportInfo(true, options, false);
|
TestTransportInfo(true, options, false);
|
||||||
}
|
}
|
||||||
@ -3817,8 +3491,6 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
TestTransportInfoOfferBundleCurrent) {
|
TestTransportInfoOfferBundleCurrent) {
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
options.bundle_enabled = true;
|
options.bundle_enabled = true;
|
||||||
TestTransportInfo(true, options, true);
|
TestTransportInfo(true, options, true);
|
||||||
}
|
}
|
||||||
@ -3854,8 +3526,6 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
|
TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
TestTransportInfo(false, options, false);
|
TestTransportInfo(false, options, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3863,16 +3533,12 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
TestTransportInfoAnswerMultimediaCurrent) {
|
TestTransportInfoAnswerMultimediaCurrent) {
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
TestTransportInfo(false, options, true);
|
TestTransportInfo(false, options, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
|
TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
options.bundle_enabled = true;
|
options.bundle_enabled = true;
|
||||||
TestTransportInfo(false, options, false);
|
TestTransportInfo(false, options, false);
|
||||||
}
|
}
|
||||||
@ -3881,8 +3547,6 @@ TEST_F(MediaSessionDescriptionFactoryTest,
|
|||||||
TestTransportInfoAnswerBundleCurrent) {
|
TestTransportInfoAnswerBundleCurrent) {
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
options.bundle_enabled = true;
|
options.bundle_enabled = true;
|
||||||
TestTransportInfo(false, options, true);
|
TestTransportInfo(false, options, true);
|
||||||
}
|
}
|
||||||
@ -4072,8 +3736,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
|
|||||||
tdf2_.set_secure(SEC_ENABLED);
|
tdf2_.set_secure(SEC_ENABLED);
|
||||||
MediaSessionOptions options;
|
MediaSessionOptions options;
|
||||||
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
|
||||||
AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
|
|
||||||
&options);
|
|
||||||
|
|
||||||
// Generate an offer with DTLS but without SDES.
|
// Generate an offer with DTLS but without SDES.
|
||||||
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
|
std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
|
||||||
@ -4085,9 +3747,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
|
|||||||
const VideoContentDescription* video_offer =
|
const VideoContentDescription* video_offer =
|
||||||
GetFirstVideoContentDescription(offer.get());
|
GetFirstVideoContentDescription(offer.get());
|
||||||
ASSERT_TRUE(video_offer->cryptos().empty());
|
ASSERT_TRUE(video_offer->cryptos().empty());
|
||||||
const RtpDataContentDescription* data_offer =
|
|
||||||
GetFirstRtpDataContentDescription(offer.get());
|
|
||||||
ASSERT_TRUE(data_offer->cryptos().empty());
|
|
||||||
|
|
||||||
const cricket::TransportDescription* audio_offer_trans_desc =
|
const cricket::TransportDescription* audio_offer_trans_desc =
|
||||||
offer->GetTransportDescriptionByName("audio");
|
offer->GetTransportDescriptionByName("audio");
|
||||||
@ -4095,9 +3754,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
|
|||||||
const cricket::TransportDescription* video_offer_trans_desc =
|
const cricket::TransportDescription* video_offer_trans_desc =
|
||||||
offer->GetTransportDescriptionByName("video");
|
offer->GetTransportDescriptionByName("video");
|
||||||
ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
|
ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
|
||||||
const cricket::TransportDescription* data_offer_trans_desc =
|
|
||||||
offer->GetTransportDescriptionByName("data");
|
|
||||||
ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
|
|
||||||
|
|
||||||
// Generate an answer with DTLS.
|
// Generate an answer with DTLS.
|
||||||
std::unique_ptr<SessionDescription> answer =
|
std::unique_ptr<SessionDescription> answer =
|
||||||
@ -4110,9 +3766,6 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
|
|||||||
const cricket::TransportDescription* video_answer_trans_desc =
|
const cricket::TransportDescription* video_answer_trans_desc =
|
||||||
answer->GetTransportDescriptionByName("video");
|
answer->GetTransportDescriptionByName("video");
|
||||||
EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
|
EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
|
||||||
const cricket::TransportDescription* data_answer_trans_desc =
|
|
||||||
answer->GetTransportDescriptionByName("data");
|
|
||||||
EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies if vad_enabled option is set to false, CN codecs are not present in
|
// Verifies if vad_enabled option is set to false, CN codecs are not present in
|
||||||
@ -4618,12 +4271,10 @@ class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
|
|||||||
MAKE_VECTOR(kAudioCodecs1));
|
MAKE_VECTOR(kAudioCodecs1));
|
||||||
f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
|
f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
|
||||||
MAKE_VECTOR(kVideoCodecs1));
|
MAKE_VECTOR(kVideoCodecs1));
|
||||||
f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
|
|
||||||
f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
|
f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
|
||||||
MAKE_VECTOR(kAudioCodecs2));
|
MAKE_VECTOR(kAudioCodecs2));
|
||||||
f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
|
f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
|
||||||
MAKE_VECTOR(kVideoCodecs2));
|
MAKE_VECTOR(kVideoCodecs2));
|
||||||
f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
|
|
||||||
f1_.set_secure(SEC_ENABLED);
|
f1_.set_secure(SEC_ENABLED);
|
||||||
f2_.set_secure(SEC_ENABLED);
|
f2_.set_secure(SEC_ENABLED);
|
||||||
tdf1_.set_certificate(rtc::RTCCertificate::Create(
|
tdf1_.set_certificate(rtc::RTCCertificate::Create(
|
||||||
|
|||||||
@ -1302,7 +1302,7 @@ rtc::scoped_refptr<DataChannelInterface> PeerConnection::CreateDataChannel(
|
|||||||
|
|
||||||
// Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
|
// Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
|
||||||
// the first SCTP DataChannel.
|
// the first SCTP DataChannel.
|
||||||
if (data_channel_type() == cricket::DCT_RTP || first_datachannel) {
|
if (first_datachannel) {
|
||||||
sdp_handler_->UpdateNegotiationNeeded();
|
sdp_handler_->UpdateNegotiationNeeded();
|
||||||
}
|
}
|
||||||
NoteUsageEvent(UsageEvent::DATA_ADDED);
|
NoteUsageEvent(UsageEvent::DATA_ADDED);
|
||||||
@ -1768,7 +1768,6 @@ void PeerConnection::Close() {
|
|||||||
// TODO(tommi): ^^ That's not exactly optimal since this is yet another
|
// TODO(tommi): ^^ That's not exactly optimal since this is yet another
|
||||||
// blocking hop to the network thread during Close(). Further still, the
|
// blocking hop to the network thread during Close(). Further still, the
|
||||||
// voice/video/data channels will be cleared on the worker thread.
|
// voice/video/data channels will be cleared on the worker thread.
|
||||||
RTC_DCHECK(!data_channel_controller_.rtp_data_channel());
|
|
||||||
transport_controller_.reset();
|
transport_controller_.reset();
|
||||||
port_allocator_->DiscardCandidatePool();
|
port_allocator_->DiscardCandidatePool();
|
||||||
if (network_thread_safety_) {
|
if (network_thread_safety_) {
|
||||||
@ -1945,11 +1944,6 @@ void PeerConnection::OnSelectedCandidatePairChanged(
|
|||||||
absl::optional<std::string> PeerConnection::GetDataMid() const {
|
absl::optional<std::string> PeerConnection::GetDataMid() const {
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
switch (data_channel_type()) {
|
switch (data_channel_type()) {
|
||||||
case cricket::DCT_RTP:
|
|
||||||
if (!data_channel_controller_.rtp_data_channel()) {
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
return data_channel_controller_.rtp_data_channel()->content_name();
|
|
||||||
case cricket::DCT_SCTP:
|
case cricket::DCT_SCTP:
|
||||||
return sctp_mid_s_;
|
return sctp_mid_s_;
|
||||||
default:
|
default:
|
||||||
@ -2106,10 +2100,6 @@ cricket::ChannelInterface* PeerConnection::GetChannel(
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rtp_data_channel() &&
|
|
||||||
rtp_data_channel()->content_name() == content_name) {
|
|
||||||
return rtp_data_channel();
|
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2211,11 +2201,6 @@ std::map<std::string, std::string> PeerConnection::GetTransportNamesByMid()
|
|||||||
channel->transport_name();
|
channel->transport_name();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data_channel_controller_.rtp_data_channel()) {
|
|
||||||
transport_names_by_mid[data_channel_controller_.rtp_data_channel()
|
|
||||||
->content_name()] =
|
|
||||||
data_channel_controller_.rtp_data_channel()->transport_name();
|
|
||||||
}
|
|
||||||
if (sctp_mid_n_) {
|
if (sctp_mid_n_) {
|
||||||
cricket::DtlsTransportInternal* dtls_transport =
|
cricket::DtlsTransportInternal* dtls_transport =
|
||||||
transport_controller_->GetDtlsTransport(*sctp_mid_n_);
|
transport_controller_->GetDtlsTransport(*sctp_mid_n_);
|
||||||
@ -2448,22 +2433,7 @@ bool PeerConnection::SetupDataChannelTransport_n(const std::string& mid) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerConnection::SetupRtpDataChannelTransport_n(
|
|
||||||
cricket::RtpDataChannel* data_channel) {
|
|
||||||
data_channel_controller_.set_rtp_data_channel(data_channel);
|
|
||||||
if (!data_channel)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// TODO(bugs.webrtc.org/9987): OnSentPacket_w needs to be changed to
|
|
||||||
// OnSentPacket_n (and be called on the network thread).
|
|
||||||
data_channel->SignalSentPacket().connect(this,
|
|
||||||
&PeerConnection::OnSentPacket_w);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PeerConnection::TeardownDataChannelTransport_n() {
|
void PeerConnection::TeardownDataChannelTransport_n() {
|
||||||
// Clear the RTP data channel if any.
|
|
||||||
data_channel_controller_.set_rtp_data_channel(nullptr);
|
|
||||||
|
|
||||||
if (sctp_mid_n_) {
|
if (sctp_mid_n_) {
|
||||||
// |sctp_mid_| may still be active through an SCTP transport. If not, unset
|
// |sctp_mid_| may still be active through an SCTP transport. If not, unset
|
||||||
// it.
|
// it.
|
||||||
@ -2707,11 +2677,6 @@ void PeerConnection::ReportTransportStats() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtp_data_channel()) {
|
|
||||||
media_types_by_transport_name[rtp_data_channel()->transport_name()].insert(
|
|
||||||
cricket::MEDIA_TYPE_DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sctp_mid_n_) {
|
if (sctp_mid_n_) {
|
||||||
cricket::DtlsTransportInternal* dtls_transport =
|
cricket::DtlsTransportInternal* dtls_transport =
|
||||||
transport_controller_->GetDtlsTransport(*sctp_mid_n_);
|
transport_controller_->GetDtlsTransport(*sctp_mid_n_);
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
#include "pc/peer_connection_internal.h"
|
#include "pc/peer_connection_internal.h"
|
||||||
#include "pc/peer_connection_message_handler.h"
|
#include "pc/peer_connection_message_handler.h"
|
||||||
#include "pc/rtc_stats_collector.h"
|
#include "pc/rtc_stats_collector.h"
|
||||||
#include "pc/rtp_data_channel.h"
|
|
||||||
#include "pc/rtp_receiver.h"
|
#include "pc/rtp_receiver.h"
|
||||||
#include "pc/rtp_sender.h"
|
#include "pc/rtp_sender.h"
|
||||||
#include "pc/rtp_transceiver.h"
|
#include "pc/rtp_transceiver.h"
|
||||||
@ -287,18 +286,10 @@ class PeerConnection : public PeerConnectionInternal,
|
|||||||
return rtp_manager()->transceivers()->List();
|
return rtp_manager()->transceivers()->List();
|
||||||
}
|
}
|
||||||
|
|
||||||
sigslot::signal1<RtpDataChannel*>& SignalRtpDataChannelCreated() override {
|
|
||||||
return data_channel_controller_.SignalRtpDataChannelCreated();
|
|
||||||
}
|
|
||||||
|
|
||||||
sigslot::signal1<SctpDataChannel*>& SignalSctpDataChannelCreated() override {
|
sigslot::signal1<SctpDataChannel*>& SignalSctpDataChannelCreated() override {
|
||||||
return data_channel_controller_.SignalSctpDataChannelCreated();
|
return data_channel_controller_.SignalSctpDataChannelCreated();
|
||||||
}
|
}
|
||||||
|
|
||||||
cricket::RtpDataChannel* rtp_data_channel() const override {
|
|
||||||
return data_channel_controller_.rtp_data_channel();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<DataChannelStats> GetDataChannelStats() const override;
|
std::vector<DataChannelStats> GetDataChannelStats() const override;
|
||||||
|
|
||||||
absl::optional<std::string> sctp_transport_name() const override;
|
absl::optional<std::string> sctp_transport_name() const override;
|
||||||
@ -404,8 +395,8 @@ class PeerConnection : public PeerConnectionInternal,
|
|||||||
}
|
}
|
||||||
bool ValidateBundleSettings(const cricket::SessionDescription* desc);
|
bool ValidateBundleSettings(const cricket::SessionDescription* desc);
|
||||||
|
|
||||||
// Returns the MID for the data section associated with either the
|
// Returns the MID for the data section associated with the
|
||||||
// RtpDataChannel or SCTP data channel, if it has been set. If no data
|
// SCTP data channel, if it has been set. If no data
|
||||||
// channels are configured this will return nullopt.
|
// channels are configured this will return nullopt.
|
||||||
absl::optional<std::string> GetDataMid() const;
|
absl::optional<std::string> GetDataMid() const;
|
||||||
|
|
||||||
@ -443,8 +434,6 @@ class PeerConnection : public PeerConnectionInternal,
|
|||||||
|
|
||||||
bool SetupDataChannelTransport_n(const std::string& mid)
|
bool SetupDataChannelTransport_n(const std::string& mid)
|
||||||
RTC_RUN_ON(network_thread());
|
RTC_RUN_ON(network_thread());
|
||||||
void SetupRtpDataChannelTransport_n(cricket::RtpDataChannel* data_channel)
|
|
||||||
RTC_RUN_ON(network_thread());
|
|
||||||
void TeardownDataChannelTransport_n() RTC_RUN_ON(network_thread());
|
void TeardownDataChannelTransport_n() RTC_RUN_ON(network_thread());
|
||||||
cricket::ChannelInterface* GetChannel(const std::string& content_name);
|
cricket::ChannelInterface* GetChannel(const std::string& content_name);
|
||||||
|
|
||||||
|
|||||||
@ -330,8 +330,9 @@ TEST_P(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
|
|||||||
|
|
||||||
auto answer = callee->CreateAnswer();
|
auto answer = callee->CreateAnswer();
|
||||||
ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
|
ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
|
||||||
|
std::string sdp;
|
||||||
|
answer->ToString(&sdp);
|
||||||
ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
|
ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
|
||||||
|
|
||||||
auto* callee_transport =
|
auto* callee_transport =
|
||||||
callee->sctp_transport_factory()->last_fake_sctp_transport();
|
callee->sctp_transport_factory()->last_fake_sctp_transport();
|
||||||
ASSERT_TRUE(callee_transport);
|
ASSERT_TRUE(callee_transport);
|
||||||
|
|||||||
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "api/peer_connection_interface.h"
|
#include "api/peer_connection_interface.h"
|
||||||
#include "call/call.h"
|
#include "call/call.h"
|
||||||
#include "pc/rtp_data_channel.h"
|
|
||||||
#include "pc/rtp_transceiver.h"
|
#include "pc/rtp_transceiver.h"
|
||||||
#include "pc/sctp_data_channel.h"
|
#include "pc/sctp_data_channel.h"
|
||||||
|
|
||||||
@ -41,13 +40,9 @@ class PeerConnectionInternal : public PeerConnectionInterface {
|
|||||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
|
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
|
||||||
GetTransceiversInternal() const = 0;
|
GetTransceiversInternal() const = 0;
|
||||||
|
|
||||||
virtual sigslot::signal1<RtpDataChannel*>& SignalRtpDataChannelCreated() = 0;
|
|
||||||
virtual sigslot::signal1<SctpDataChannel*>&
|
virtual sigslot::signal1<SctpDataChannel*>&
|
||||||
SignalSctpDataChannelCreated() = 0;
|
SignalSctpDataChannelCreated() = 0;
|
||||||
|
|
||||||
// Only valid when using deprecated RTP data channels.
|
|
||||||
virtual cricket::RtpDataChannel* rtp_data_channel() const = 0;
|
|
||||||
|
|
||||||
// Call on the network thread to fetch stats for all the data channels.
|
// Call on the network thread to fetch stats for all the data channels.
|
||||||
// TODO(tommi): Make pure virtual after downstream updates.
|
// TODO(tommi): Make pure virtual after downstream updates.
|
||||||
virtual std::vector<DataChannelStats> GetDataChannelStats() const {
|
virtual std::vector<DataChannelStats> GetDataChannelStats() const {
|
||||||
|
|||||||
@ -1118,8 +1118,6 @@ RTCStatsCollector::RTCStatsCollector(PeerConnectionInternal* pc,
|
|||||||
RTC_DCHECK(worker_thread_);
|
RTC_DCHECK(worker_thread_);
|
||||||
RTC_DCHECK(network_thread_);
|
RTC_DCHECK(network_thread_);
|
||||||
RTC_DCHECK_GE(cache_lifetime_us_, 0);
|
RTC_DCHECK_GE(cache_lifetime_us_, 0);
|
||||||
pc_->SignalRtpDataChannelCreated().connect(
|
|
||||||
this, &RTCStatsCollector::OnRtpDataChannelCreated);
|
|
||||||
pc_->SignalSctpDataChannelCreated().connect(
|
pc_->SignalSctpDataChannelCreated().connect(
|
||||||
this, &RTCStatsCollector::OnSctpDataChannelCreated);
|
this, &RTCStatsCollector::OnSctpDataChannelCreated);
|
||||||
}
|
}
|
||||||
@ -2150,20 +2148,12 @@ std::set<std::string> RTCStatsCollector::PrepareTransportNames_s() const {
|
|||||||
transceiver->internal()->channel()->transport_name());
|
transceiver->internal()->channel()->transport_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pc_->rtp_data_channel()) {
|
|
||||||
transport_names.insert(pc_->rtp_data_channel()->transport_name());
|
|
||||||
}
|
|
||||||
if (pc_->sctp_transport_name()) {
|
if (pc_->sctp_transport_name()) {
|
||||||
transport_names.insert(*pc_->sctp_transport_name());
|
transport_names.insert(*pc_->sctp_transport_name());
|
||||||
}
|
}
|
||||||
return transport_names;
|
return transport_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTCStatsCollector::OnRtpDataChannelCreated(RtpDataChannel* channel) {
|
|
||||||
channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
|
|
||||||
channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RTCStatsCollector::OnSctpDataChannelCreated(SctpDataChannel* channel) {
|
void RTCStatsCollector::OnSctpDataChannelCreated(SctpDataChannel* channel) {
|
||||||
channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
|
channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
|
||||||
channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
|
channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
|
||||||
|
|||||||
@ -29,7 +29,6 @@
|
|||||||
#include "media/base/media_channel.h"
|
#include "media/base/media_channel.h"
|
||||||
#include "pc/data_channel_utils.h"
|
#include "pc/data_channel_utils.h"
|
||||||
#include "pc/peer_connection_internal.h"
|
#include "pc/peer_connection_internal.h"
|
||||||
#include "pc/rtp_data_channel.h"
|
|
||||||
#include "pc/rtp_receiver.h"
|
#include "pc/rtp_receiver.h"
|
||||||
#include "pc/rtp_sender.h"
|
#include "pc/rtp_sender.h"
|
||||||
#include "pc/rtp_transceiver.h"
|
#include "pc/rtp_transceiver.h"
|
||||||
@ -239,7 +238,6 @@ class RTCStatsCollector : public virtual rtc::RefCountInterface,
|
|||||||
void MergeNetworkReport_s();
|
void MergeNetworkReport_s();
|
||||||
|
|
||||||
// Slots for signals (sigslot) that are wired up to |pc_|.
|
// Slots for signals (sigslot) that are wired up to |pc_|.
|
||||||
void OnRtpDataChannelCreated(RtpDataChannel* channel);
|
|
||||||
void OnSctpDataChannelCreated(SctpDataChannel* channel);
|
void OnSctpDataChannelCreated(SctpDataChannel* channel);
|
||||||
// Slots for signals (sigslot) that are wired up to |channel|.
|
// Slots for signals (sigslot) that are wired up to |channel|.
|
||||||
void OnDataChannelOpened(DataChannelInterface* channel);
|
void OnDataChannelOpened(DataChannelInterface* channel);
|
||||||
|
|||||||
@ -1,394 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "pc/rtp_data_channel.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "api/proxy.h"
|
|
||||||
#include "rtc_base/checks.h"
|
|
||||||
#include "rtc_base/location.h"
|
|
||||||
#include "rtc_base/logging.h"
|
|
||||||
#include "rtc_base/ref_counted_object.h"
|
|
||||||
#include "rtc_base/thread.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
static size_t kMaxQueuedReceivedDataBytes = 16 * 1024 * 1024;
|
|
||||||
|
|
||||||
static std::atomic<int> g_unique_id{0};
|
|
||||||
|
|
||||||
int GenerateUniqueId() {
|
|
||||||
return ++g_unique_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define proxy for DataChannelInterface.
|
|
||||||
BEGIN_PRIMARY_PROXY_MAP(DataChannel)
|
|
||||||
PROXY_PRIMARY_THREAD_DESTRUCTOR()
|
|
||||||
PROXY_METHOD1(void, RegisterObserver, DataChannelObserver*)
|
|
||||||
PROXY_METHOD0(void, UnregisterObserver)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(std::string, label)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(bool, reliable)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(bool, ordered)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(uint16_t, maxRetransmitTime)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(uint16_t, maxRetransmits)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(absl::optional<int>, maxRetransmitsOpt)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(absl::optional<int>, maxPacketLifeTime)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(std::string, protocol)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(bool, negotiated)
|
|
||||||
// Can't bypass the proxy since the id may change.
|
|
||||||
PROXY_CONSTMETHOD0(int, id)
|
|
||||||
BYPASS_PROXY_CONSTMETHOD0(Priority, priority)
|
|
||||||
PROXY_CONSTMETHOD0(DataState, state)
|
|
||||||
PROXY_CONSTMETHOD0(RTCError, error)
|
|
||||||
PROXY_CONSTMETHOD0(uint32_t, messages_sent)
|
|
||||||
PROXY_CONSTMETHOD0(uint64_t, bytes_sent)
|
|
||||||
PROXY_CONSTMETHOD0(uint32_t, messages_received)
|
|
||||||
PROXY_CONSTMETHOD0(uint64_t, bytes_received)
|
|
||||||
PROXY_CONSTMETHOD0(uint64_t, buffered_amount)
|
|
||||||
PROXY_METHOD0(void, Close)
|
|
||||||
// TODO(bugs.webrtc.org/11547): Change to run on the network thread.
|
|
||||||
PROXY_METHOD1(bool, Send, const DataBuffer&)
|
|
||||||
END_PROXY_MAP()
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
rtc::scoped_refptr<RtpDataChannel> RtpDataChannel::Create(
|
|
||||||
RtpDataChannelProviderInterface* provider,
|
|
||||||
const std::string& label,
|
|
||||||
const DataChannelInit& config,
|
|
||||||
rtc::Thread* signaling_thread) {
|
|
||||||
rtc::scoped_refptr<RtpDataChannel> channel(
|
|
||||||
new rtc::RefCountedObject<RtpDataChannel>(config, provider, label,
|
|
||||||
signaling_thread));
|
|
||||||
if (!channel->Init()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
rtc::scoped_refptr<DataChannelInterface> RtpDataChannel::CreateProxy(
|
|
||||||
rtc::scoped_refptr<RtpDataChannel> channel) {
|
|
||||||
return DataChannelProxy::Create(channel->signaling_thread_, channel.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpDataChannel::RtpDataChannel(const DataChannelInit& config,
|
|
||||||
RtpDataChannelProviderInterface* provider,
|
|
||||||
const std::string& label,
|
|
||||||
rtc::Thread* signaling_thread)
|
|
||||||
: signaling_thread_(signaling_thread),
|
|
||||||
internal_id_(GenerateUniqueId()),
|
|
||||||
label_(label),
|
|
||||||
config_(config),
|
|
||||||
provider_(provider) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataChannel::Init() {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
if (config_.reliable || config_.id != -1 || config_.maxRetransmits ||
|
|
||||||
config_.maxRetransmitTime) {
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to initialize the RTP data channel due to "
|
|
||||||
"invalid DataChannelInit.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpDataChannel::~RtpDataChannel() {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::RegisterObserver(DataChannelObserver* observer) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
observer_ = observer;
|
|
||||||
DeliverQueuedReceivedData();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::UnregisterObserver() {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
observer_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::Close() {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
if (state_ == kClosed)
|
|
||||||
return;
|
|
||||||
send_ssrc_ = 0;
|
|
||||||
send_ssrc_set_ = false;
|
|
||||||
SetState(kClosing);
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpDataChannel::DataState RtpDataChannel::state() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
return state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
RTCError RtpDataChannel::error() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
return error_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t RtpDataChannel::messages_sent() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
return messages_sent_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t RtpDataChannel::bytes_sent() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
return bytes_sent_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t RtpDataChannel::messages_received() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
return messages_received_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t RtpDataChannel::bytes_received() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
return bytes_received_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataChannel::Send(const DataBuffer& buffer) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
|
|
||||||
if (state_ != kOpen) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(jiayl): the spec is unclear about if the remote side should get the
|
|
||||||
// onmessage event. We need to figure out the expected behavior and change the
|
|
||||||
// code accordingly.
|
|
||||||
if (buffer.size() == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SendDataMessage(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::SetReceiveSsrc(uint32_t receive_ssrc) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
|
|
||||||
if (receive_ssrc_set_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
receive_ssrc_ = receive_ssrc;
|
|
||||||
receive_ssrc_set_ = true;
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::OnTransportChannelClosed() {
|
|
||||||
RTCError error = RTCError(RTCErrorType::OPERATION_ERROR_WITH_DATA,
|
|
||||||
"Transport channel closed");
|
|
||||||
CloseAbruptlyWithError(std::move(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
DataChannelStats RtpDataChannel::GetStats() const {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
DataChannelStats stats{internal_id_, id(), label(),
|
|
||||||
protocol(), state(), messages_sent(),
|
|
||||||
messages_received(), bytes_sent(), bytes_received()};
|
|
||||||
return stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The remote peer request that this channel shall be closed.
|
|
||||||
void RtpDataChannel::RemotePeerRequestClose() {
|
|
||||||
// Close with error code explicitly set to OK.
|
|
||||||
CloseAbruptlyWithError(RTCError());
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::SetSendSsrc(uint32_t send_ssrc) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
if (send_ssrc_set_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
send_ssrc_ = send_ssrc;
|
|
||||||
send_ssrc_set_ = true;
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::OnDataReceived(const cricket::ReceiveDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
if (params.ssrc != receive_ssrc_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RTC_DCHECK(params.type == cricket::DMT_BINARY ||
|
|
||||||
params.type == cricket::DMT_TEXT);
|
|
||||||
|
|
||||||
RTC_LOG(LS_VERBOSE) << "DataChannel received DATA message, sid = "
|
|
||||||
<< params.sid;
|
|
||||||
|
|
||||||
bool binary = (params.type == cricket::DMT_BINARY);
|
|
||||||
auto buffer = std::make_unique<DataBuffer>(payload, binary);
|
|
||||||
if (state_ == kOpen && observer_) {
|
|
||||||
++messages_received_;
|
|
||||||
bytes_received_ += buffer->size();
|
|
||||||
observer_->OnMessage(*buffer.get());
|
|
||||||
} else {
|
|
||||||
if (queued_received_data_.byte_count() + payload.size() >
|
|
||||||
kMaxQueuedReceivedDataBytes) {
|
|
||||||
RTC_LOG(LS_ERROR) << "Queued received data exceeds the max buffer size.";
|
|
||||||
|
|
||||||
queued_received_data_.Clear();
|
|
||||||
CloseAbruptlyWithError(
|
|
||||||
RTCError(RTCErrorType::RESOURCE_EXHAUSTED,
|
|
||||||
"Queued received data exceeds the max buffer size."));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
queued_received_data_.PushBack(std::move(buffer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::OnChannelReady(bool writable) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
|
|
||||||
writable_ = writable;
|
|
||||||
if (!writable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::CloseAbruptlyWithError(RTCError error) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
|
|
||||||
if (state_ == kClosed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connected_to_provider_) {
|
|
||||||
DisconnectFromProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Still go to "kClosing" before "kClosed", since observers may be expecting
|
|
||||||
// that.
|
|
||||||
SetState(kClosing);
|
|
||||||
error_ = std::move(error);
|
|
||||||
SetState(kClosed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::UpdateState() {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
// UpdateState determines what to do from a few state variables. Include
|
|
||||||
// all conditions required for each state transition here for
|
|
||||||
// clarity.
|
|
||||||
switch (state_) {
|
|
||||||
case kConnecting: {
|
|
||||||
if (send_ssrc_set_ == receive_ssrc_set_) {
|
|
||||||
if (!connected_to_provider_) {
|
|
||||||
connected_to_provider_ = provider_->ConnectDataChannel(this);
|
|
||||||
}
|
|
||||||
if (connected_to_provider_ && writable_) {
|
|
||||||
SetState(kOpen);
|
|
||||||
// If we have received buffers before the channel got writable.
|
|
||||||
// Deliver them now.
|
|
||||||
DeliverQueuedReceivedData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kOpen: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kClosing: {
|
|
||||||
// For RTP data channels, we can go to "closed" after we finish
|
|
||||||
// sending data and the send/recv SSRCs are unset.
|
|
||||||
if (connected_to_provider_) {
|
|
||||||
DisconnectFromProvider();
|
|
||||||
}
|
|
||||||
if (!send_ssrc_set_ && !receive_ssrc_set_) {
|
|
||||||
SetState(kClosed);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kClosed:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::SetState(DataState state) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
if (state_ == state) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state_ = state;
|
|
||||||
if (observer_) {
|
|
||||||
observer_->OnStateChange();
|
|
||||||
}
|
|
||||||
if (state_ == kOpen) {
|
|
||||||
SignalOpened(this);
|
|
||||||
} else if (state_ == kClosed) {
|
|
||||||
SignalClosed(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::DisconnectFromProvider() {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
if (!connected_to_provider_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
provider_->DisconnectDataChannel(this);
|
|
||||||
connected_to_provider_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpDataChannel::DeliverQueuedReceivedData() {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
if (!observer_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!queued_received_data_.Empty()) {
|
|
||||||
std::unique_ptr<DataBuffer> buffer = queued_received_data_.PopFront();
|
|
||||||
++messages_received_;
|
|
||||||
bytes_received_ += buffer->size();
|
|
||||||
observer_->OnMessage(*buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpDataChannel::SendDataMessage(const DataBuffer& buffer) {
|
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread_);
|
|
||||||
cricket::SendDataParams send_params;
|
|
||||||
|
|
||||||
send_params.ssrc = send_ssrc_;
|
|
||||||
send_params.type = buffer.binary ? cricket::DMT_BINARY : cricket::DMT_TEXT;
|
|
||||||
|
|
||||||
cricket::SendDataResult send_result = cricket::SDR_SUCCESS;
|
|
||||||
bool success = provider_->SendData(send_params, buffer.data, &send_result);
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
++messages_sent_;
|
|
||||||
bytes_sent_ += buffer.size();
|
|
||||||
if (observer_ && buffer.size() > 0) {
|
|
||||||
observer_->OnBufferedAmountChange(buffer.size());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
void RtpDataChannel::ResetInternalIdAllocatorForTesting(int new_value) {
|
|
||||||
g_unique_id = new_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
@ -1,204 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PC_RTP_DATA_CHANNEL_H_
|
|
||||||
#define PC_RTP_DATA_CHANNEL_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "absl/types/optional.h"
|
|
||||||
#include "api/data_channel_interface.h"
|
|
||||||
#include "api/priority.h"
|
|
||||||
#include "api/rtc_error.h"
|
|
||||||
#include "api/scoped_refptr.h"
|
|
||||||
#include "api/transport/data_channel_transport_interface.h"
|
|
||||||
#include "media/base/media_channel.h"
|
|
||||||
#include "pc/channel.h"
|
|
||||||
#include "pc/data_channel_utils.h"
|
|
||||||
#include "rtc_base/copy_on_write_buffer.h"
|
|
||||||
#include "rtc_base/third_party/sigslot/sigslot.h"
|
|
||||||
#include "rtc_base/thread.h"
|
|
||||||
#include "rtc_base/thread_annotations.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
class RtpDataChannel;
|
|
||||||
|
|
||||||
// TODO(deadbeef): Once RTP data channels go away, get rid of this and have
|
|
||||||
// DataChannel depend on SctpTransportInternal (pure virtual SctpTransport
|
|
||||||
// interface) instead.
|
|
||||||
class RtpDataChannelProviderInterface {
|
|
||||||
public:
|
|
||||||
// Sends the data to the transport.
|
|
||||||
virtual bool SendData(const cricket::SendDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload,
|
|
||||||
cricket::SendDataResult* result) = 0;
|
|
||||||
// Connects to the transport signals.
|
|
||||||
virtual bool ConnectDataChannel(RtpDataChannel* data_channel) = 0;
|
|
||||||
// Disconnects from the transport signals.
|
|
||||||
virtual void DisconnectDataChannel(RtpDataChannel* data_channel) = 0;
|
|
||||||
// Returns true if the transport channel is ready to send data.
|
|
||||||
virtual bool ReadyToSendData() const = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~RtpDataChannelProviderInterface() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// RtpDataChannel is an implementation of the DataChannelInterface based on
|
|
||||||
// libjingle's data engine. It provides an implementation of unreliable data
|
|
||||||
// channels.
|
|
||||||
|
|
||||||
// DataChannel states:
|
|
||||||
// kConnecting: The channel has been created the transport might not yet be
|
|
||||||
// ready.
|
|
||||||
// kOpen: The channel have a local SSRC set by a call to UpdateSendSsrc
|
|
||||||
// and a remote SSRC set by call to UpdateReceiveSsrc and the transport
|
|
||||||
// has been writable once.
|
|
||||||
// kClosing: DataChannelInterface::Close has been called or UpdateReceiveSsrc
|
|
||||||
// has been called with SSRC==0
|
|
||||||
// kClosed: Both UpdateReceiveSsrc and UpdateSendSsrc has been called with
|
|
||||||
// SSRC==0.
|
|
||||||
class RtpDataChannel : public DataChannelInterface,
|
|
||||||
public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
static rtc::scoped_refptr<RtpDataChannel> Create(
|
|
||||||
RtpDataChannelProviderInterface* provider,
|
|
||||||
const std::string& label,
|
|
||||||
const DataChannelInit& config,
|
|
||||||
rtc::Thread* signaling_thread);
|
|
||||||
|
|
||||||
// Instantiates an API proxy for a DataChannel instance that will be handed
|
|
||||||
// out to external callers.
|
|
||||||
static rtc::scoped_refptr<DataChannelInterface> CreateProxy(
|
|
||||||
rtc::scoped_refptr<RtpDataChannel> channel);
|
|
||||||
|
|
||||||
void RegisterObserver(DataChannelObserver* observer) override;
|
|
||||||
void UnregisterObserver() override;
|
|
||||||
|
|
||||||
std::string label() const override { return label_; }
|
|
||||||
bool reliable() const override { return false; }
|
|
||||||
bool ordered() const override { return config_.ordered; }
|
|
||||||
// Backwards compatible accessors
|
|
||||||
uint16_t maxRetransmitTime() const override {
|
|
||||||
return config_.maxRetransmitTime ? *config_.maxRetransmitTime
|
|
||||||
: static_cast<uint16_t>(-1);
|
|
||||||
}
|
|
||||||
uint16_t maxRetransmits() const override {
|
|
||||||
return config_.maxRetransmits ? *config_.maxRetransmits
|
|
||||||
: static_cast<uint16_t>(-1);
|
|
||||||
}
|
|
||||||
absl::optional<int> maxPacketLifeTime() const override {
|
|
||||||
return config_.maxRetransmitTime;
|
|
||||||
}
|
|
||||||
absl::optional<int> maxRetransmitsOpt() const override {
|
|
||||||
return config_.maxRetransmits;
|
|
||||||
}
|
|
||||||
std::string protocol() const override { return config_.protocol; }
|
|
||||||
bool negotiated() const override { return config_.negotiated; }
|
|
||||||
int id() const override { return config_.id; }
|
|
||||||
Priority priority() const override {
|
|
||||||
return config_.priority ? *config_.priority : Priority::kLow;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int internal_id() const { return internal_id_; }
|
|
||||||
|
|
||||||
uint64_t buffered_amount() const override { return 0; }
|
|
||||||
void Close() override;
|
|
||||||
DataState state() const override;
|
|
||||||
RTCError error() const override;
|
|
||||||
uint32_t messages_sent() const override;
|
|
||||||
uint64_t bytes_sent() const override;
|
|
||||||
uint32_t messages_received() const override;
|
|
||||||
uint64_t bytes_received() const override;
|
|
||||||
bool Send(const DataBuffer& buffer) override;
|
|
||||||
|
|
||||||
// Close immediately, ignoring any queued data or closing procedure.
|
|
||||||
// This is called when SDP indicates a channel should be removed.
|
|
||||||
void CloseAbruptlyWithError(RTCError error);
|
|
||||||
|
|
||||||
// Called when the channel's ready to use. That can happen when the
|
|
||||||
// underlying DataMediaChannel becomes ready, or when this channel is a new
|
|
||||||
// stream on an existing DataMediaChannel, and we've finished negotiation.
|
|
||||||
void OnChannelReady(bool writable);
|
|
||||||
|
|
||||||
// Slots for provider to connect signals to.
|
|
||||||
void OnDataReceived(const cricket::ReceiveDataParams& params,
|
|
||||||
const rtc::CopyOnWriteBuffer& payload);
|
|
||||||
|
|
||||||
// Called when the transport channel is unusable.
|
|
||||||
// This method makes sure the DataChannel is disconnected and changes state
|
|
||||||
// to kClosed.
|
|
||||||
void OnTransportChannelClosed();
|
|
||||||
|
|
||||||
DataChannelStats GetStats() const;
|
|
||||||
|
|
||||||
// The remote peer requested that this channel should be closed.
|
|
||||||
void RemotePeerRequestClose();
|
|
||||||
// Set the SSRC this channel should use to send data on the
|
|
||||||
// underlying data engine. |send_ssrc| == 0 means that the channel is no
|
|
||||||
// longer part of the session negotiation.
|
|
||||||
void SetSendSsrc(uint32_t send_ssrc);
|
|
||||||
// Set the SSRC this channel should use to receive data from the
|
|
||||||
// underlying data engine.
|
|
||||||
void SetReceiveSsrc(uint32_t receive_ssrc);
|
|
||||||
|
|
||||||
// Emitted when state transitions to kOpen.
|
|
||||||
sigslot::signal1<DataChannelInterface*> SignalOpened;
|
|
||||||
// Emitted when state transitions to kClosed.
|
|
||||||
sigslot::signal1<DataChannelInterface*> SignalClosed;
|
|
||||||
|
|
||||||
// Reset the allocator for internal ID values for testing, so that
|
|
||||||
// the internal IDs generated are predictable. Test only.
|
|
||||||
static void ResetInternalIdAllocatorForTesting(int new_value);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
RtpDataChannel(const DataChannelInit& config,
|
|
||||||
RtpDataChannelProviderInterface* client,
|
|
||||||
const std::string& label,
|
|
||||||
rtc::Thread* signaling_thread);
|
|
||||||
~RtpDataChannel() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool Init();
|
|
||||||
void UpdateState();
|
|
||||||
void SetState(DataState state);
|
|
||||||
void DisconnectFromProvider();
|
|
||||||
|
|
||||||
void DeliverQueuedReceivedData();
|
|
||||||
|
|
||||||
bool SendDataMessage(const DataBuffer& buffer);
|
|
||||||
|
|
||||||
rtc::Thread* const signaling_thread_;
|
|
||||||
const int internal_id_;
|
|
||||||
const std::string label_;
|
|
||||||
const DataChannelInit config_;
|
|
||||||
DataChannelObserver* observer_ RTC_GUARDED_BY(signaling_thread_) = nullptr;
|
|
||||||
DataState state_ RTC_GUARDED_BY(signaling_thread_) = kConnecting;
|
|
||||||
RTCError error_ RTC_GUARDED_BY(signaling_thread_);
|
|
||||||
uint32_t messages_sent_ RTC_GUARDED_BY(signaling_thread_) = 0;
|
|
||||||
uint64_t bytes_sent_ RTC_GUARDED_BY(signaling_thread_) = 0;
|
|
||||||
uint32_t messages_received_ RTC_GUARDED_BY(signaling_thread_) = 0;
|
|
||||||
uint64_t bytes_received_ RTC_GUARDED_BY(signaling_thread_) = 0;
|
|
||||||
RtpDataChannelProviderInterface* const provider_;
|
|
||||||
bool connected_to_provider_ RTC_GUARDED_BY(signaling_thread_) = false;
|
|
||||||
bool send_ssrc_set_ RTC_GUARDED_BY(signaling_thread_) = false;
|
|
||||||
bool receive_ssrc_set_ RTC_GUARDED_BY(signaling_thread_) = false;
|
|
||||||
bool writable_ RTC_GUARDED_BY(signaling_thread_) = false;
|
|
||||||
uint32_t send_ssrc_ RTC_GUARDED_BY(signaling_thread_) = 0;
|
|
||||||
uint32_t receive_ssrc_ RTC_GUARDED_BY(signaling_thread_) = 0;
|
|
||||||
PacketQueue queued_received_data_ RTC_GUARDED_BY(signaling_thread_);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // PC_RTP_DATA_CHANNEL_H_
|
|
||||||
@ -37,7 +37,6 @@
|
|||||||
#include "media/base/media_channel.h"
|
#include "media/base/media_channel.h"
|
||||||
#include "media/base/media_config.h"
|
#include "media/base/media_config.h"
|
||||||
#include "media/base/media_engine.h"
|
#include "media/base/media_engine.h"
|
||||||
#include "media/base/rtp_data_engine.h"
|
|
||||||
#include "media/base/stream_params.h"
|
#include "media/base/stream_params.h"
|
||||||
#include "media/base/test_utils.h"
|
#include "media/base/test_utils.h"
|
||||||
#include "media/engine/fake_webrtc_call.h"
|
#include "media/engine/fake_webrtc_call.h"
|
||||||
@ -112,8 +111,7 @@ class RtpSenderReceiverTest
|
|||||||
local_stream_(MediaStream::Create(kStreamId1)) {
|
local_stream_(MediaStream::Create(kStreamId1)) {
|
||||||
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&]() {
|
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&]() {
|
||||||
channel_manager_ = cricket::ChannelManager::Create(
|
channel_manager_ = cricket::ChannelManager::Create(
|
||||||
absl::WrapUnique(media_engine_),
|
absl::WrapUnique(media_engine_), false, worker_thread_,
|
||||||
std::make_unique<cricket::RtpDataEngine>(), false, worker_thread_,
|
|
||||||
network_thread_);
|
network_thread_);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -84,7 +84,6 @@ class RtpTransceiverUnifiedPlanTest : public ::testing::Test {
|
|||||||
RtpTransceiverUnifiedPlanTest()
|
RtpTransceiverUnifiedPlanTest()
|
||||||
: channel_manager_(cricket::ChannelManager::Create(
|
: channel_manager_(cricket::ChannelManager::Create(
|
||||||
std::make_unique<cricket::FakeMediaEngine>(),
|
std::make_unique<cricket::FakeMediaEngine>(),
|
||||||
std::make_unique<cricket::FakeDataEngine>(),
|
|
||||||
false,
|
false,
|
||||||
rtc::Thread::Current(),
|
rtc::Thread::Current(),
|
||||||
rtc::Thread::Current())),
|
rtc::Thread::Current())),
|
||||||
@ -121,7 +120,6 @@ class RtpTransceiverTestForHeaderExtensions : public ::testing::Test {
|
|||||||
RtpTransceiverTestForHeaderExtensions()
|
RtpTransceiverTestForHeaderExtensions()
|
||||||
: channel_manager_(cricket::ChannelManager::Create(
|
: channel_manager_(cricket::ChannelManager::Create(
|
||||||
std::make_unique<cricket::FakeMediaEngine>(),
|
std::make_unique<cricket::FakeMediaEngine>(),
|
||||||
std::make_unique<cricket::FakeDataEngine>(),
|
|
||||||
false,
|
false,
|
||||||
rtc::Thread::Current(),
|
rtc::Thread::Current(),
|
||||||
rtc::Thread::Current())),
|
rtc::Thread::Current())),
|
||||||
|
|||||||
@ -43,7 +43,6 @@
|
|||||||
#include "pc/media_stream.h"
|
#include "pc/media_stream.h"
|
||||||
#include "pc/peer_connection.h"
|
#include "pc/peer_connection.h"
|
||||||
#include "pc/peer_connection_message_handler.h"
|
#include "pc/peer_connection_message_handler.h"
|
||||||
#include "pc/rtp_data_channel.h"
|
|
||||||
#include "pc/rtp_media_utils.h"
|
#include "pc/rtp_media_utils.h"
|
||||||
#include "pc/rtp_sender.h"
|
#include "pc/rtp_sender.h"
|
||||||
#include "pc/rtp_transport_internal.h"
|
#include "pc/rtp_transport_internal.h"
|
||||||
@ -693,27 +692,6 @@ std::string GenerateRtcpCname() {
|
|||||||
return cname;
|
return cname;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add options to |session_options| from |rtp_data_channels|.
|
|
||||||
void AddRtpDataChannelOptions(
|
|
||||||
const std::map<std::string, rtc::scoped_refptr<RtpDataChannel>>&
|
|
||||||
rtp_data_channels,
|
|
||||||
cricket::MediaDescriptionOptions* data_media_description_options) {
|
|
||||||
if (!data_media_description_options) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Check for data channels.
|
|
||||||
for (const auto& kv : rtp_data_channels) {
|
|
||||||
const RtpDataChannel* channel = kv.second;
|
|
||||||
if (channel->state() == RtpDataChannel::kConnecting ||
|
|
||||||
channel->state() == RtpDataChannel::kOpen) {
|
|
||||||
// Legacy RTP data channels are signaled with the track/stream ID set to
|
|
||||||
// the data channel's label.
|
|
||||||
data_media_description_options->AddRtpDataChannel(channel->label(),
|
|
||||||
channel->label());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we can send |new_stream| on a PeerConnection.
|
// Check if we can send |new_stream| on a PeerConnection.
|
||||||
bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
|
bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
|
||||||
webrtc::MediaStreamInterface* new_stream) {
|
webrtc::MediaStreamInterface* new_stream) {
|
||||||
@ -1464,17 +1442,7 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cricket::ContentInfo* data_content =
|
// This function does nothing with data content.
|
||||||
GetFirstDataContent(local_description()->description());
|
|
||||||
if (data_content) {
|
|
||||||
const cricket::RtpDataContentDescription* rtp_data_desc =
|
|
||||||
data_content->media_description()->as_rtp_data();
|
|
||||||
// rtp_data_desc will be null if this is an SCTP description.
|
|
||||||
if (rtp_data_desc) {
|
|
||||||
data_channel_controller()->UpdateLocalRtpDataChannels(
|
|
||||||
rtp_data_desc->streams());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == SdpType::kAnswer &&
|
if (type == SdpType::kAnswer &&
|
||||||
local_ice_credentials_to_replace_->SatisfiesIceRestart(
|
local_ice_credentials_to_replace_->SatisfiesIceRestart(
|
||||||
@ -1802,8 +1770,6 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
|
|||||||
GetFirstAudioContentDescription(remote_description()->description());
|
GetFirstAudioContentDescription(remote_description()->description());
|
||||||
const cricket::VideoContentDescription* video_desc =
|
const cricket::VideoContentDescription* video_desc =
|
||||||
GetFirstVideoContentDescription(remote_description()->description());
|
GetFirstVideoContentDescription(remote_description()->description());
|
||||||
const cricket::RtpDataContentDescription* rtp_data_desc =
|
|
||||||
GetFirstRtpDataContentDescription(remote_description()->description());
|
|
||||||
|
|
||||||
// Check if the descriptions include streams, just in case the peer supports
|
// Check if the descriptions include streams, just in case the peer supports
|
||||||
// MSID, but doesn't indicate so with "a=msid-semantic".
|
// MSID, but doesn't indicate so with "a=msid-semantic".
|
||||||
@ -1856,13 +1822,6 @@ RTCError SdpOfferAnswerHandler::ApplyRemoteDescription(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is an RTP data transport, update the DataChannels with the
|
|
||||||
// information from the remote peer.
|
|
||||||
if (rtp_data_desc) {
|
|
||||||
data_channel_controller()->UpdateRemoteRtpDataChannels(
|
|
||||||
GetActiveStreams(rtp_data_desc));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate new_streams and notify the observer about new MediaStreams.
|
// Iterate new_streams and notify the observer about new MediaStreams.
|
||||||
auto observer = pc_->Observer();
|
auto observer = pc_->Observer();
|
||||||
for (size_t i = 0; i < new_streams->count(); ++i) {
|
for (size_t i = 0; i < new_streams->count(); ++i) {
|
||||||
@ -2515,7 +2474,6 @@ RTCError SdpOfferAnswerHandler::UpdateSessionState(
|
|||||||
RTC_DCHECK(type == SdpType::kAnswer);
|
RTC_DCHECK(type == SdpType::kAnswer);
|
||||||
ChangeSignalingState(PeerConnectionInterface::kStable);
|
ChangeSignalingState(PeerConnectionInterface::kStable);
|
||||||
transceivers()->DiscardStableStates();
|
transceivers()->DiscardStableStates();
|
||||||
have_pending_rtp_data_channel_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update internal objects according to the session description's media
|
// Update internal objects according to the session description's media
|
||||||
@ -2739,10 +2697,6 @@ RTCError SdpOfferAnswerHandler::Rollback(SdpType desc_type) {
|
|||||||
transceiver->internal()->set_mline_index(state.mline_index());
|
transceiver->internal()->set_mline_index(state.mline_index());
|
||||||
}
|
}
|
||||||
transport_controller()->RollbackTransports();
|
transport_controller()->RollbackTransports();
|
||||||
if (have_pending_rtp_data_channel_) {
|
|
||||||
DestroyDataChannelTransport();
|
|
||||||
have_pending_rtp_data_channel_ = false;
|
|
||||||
}
|
|
||||||
transceivers()->DiscardStableStates();
|
transceivers()->DiscardStableStates();
|
||||||
pending_local_description_.reset();
|
pending_local_description_.reset();
|
||||||
pending_remote_description_.reset();
|
pending_remote_description_.reset();
|
||||||
@ -3407,21 +3361,13 @@ RTCError SdpOfferAnswerHandler::UpdateDataChannel(
|
|||||||
RTC_LOG(LS_INFO) << "Rejected data channel, mid=" << content.mid();
|
RTC_LOG(LS_INFO) << "Rejected data channel, mid=" << content.mid();
|
||||||
DestroyDataChannelTransport();
|
DestroyDataChannelTransport();
|
||||||
} else {
|
} else {
|
||||||
if (!data_channel_controller()->rtp_data_channel() &&
|
if (!data_channel_controller()->data_channel_transport()) {
|
||||||
!data_channel_controller()->data_channel_transport()) {
|
|
||||||
RTC_LOG(LS_INFO) << "Creating data channel, mid=" << content.mid();
|
RTC_LOG(LS_INFO) << "Creating data channel, mid=" << content.mid();
|
||||||
if (!CreateDataChannel(content.name)) {
|
if (!CreateDataChannel(content.name)) {
|
||||||
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
|
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
|
||||||
"Failed to create data channel.");
|
"Failed to create data channel.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (source == cricket::CS_REMOTE) {
|
|
||||||
const MediaContentDescription* data_desc = content.media_description();
|
|
||||||
if (data_desc && cricket::IsRtpProtocol(data_desc->protocol())) {
|
|
||||||
data_channel_controller()->UpdateRemoteRtpDataChannels(
|
|
||||||
GetActiveStreams(data_desc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return RTCError::OK();
|
return RTCError::OK();
|
||||||
}
|
}
|
||||||
@ -3548,15 +3494,7 @@ void SdpOfferAnswerHandler::GetOptionsForOffer(
|
|||||||
GetOptionsForPlanBOffer(offer_answer_options, session_options);
|
GetOptionsForPlanBOffer(offer_answer_options, session_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intentionally unset the data channel type for RTP data channel with the
|
session_options->data_channel_type = pc_->data_channel_type();
|
||||||
// second condition. Otherwise the RTP data channels would be successfully
|
|
||||||
// negotiated by default and the unit tests in WebRtcDataBrowserTest will fail
|
|
||||||
// when building with chromium. We want to leave RTP data channels broken, so
|
|
||||||
// people won't try to use them.
|
|
||||||
if (data_channel_controller()->HasRtpDataChannels() ||
|
|
||||||
pc_->data_channel_type() != cricket::DCT_RTP) {
|
|
||||||
session_options->data_channel_type = pc_->data_channel_type();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply ICE restart flag and renomination flag.
|
// Apply ICE restart flag and renomination flag.
|
||||||
bool ice_restart = offer_answer_options.ice_restart || HasNewIceCredentials();
|
bool ice_restart = offer_answer_options.ice_restart || HasNewIceCredentials();
|
||||||
@ -3815,14 +3753,7 @@ void SdpOfferAnswerHandler::GetOptionsForAnswer(
|
|||||||
GetOptionsForPlanBAnswer(offer_answer_options, session_options);
|
GetOptionsForPlanBAnswer(offer_answer_options, session_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intentionally unset the data channel type for RTP data channel. Otherwise
|
session_options->data_channel_type = pc_->data_channel_type();
|
||||||
// the RTP data channels would be successfully negotiated by default and the
|
|
||||||
// unit tests in WebRtcDataBrowserTest will fail when building with chromium.
|
|
||||||
// We want to leave RTP data channels broken, so people won't try to use them.
|
|
||||||
if (data_channel_controller()->HasRtpDataChannels() ||
|
|
||||||
pc_->data_channel_type() != cricket::DCT_RTP) {
|
|
||||||
session_options->data_channel_type = pc_->data_channel_type();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply ICE renomination flag.
|
// Apply ICE renomination flag.
|
||||||
for (auto& options : session_options->media_description_options) {
|
for (auto& options : session_options->media_description_options) {
|
||||||
@ -4234,11 +4165,6 @@ void SdpOfferAnswerHandler::EnableSending() {
|
|||||||
channel->Enable(true);
|
channel->Enable(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_channel_controller()->rtp_data_channel() &&
|
|
||||||
!data_channel_controller()->rtp_data_channel()->enabled()) {
|
|
||||||
data_channel_controller()->rtp_data_channel()->Enable(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCError SdpOfferAnswerHandler::PushdownMediaDescription(
|
RTCError SdpOfferAnswerHandler::PushdownMediaDescription(
|
||||||
@ -4280,29 +4206,6 @@ RTCError SdpOfferAnswerHandler::PushdownMediaDescription(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If using the RtpDataChannel, push down the new SDP section for it too.
|
|
||||||
if (data_channel_controller()->rtp_data_channel()) {
|
|
||||||
const ContentInfo* data_content =
|
|
||||||
cricket::GetFirstDataContent(sdesc->description());
|
|
||||||
if (data_content && !data_content->rejected) {
|
|
||||||
const MediaContentDescription* data_desc =
|
|
||||||
data_content->media_description();
|
|
||||||
if (data_desc) {
|
|
||||||
std::string error;
|
|
||||||
bool success = (source == cricket::CS_LOCAL)
|
|
||||||
? data_channel_controller()
|
|
||||||
->rtp_data_channel()
|
|
||||||
->SetLocalContent(data_desc, type, &error)
|
|
||||||
: data_channel_controller()
|
|
||||||
->rtp_data_channel()
|
|
||||||
->SetRemoteContent(data_desc, type, &error);
|
|
||||||
if (!success) {
|
|
||||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need complete offer/answer with an SCTP m= section before starting SCTP,
|
// Need complete offer/answer with an SCTP m= section before starting SCTP,
|
||||||
// according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
|
// according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
|
||||||
if (pc_->sctp_mid() && local_description() && remote_description()) {
|
if (pc_->sctp_mid() && local_description() && remote_description()) {
|
||||||
@ -4599,8 +4502,7 @@ RTCError SdpOfferAnswerHandler::CreateChannels(const SessionDescription& desc) {
|
|||||||
|
|
||||||
const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc);
|
const cricket::ContentInfo* data = cricket::GetFirstDataContent(&desc);
|
||||||
if (pc_->data_channel_type() != cricket::DCT_NONE && data &&
|
if (pc_->data_channel_type() != cricket::DCT_NONE && data &&
|
||||||
!data->rejected && !data_channel_controller()->rtp_data_channel() &&
|
!data->rejected && !data_channel_controller()->data_channel_transport()) {
|
||||||
!data_channel_controller()->data_channel_transport()) {
|
|
||||||
if (!CreateDataChannel(data->name)) {
|
if (!CreateDataChannel(data->name)) {
|
||||||
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
|
LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
|
||||||
"Failed to create data channel.");
|
"Failed to create data channel.");
|
||||||
@ -4678,23 +4580,10 @@ bool SdpOfferAnswerHandler::CreateDataChannel(const std::string& mid) {
|
|||||||
// out of sync (transport name not set while the mid is set).
|
// out of sync (transport name not set while the mid is set).
|
||||||
pc_->SetSctpDataMid(mid);
|
pc_->SetSctpDataMid(mid);
|
||||||
break;
|
break;
|
||||||
case cricket::DCT_RTP:
|
case cricket::DCT_NONE:
|
||||||
default:
|
// User error.
|
||||||
RtpTransportInternal* rtp_transport = pc_->GetRtpTransport(mid);
|
RTC_NOTREACHED();
|
||||||
cricket::RtpDataChannel* data_channel =
|
return false;
|
||||||
channel_manager()->CreateRtpDataChannel(
|
|
||||||
pc_->configuration()->media_config, rtp_transport,
|
|
||||||
signaling_thread(), mid, pc_->SrtpRequired(),
|
|
||||||
pc_->GetCryptoOptions(), &ssrc_generator_);
|
|
||||||
if (!data_channel)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pc_->network_thread()->Invoke<void>(RTC_FROM_HERE, [this, data_channel] {
|
|
||||||
RTC_DCHECK_RUN_ON(pc_->network_thread());
|
|
||||||
pc_->SetupRtpDataChannelTransport_n(data_channel);
|
|
||||||
});
|
|
||||||
have_pending_rtp_data_channel_ = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -4716,9 +4605,9 @@ void SdpOfferAnswerHandler::DestroyTransceiverChannel(
|
|||||||
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(0);
|
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(0);
|
||||||
if (channel) {
|
if (channel) {
|
||||||
// TODO(tommi): VideoRtpReceiver::SetMediaChannel blocks and jumps to the
|
// TODO(tommi): VideoRtpReceiver::SetMediaChannel blocks and jumps to the
|
||||||
// worker thread. When being set to nullptr, there are additional blocking
|
// worker thread. When being set to nullptrpus, there are additional
|
||||||
// calls to e.g. ClearRecordableEncodedFrameCallback which triggers another
|
// blocking calls to e.g. ClearRecordableEncodedFrameCallback which triggers
|
||||||
// blocking call or Stop() for video channels.
|
// another blocking call or Stop() for video channels.
|
||||||
transceiver->internal()->SetChannel(nullptr);
|
transceiver->internal()->SetChannel(nullptr);
|
||||||
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
|
RTC_DCHECK_BLOCK_COUNT_NO_MORE_THAN(2);
|
||||||
// TODO(tommi): All channel objects end up getting deleted on the
|
// TODO(tommi): All channel objects end up getting deleted on the
|
||||||
@ -4731,9 +4620,8 @@ void SdpOfferAnswerHandler::DestroyTransceiverChannel(
|
|||||||
void SdpOfferAnswerHandler::DestroyDataChannelTransport() {
|
void SdpOfferAnswerHandler::DestroyDataChannelTransport() {
|
||||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||||
const bool has_sctp = pc_->sctp_mid().has_value();
|
const bool has_sctp = pc_->sctp_mid().has_value();
|
||||||
auto* rtp_data_channel = data_channel_controller()->rtp_data_channel();
|
|
||||||
|
|
||||||
if (has_sctp || rtp_data_channel)
|
if (has_sctp)
|
||||||
data_channel_controller()->OnTransportChannelClosed();
|
data_channel_controller()->OnTransportChannelClosed();
|
||||||
|
|
||||||
pc_->network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
|
pc_->network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
|
||||||
@ -4743,9 +4631,6 @@ void SdpOfferAnswerHandler::DestroyDataChannelTransport() {
|
|||||||
|
|
||||||
if (has_sctp)
|
if (has_sctp)
|
||||||
pc_->ResetSctpDataMid();
|
pc_->ResetSctpDataMid();
|
||||||
|
|
||||||
if (rtp_data_channel)
|
|
||||||
DestroyChannelInterface(rtp_data_channel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdpOfferAnswerHandler::DestroyChannelInterface(
|
void SdpOfferAnswerHandler::DestroyChannelInterface(
|
||||||
@ -4770,8 +4655,8 @@ void SdpOfferAnswerHandler::DestroyChannelInterface(
|
|||||||
static_cast<cricket::VideoChannel*>(channel));
|
static_cast<cricket::VideoChannel*>(channel));
|
||||||
break;
|
break;
|
||||||
case cricket::MEDIA_TYPE_DATA:
|
case cricket::MEDIA_TYPE_DATA:
|
||||||
channel_manager()->DestroyRtpDataChannel(
|
RTC_NOTREACHED()
|
||||||
static_cast<cricket::RtpDataChannel*>(channel));
|
<< "Trying to destroy datachannel through DestroyChannelInterface";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
RTC_NOTREACHED() << "Unknown media type: " << channel->media_type();
|
RTC_NOTREACHED() << "Unknown media type: " << channel->media_type();
|
||||||
@ -4887,8 +4772,6 @@ SdpOfferAnswerHandler::GetMediaDescriptionOptionsForActiveData(
|
|||||||
cricket::MediaDescriptionOptions options(cricket::MEDIA_TYPE_DATA, mid,
|
cricket::MediaDescriptionOptions options(cricket::MEDIA_TYPE_DATA, mid,
|
||||||
RtpTransceiverDirection::kSendRecv,
|
RtpTransceiverDirection::kSendRecv,
|
||||||
/*stopped=*/false);
|
/*stopped=*/false);
|
||||||
AddRtpDataChannelOptions(*(data_channel_controller()->rtp_data_channels()),
|
|
||||||
&options);
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4899,8 +4782,6 @@ SdpOfferAnswerHandler::GetMediaDescriptionOptionsForRejectedData(
|
|||||||
cricket::MediaDescriptionOptions options(cricket::MEDIA_TYPE_DATA, mid,
|
cricket::MediaDescriptionOptions options(cricket::MEDIA_TYPE_DATA, mid,
|
||||||
RtpTransceiverDirection::kInactive,
|
RtpTransceiverDirection::kInactive,
|
||||||
/*stopped=*/true);
|
/*stopped=*/true);
|
||||||
AddRtpDataChannelOptions(*(data_channel_controller()->rtp_data_channels()),
|
|
||||||
&options);
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -632,10 +632,6 @@ class SdpOfferAnswerHandler : public SdpStateProvider,
|
|||||||
rtc::scoped_refptr<MediaStreamInterface> missing_msid_default_stream_
|
rtc::scoped_refptr<MediaStreamInterface> missing_msid_default_stream_
|
||||||
RTC_GUARDED_BY(signaling_thread());
|
RTC_GUARDED_BY(signaling_thread());
|
||||||
|
|
||||||
// Used when rolling back RTP data channels.
|
|
||||||
bool have_pending_rtp_data_channel_ RTC_GUARDED_BY(signaling_thread()) =
|
|
||||||
false;
|
|
||||||
|
|
||||||
// Updates the error state, signaling if necessary.
|
// Updates the error state, signaling if necessary.
|
||||||
void SetSessionError(SessionError error, const std::string& error_desc);
|
void SetSessionError(SessionError error, const std::string& error_desc);
|
||||||
|
|
||||||
|
|||||||
@ -60,7 +60,6 @@ const int kAutoBandwidth = -1;
|
|||||||
|
|
||||||
class AudioContentDescription;
|
class AudioContentDescription;
|
||||||
class VideoContentDescription;
|
class VideoContentDescription;
|
||||||
class RtpDataContentDescription;
|
|
||||||
class SctpDataContentDescription;
|
class SctpDataContentDescription;
|
||||||
class UnsupportedContentDescription;
|
class UnsupportedContentDescription;
|
||||||
|
|
||||||
@ -83,11 +82,6 @@ class MediaContentDescription {
|
|||||||
virtual VideoContentDescription* as_video() { return nullptr; }
|
virtual VideoContentDescription* as_video() { return nullptr; }
|
||||||
virtual const VideoContentDescription* as_video() const { return nullptr; }
|
virtual const VideoContentDescription* as_video() const { return nullptr; }
|
||||||
|
|
||||||
virtual RtpDataContentDescription* as_rtp_data() { return nullptr; }
|
|
||||||
virtual const RtpDataContentDescription* as_rtp_data() const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual SctpDataContentDescription* as_sctp() { return nullptr; }
|
virtual SctpDataContentDescription* as_sctp() { return nullptr; }
|
||||||
virtual const SctpDataContentDescription* as_sctp() const { return nullptr; }
|
virtual const SctpDataContentDescription* as_sctp() const { return nullptr; }
|
||||||
|
|
||||||
@ -361,20 +355,6 @@ class VideoContentDescription : public MediaContentDescriptionImpl<VideoCodec> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class RtpDataContentDescription
|
|
||||||
: public MediaContentDescriptionImpl<RtpDataCodec> {
|
|
||||||
public:
|
|
||||||
RtpDataContentDescription() {}
|
|
||||||
MediaType type() const override { return MEDIA_TYPE_DATA; }
|
|
||||||
RtpDataContentDescription* as_rtp_data() override { return this; }
|
|
||||||
const RtpDataContentDescription* as_rtp_data() const override { return this; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
RtpDataContentDescription* CloneInternal() const override {
|
|
||||||
return new RtpDataContentDescription(*this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SctpDataContentDescription : public MediaContentDescription {
|
class SctpDataContentDescription : public MediaContentDescription {
|
||||||
public:
|
public:
|
||||||
SctpDataContentDescription() {}
|
SctpDataContentDescription() {}
|
||||||
|
|||||||
@ -130,16 +130,6 @@ TEST(SessionDescriptionTest, AddContentTransfersExtmapAllowMixedSetting) {
|
|||||||
EXPECT_EQ(MediaContentDescription::kSession,
|
EXPECT_EQ(MediaContentDescription::kSession,
|
||||||
session_desc.GetContentDescriptionByName("video")
|
session_desc.GetContentDescriptionByName("video")
|
||||||
->extmap_allow_mixed_enum());
|
->extmap_allow_mixed_enum());
|
||||||
|
|
||||||
// Session level setting overrides media level when new content is added.
|
|
||||||
std::unique_ptr<MediaContentDescription> data_desc =
|
|
||||||
std::make_unique<RtpDataContentDescription>();
|
|
||||||
data_desc->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
|
|
||||||
session_desc.AddContent("data", MediaProtocolType::kRtp,
|
|
||||||
std::move(data_desc));
|
|
||||||
EXPECT_EQ(MediaContentDescription::kSession,
|
|
||||||
session_desc.GetContentDescriptionByName("data")
|
|
||||||
->extmap_allow_mixed_enum());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|||||||
@ -248,16 +248,10 @@ class FakePeerConnectionBase : public PeerConnectionInternal {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
sigslot::signal1<RtpDataChannel*>& SignalRtpDataChannelCreated() override {
|
|
||||||
return SignalRtpDataChannelCreated_;
|
|
||||||
}
|
|
||||||
|
|
||||||
sigslot::signal1<SctpDataChannel*>& SignalSctpDataChannelCreated() override {
|
sigslot::signal1<SctpDataChannel*>& SignalSctpDataChannelCreated() override {
|
||||||
return SignalSctpDataChannelCreated_;
|
return SignalSctpDataChannelCreated_;
|
||||||
}
|
}
|
||||||
|
|
||||||
cricket::RtpDataChannel* rtp_data_channel() const override { return nullptr; }
|
|
||||||
|
|
||||||
absl::optional<std::string> sctp_transport_name() const override {
|
absl::optional<std::string> sctp_transport_name() const override {
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
@ -298,7 +292,6 @@ class FakePeerConnectionBase : public PeerConnectionInternal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
sigslot::signal1<RtpDataChannel*> SignalRtpDataChannelCreated_;
|
|
||||||
sigslot::signal1<SctpDataChannel*> SignalSctpDataChannelCreated_;
|
sigslot::signal1<SctpDataChannel*> SignalSctpDataChannelCreated_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -82,7 +82,6 @@ using cricket::MediaContentDescription;
|
|||||||
using cricket::MediaProtocolType;
|
using cricket::MediaProtocolType;
|
||||||
using cricket::MediaType;
|
using cricket::MediaType;
|
||||||
using cricket::RidDescription;
|
using cricket::RidDescription;
|
||||||
using cricket::RtpDataContentDescription;
|
|
||||||
using cricket::RtpHeaderExtensions;
|
using cricket::RtpHeaderExtensions;
|
||||||
using cricket::SctpDataContentDescription;
|
using cricket::SctpDataContentDescription;
|
||||||
using cricket::SimulcastDescription;
|
using cricket::SimulcastDescription;
|
||||||
@ -1415,12 +1414,7 @@ void BuildMediaDescription(const ContentInfo* content_info,
|
|||||||
fmt.append(kDefaultSctpmapProtocol);
|
fmt.append(kDefaultSctpmapProtocol);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const RtpDataContentDescription* rtp_data_desc =
|
RTC_NOTREACHED() << "Data description without SCTP";
|
||||||
media_desc->as_rtp_data();
|
|
||||||
for (const cricket::RtpDataCodec& codec : rtp_data_desc->codecs()) {
|
|
||||||
fmt.append(" ");
|
|
||||||
fmt.append(rtc::ToString(codec.id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (media_type == cricket::MEDIA_TYPE_UNSUPPORTED) {
|
} else if (media_type == cricket::MEDIA_TYPE_UNSUPPORTED) {
|
||||||
const UnsupportedContentDescription* unsupported_desc =
|
const UnsupportedContentDescription* unsupported_desc =
|
||||||
@ -1972,19 +1966,6 @@ void BuildRtpMap(const MediaContentDescription* media_desc,
|
|||||||
ptime = std::max(ptime, max_minptime);
|
ptime = std::max(ptime, max_minptime);
|
||||||
AddAttributeLine(kCodecParamPTime, ptime, message);
|
AddAttributeLine(kCodecParamPTime, ptime, message);
|
||||||
}
|
}
|
||||||
} else if (media_type == cricket::MEDIA_TYPE_DATA) {
|
|
||||||
if (media_desc->as_rtp_data()) {
|
|
||||||
for (const cricket::RtpDataCodec& codec :
|
|
||||||
media_desc->as_rtp_data()->codecs()) {
|
|
||||||
// RFC 4566
|
|
||||||
// a=rtpmap:<payload type> <encoding name>/<clock rate>
|
|
||||||
// [/<encodingparameters>]
|
|
||||||
InitAttrLine(kAttributeRtpmap, &os);
|
|
||||||
os << kSdpDelimiterColon << codec.id << " " << codec.name << "/"
|
|
||||||
<< codec.clockrate;
|
|
||||||
AddLine(os.str(), message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2739,14 +2720,6 @@ bool ParseMediaDescription(
|
|||||||
}
|
}
|
||||||
data_desc->set_protocol(protocol);
|
data_desc->set_protocol(protocol);
|
||||||
content = std::move(data_desc);
|
content = std::move(data_desc);
|
||||||
} else if (cricket::IsRtpProtocol(protocol)) {
|
|
||||||
// RTP
|
|
||||||
std::unique_ptr<RtpDataContentDescription> data_desc =
|
|
||||||
ParseContentDescription<RtpDataContentDescription>(
|
|
||||||
message, cricket::MEDIA_TYPE_DATA, mline_index, protocol,
|
|
||||||
payload_types, pos, &content_name, &bundle_only,
|
|
||||||
§ion_msid_signaling, &transport, candidates, error);
|
|
||||||
content = std::move(data_desc);
|
|
||||||
} else {
|
} else {
|
||||||
return ParseFailed(line, "Unsupported protocol for media type", error);
|
return ParseFailed(line, "Unsupported protocol for media type", error);
|
||||||
}
|
}
|
||||||
@ -3671,11 +3644,6 @@ bool ParseRtpmapAttribute(const std::string& line,
|
|||||||
AudioContentDescription* audio_desc = media_desc->as_audio();
|
AudioContentDescription* audio_desc = media_desc->as_audio();
|
||||||
UpdateCodec(payload_type, encoding_name, clock_rate, 0, channels,
|
UpdateCodec(payload_type, encoding_name, clock_rate, 0, channels,
|
||||||
audio_desc);
|
audio_desc);
|
||||||
} else if (media_type == cricket::MEDIA_TYPE_DATA) {
|
|
||||||
RtpDataContentDescription* data_desc = media_desc->as_rtp_data();
|
|
||||||
if (data_desc) {
|
|
||||||
data_desc->AddCodec(cricket::RtpDataCodec(payload_type, encoding_name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,6 @@ using cricket::MediaProtocolType;
|
|||||||
using cricket::RELAY_PORT_TYPE;
|
using cricket::RELAY_PORT_TYPE;
|
||||||
using cricket::RidDescription;
|
using cricket::RidDescription;
|
||||||
using cricket::RidDirection;
|
using cricket::RidDirection;
|
||||||
using cricket::RtpDataContentDescription;
|
|
||||||
using cricket::SctpDataContentDescription;
|
using cricket::SctpDataContentDescription;
|
||||||
using cricket::SessionDescription;
|
using cricket::SessionDescription;
|
||||||
using cricket::SimulcastDescription;
|
using cricket::SimulcastDescription;
|
||||||
@ -263,22 +262,6 @@ static const char kSdpString[] =
|
|||||||
"a=ssrc:3 mslabel:local_stream_1\r\n"
|
"a=ssrc:3 mslabel:local_stream_1\r\n"
|
||||||
"a=ssrc:3 label:video_track_id_1\r\n";
|
"a=ssrc:3 label:video_track_id_1\r\n";
|
||||||
|
|
||||||
static const char kSdpRtpDataChannelString[] =
|
|
||||||
"m=application 9 RTP/SAVPF 101\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_data\r\n"
|
|
||||||
"a=ice-pwd:pwd_data\r\n"
|
|
||||||
"a=mid:data_content_name\r\n"
|
|
||||||
"a=sendrecv\r\n"
|
|
||||||
"a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
|
|
||||||
"inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5\r\n"
|
|
||||||
"a=rtpmap:101 google-data/90000\r\n"
|
|
||||||
"a=ssrc:10 cname:data_channel_cname\r\n"
|
|
||||||
"a=ssrc:10 msid:data_channel data_channeld0\r\n"
|
|
||||||
"a=ssrc:10 mslabel:data_channel\r\n"
|
|
||||||
"a=ssrc:10 label:data_channeld0\r\n";
|
|
||||||
|
|
||||||
// draft-ietf-mmusic-sctp-sdp-03
|
// draft-ietf-mmusic-sctp-sdp-03
|
||||||
static const char kSdpSctpDataChannelString[] =
|
static const char kSdpSctpDataChannelString[] =
|
||||||
"m=application 9 UDP/DTLS/SCTP 5000\r\n"
|
"m=application 9 UDP/DTLS/SCTP 5000\r\n"
|
||||||
@ -906,12 +889,6 @@ static const uint32_t kVideoTrack3Ssrc = 6;
|
|||||||
static const char kAudioTrackId3[] = "audio_track_id_3";
|
static const char kAudioTrackId3[] = "audio_track_id_3";
|
||||||
static const uint32_t kAudioTrack3Ssrc = 7;
|
static const uint32_t kAudioTrack3Ssrc = 7;
|
||||||
|
|
||||||
// DataChannel
|
|
||||||
static const char kDataChannelLabel[] = "data_channel";
|
|
||||||
static const char kDataChannelMsid[] = "data_channeld0";
|
|
||||||
static const char kDataChannelCname[] = "data_channel_cname";
|
|
||||||
static const uint32_t kDataChannelSsrc = 10;
|
|
||||||
|
|
||||||
// Candidate
|
// Candidate
|
||||||
static const char kDummyMid[] = "dummy_mid";
|
static const char kDummyMid[] = "dummy_mid";
|
||||||
static const int kDummyIndex = 123;
|
static const int kDummyIndex = 123;
|
||||||
@ -1466,11 +1443,6 @@ class WebRtcSdpTest : public ::testing::Test {
|
|||||||
simulcast2.receive_layers().size());
|
simulcast2.receive_layers().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompareRtpDataContentDescription(const RtpDataContentDescription* dcd1,
|
|
||||||
const RtpDataContentDescription* dcd2) {
|
|
||||||
CompareMediaContentDescription<RtpDataContentDescription>(dcd1, dcd2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CompareSctpDataContentDescription(
|
void CompareSctpDataContentDescription(
|
||||||
const SctpDataContentDescription* dcd1,
|
const SctpDataContentDescription* dcd1,
|
||||||
const SctpDataContentDescription* dcd2) {
|
const SctpDataContentDescription* dcd2) {
|
||||||
@ -1521,14 +1493,6 @@ class WebRtcSdpTest : public ::testing::Test {
|
|||||||
const SctpDataContentDescription* scd2 =
|
const SctpDataContentDescription* scd2 =
|
||||||
c2.media_description()->as_sctp();
|
c2.media_description()->as_sctp();
|
||||||
CompareSctpDataContentDescription(scd1, scd2);
|
CompareSctpDataContentDescription(scd1, scd2);
|
||||||
} else {
|
|
||||||
if (IsDataContent(&c1)) {
|
|
||||||
const RtpDataContentDescription* dcd1 =
|
|
||||||
c1.media_description()->as_rtp_data();
|
|
||||||
const RtpDataContentDescription* dcd2 =
|
|
||||||
c2.media_description()->as_rtp_data();
|
|
||||||
CompareRtpDataContentDescription(dcd1, dcd2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareSimulcastDescription(
|
CompareSimulcastDescription(
|
||||||
@ -1816,28 +1780,6 @@ class WebRtcSdpTest : public ::testing::Test {
|
|||||||
kDataContentName, TransportDescription(kUfragData, kPwdData)));
|
kDataContentName, TransportDescription(kUfragData, kPwdData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddRtpDataChannel() {
|
|
||||||
std::unique_ptr<RtpDataContentDescription> data(
|
|
||||||
new RtpDataContentDescription());
|
|
||||||
data_desc_ = data.get();
|
|
||||||
|
|
||||||
data_desc_->AddCodec(DataCodec(101, "google-data"));
|
|
||||||
StreamParams data_stream;
|
|
||||||
data_stream.id = kDataChannelMsid;
|
|
||||||
data_stream.cname = kDataChannelCname;
|
|
||||||
data_stream.set_stream_ids({kDataChannelLabel});
|
|
||||||
data_stream.ssrcs.push_back(kDataChannelSsrc);
|
|
||||||
data_desc_->AddStream(data_stream);
|
|
||||||
data_desc_->AddCrypto(
|
|
||||||
CryptoParams(1, "AES_CM_128_HMAC_SHA1_80",
|
|
||||||
"inline:FvLcvU2P3ZWmQxgPAgcDu7Zl9vftYElFOjEzhWs5", ""));
|
|
||||||
data_desc_->set_protocol(cricket::kMediaProtocolSavpf);
|
|
||||||
desc_.AddContent(kDataContentName, MediaProtocolType::kRtp,
|
|
||||||
std::move(data));
|
|
||||||
desc_.AddTransportInfo(TransportInfo(
|
|
||||||
kDataContentName, TransportDescription(kUfragData, kPwdData)));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TestDeserializeDirection(RtpTransceiverDirection direction) {
|
bool TestDeserializeDirection(RtpTransceiverDirection direction) {
|
||||||
std::string new_sdp = kSdpFullString;
|
std::string new_sdp = kSdpFullString;
|
||||||
ReplaceDirection(direction, &new_sdp);
|
ReplaceDirection(direction, &new_sdp);
|
||||||
@ -2103,7 +2045,6 @@ class WebRtcSdpTest : public ::testing::Test {
|
|||||||
SessionDescription desc_;
|
SessionDescription desc_;
|
||||||
AudioContentDescription* audio_desc_;
|
AudioContentDescription* audio_desc_;
|
||||||
VideoContentDescription* video_desc_;
|
VideoContentDescription* video_desc_;
|
||||||
RtpDataContentDescription* data_desc_;
|
|
||||||
SctpDataContentDescription* sctp_desc_;
|
SctpDataContentDescription* sctp_desc_;
|
||||||
Candidates candidates_;
|
Candidates candidates_;
|
||||||
std::unique_ptr<IceCandidateInterface> jcandidate_;
|
std::unique_ptr<IceCandidateInterface> jcandidate_;
|
||||||
@ -2269,18 +2210,6 @@ TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioVideoRejected) {
|
|||||||
EXPECT_TRUE(TestSerializeRejected(true, true));
|
EXPECT_TRUE(TestSerializeRejected(true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRtpDataChannel) {
|
|
||||||
AddRtpDataChannel();
|
|
||||||
JsepSessionDescription jsep_desc(kDummyType);
|
|
||||||
|
|
||||||
MakeDescriptionWithoutCandidates(&jsep_desc);
|
|
||||||
std::string message = webrtc::SdpSerialize(jsep_desc);
|
|
||||||
|
|
||||||
std::string expected_sdp = kSdpString;
|
|
||||||
expected_sdp.append(kSdpRtpDataChannelString);
|
|
||||||
EXPECT_EQ(expected_sdp, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSctpDataChannel) {
|
||||||
bool use_sctpmap = true;
|
bool use_sctpmap = true;
|
||||||
AddSctpDataChannel(use_sctpmap);
|
AddSctpDataChannel(use_sctpmap);
|
||||||
@ -2327,22 +2256,6 @@ TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
|
|||||||
EXPECT_EQ(expected_sdp, message);
|
EXPECT_EQ(expected_sdp, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithDataChannelAndBandwidth) {
|
|
||||||
JsepSessionDescription jsep_desc(kDummyType);
|
|
||||||
AddRtpDataChannel();
|
|
||||||
data_desc_->set_bandwidth(100 * 1000);
|
|
||||||
data_desc_->set_bandwidth_type("AS");
|
|
||||||
MakeDescriptionWithoutCandidates(&jsep_desc);
|
|
||||||
std::string message = webrtc::SdpSerialize(jsep_desc);
|
|
||||||
|
|
||||||
std::string expected_sdp = kSdpString;
|
|
||||||
expected_sdp.append(kSdpRtpDataChannelString);
|
|
||||||
// Serializing data content shouldn't ignore bandwidth settings.
|
|
||||||
InjectAfter("m=application 9 RTP/SAVPF 101\r\nc=IN IP4 0.0.0.0\r\n",
|
|
||||||
"b=AS:100\r\n", &expected_sdp);
|
|
||||||
EXPECT_EQ(expected_sdp, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapAllowMixed) {
|
TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithExtmapAllowMixed) {
|
||||||
jdesc_.description()->set_extmap_allow_mixed(true);
|
jdesc_.description()->set_extmap_allow_mixed(true);
|
||||||
TestSerialize(jdesc_);
|
TestSerialize(jdesc_);
|
||||||
@ -2913,21 +2826,6 @@ TEST_F(WebRtcSdpTest, DeserializeInvalidCandidiate) {
|
|||||||
EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
|
EXPECT_FALSE(SdpDeserializeCandidate(kSdpTcpInvalidCandidate, &jcandidate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannels) {
|
|
||||||
AddRtpDataChannel();
|
|
||||||
JsepSessionDescription jdesc(kDummyType);
|
|
||||||
ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));
|
|
||||||
|
|
||||||
std::string sdp_with_data = kSdpString;
|
|
||||||
sdp_with_data.append(kSdpRtpDataChannelString);
|
|
||||||
JsepSessionDescription jdesc_output(kDummyType);
|
|
||||||
|
|
||||||
// Deserialize
|
|
||||||
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output));
|
|
||||||
// Verify
|
|
||||||
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannels) {
|
||||||
bool use_sctpmap = true;
|
bool use_sctpmap = true;
|
||||||
AddSctpDataChannel(use_sctpmap);
|
AddSctpDataChannel(use_sctpmap);
|
||||||
@ -3088,8 +2986,9 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpmapAttribute) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, DeserializeSdpWithStrangeApplicationProtocolNames) {
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithStrangeApplicationProtocolNames) {
|
||||||
static const char* bad_strings[] = {"DTLS/SCTPRTP/", "obviously-bogus",
|
static const char* bad_strings[] = {
|
||||||
"UDP/TL/RTSP/SAVPF", "UDP/TL/RTSP/S"};
|
"DTLS/SCTPRTP/", "obviously-bogus", "UDP/TL/RTSP/SAVPF",
|
||||||
|
"UDP/TL/RTSP/S", "DTLS/SCTP/RTP/FOO", "obviously-bogus/RTP/"};
|
||||||
for (auto proto : bad_strings) {
|
for (auto proto : bad_strings) {
|
||||||
std::string sdp_with_data = kSdpString;
|
std::string sdp_with_data = kSdpString;
|
||||||
sdp_with_data.append("m=application 9 ");
|
sdp_with_data.append("m=application 9 ");
|
||||||
@ -3099,18 +2998,6 @@ TEST_F(WebRtcSdpTest, DeserializeSdpWithStrangeApplicationProtocolNames) {
|
|||||||
EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output))
|
EXPECT_FALSE(SdpDeserialize(sdp_with_data, &jdesc_output))
|
||||||
<< "Parsing should have failed on " << proto;
|
<< "Parsing should have failed on " << proto;
|
||||||
}
|
}
|
||||||
// The following strings are strange, but acceptable as RTP.
|
|
||||||
static const char* weird_strings[] = {"DTLS/SCTP/RTP/FOO",
|
|
||||||
"obviously-bogus/RTP/"};
|
|
||||||
for (auto proto : weird_strings) {
|
|
||||||
std::string sdp_with_data = kSdpString;
|
|
||||||
sdp_with_data.append("m=application 9 ");
|
|
||||||
sdp_with_data.append(proto);
|
|
||||||
sdp_with_data.append(" 47\r\n");
|
|
||||||
JsepSessionDescription jdesc_output(kDummyType);
|
|
||||||
EXPECT_TRUE(SdpDeserialize(sdp_with_data, &jdesc_output))
|
|
||||||
<< "Parsing should have succeeded on " << proto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For crbug/344475.
|
// For crbug/344475.
|
||||||
@ -3168,21 +3055,6 @@ TEST_F(WebRtcSdpTest,
|
|||||||
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
EXPECT_TRUE(CompareSessionDescription(jdesc, jdesc_output));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, DeserializeSdpWithRtpDataChannelsAndBandwidth) {
|
|
||||||
// We want to test that deserializing data content limits bandwidth
|
|
||||||
// settings (it should never be greater than the default).
|
|
||||||
// This should prevent someone from using unlimited data bandwidth through
|
|
||||||
// JS and "breaking the Internet".
|
|
||||||
// See: https://code.google.com/p/chromium/issues/detail?id=280726
|
|
||||||
std::string sdp_with_bandwidth = kSdpString;
|
|
||||||
sdp_with_bandwidth.append(kSdpRtpDataChannelString);
|
|
||||||
InjectAfter("a=mid:data_content_name\r\n", "b=AS:100\r\n",
|
|
||||||
&sdp_with_bandwidth);
|
|
||||||
JsepSessionDescription jdesc_with_bandwidth(kDummyType);
|
|
||||||
|
|
||||||
EXPECT_FALSE(SdpDeserialize(sdp_with_bandwidth, &jdesc_with_bandwidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
|
TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelsAndBandwidth) {
|
||||||
bool use_sctpmap = true;
|
bool use_sctpmap = true;
|
||||||
AddSctpDataChannel(use_sctpmap);
|
AddSctpDataChannel(use_sctpmap);
|
||||||
|
|||||||
@ -40,8 +40,14 @@ class FakeSctpTransport : public cricket::SctpTransportInternal {
|
|||||||
int max_message_size() const { return max_message_size_; }
|
int max_message_size() const { return max_message_size_; }
|
||||||
absl::optional<int> max_outbound_streams() const { return absl::nullopt; }
|
absl::optional<int> max_outbound_streams() const { return absl::nullopt; }
|
||||||
absl::optional<int> max_inbound_streams() const { return absl::nullopt; }
|
absl::optional<int> max_inbound_streams() const { return absl::nullopt; }
|
||||||
int local_port() const { return *local_port_; }
|
int local_port() const {
|
||||||
int remote_port() const { return *remote_port_; }
|
RTC_DCHECK(local_port_);
|
||||||
|
return *local_port_;
|
||||||
|
}
|
||||||
|
int remote_port() const {
|
||||||
|
RTC_DCHECK(remote_port_);
|
||||||
|
return *remote_port_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
absl::optional<int> local_port_;
|
absl::optional<int> local_port_;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user