pRevert 5371 "Revert 5367 "Update talk to 59410372.""
> Revert 5367 "Update talk to 59410372." > > > Update talk to 59410372. > > > > R=jiayl@webrtc.org, wu@webrtc.org > > > > Review URL: https://webrtc-codereview.appspot.com/6929004 > > TBR=mallinath@webrtc.org > > Review URL: https://webrtc-codereview.appspot.com/6999004 TBR=henrika@webrtc.org Review URL: https://webrtc-codereview.appspot.com/7109004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5381 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -29,9 +29,9 @@
|
||||
#include <string>
|
||||
|
||||
#include "talk/app/webrtc/mediastreamprovider.h"
|
||||
#include "talk/app/webrtc/sctputils.h"
|
||||
#include "talk/base/logging.h"
|
||||
#include "talk/base/refcount.h"
|
||||
#include "talk/media/sctp/sctputils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@@ -46,7 +46,7 @@ talk_base::scoped_refptr<DataChannel> DataChannel::Create(
|
||||
DataChannelProviderInterface* provider,
|
||||
cricket::DataChannelType dct,
|
||||
const std::string& label,
|
||||
const DataChannelInit* config) {
|
||||
const InternalDataChannelInit& config) {
|
||||
talk_base::scoped_refptr<DataChannel> channel(
|
||||
new talk_base::RefCountedObject<DataChannel>(provider, dct, label));
|
||||
if (!channel->Init(config)) {
|
||||
@@ -62,39 +62,40 @@ DataChannel::DataChannel(
|
||||
: label_(label),
|
||||
observer_(NULL),
|
||||
state_(kConnecting),
|
||||
was_ever_writable_(false),
|
||||
connected_to_provider_(false),
|
||||
data_channel_type_(dct),
|
||||
provider_(provider),
|
||||
waiting_for_open_ack_(false),
|
||||
was_ever_writable_(false),
|
||||
connected_to_provider_(false),
|
||||
send_ssrc_set_(false),
|
||||
send_ssrc_(0),
|
||||
receive_ssrc_set_(false),
|
||||
send_ssrc_(0),
|
||||
receive_ssrc_(0) {
|
||||
}
|
||||
|
||||
bool DataChannel::Init(const DataChannelInit* config) {
|
||||
bool DataChannel::Init(const InternalDataChannelInit& config) {
|
||||
if (data_channel_type_ == cricket::DCT_RTP &&
|
||||
(config->reliable ||
|
||||
config->id != -1 ||
|
||||
config->maxRetransmits != -1 ||
|
||||
config->maxRetransmitTime != -1)) {
|
||||
(config.reliable ||
|
||||
config.id != -1 ||
|
||||
config.maxRetransmits != -1 ||
|
||||
config.maxRetransmitTime != -1)) {
|
||||
LOG(LS_ERROR) << "Failed to initialize the RTP data channel due to "
|
||||
<< "invalid DataChannelInit.";
|
||||
return false;
|
||||
} else if (data_channel_type_ == cricket::DCT_SCTP) {
|
||||
if (config->id < -1 ||
|
||||
config->maxRetransmits < -1 ||
|
||||
config->maxRetransmitTime < -1) {
|
||||
if (config.id < -1 ||
|
||||
config.maxRetransmits < -1 ||
|
||||
config.maxRetransmitTime < -1) {
|
||||
LOG(LS_ERROR) << "Failed to initialize the SCTP data channel due to "
|
||||
<< "invalid DataChannelInit.";
|
||||
return false;
|
||||
}
|
||||
if (config->maxRetransmits != -1 && config->maxRetransmitTime != -1) {
|
||||
if (config.maxRetransmits != -1 && config.maxRetransmitTime != -1) {
|
||||
LOG(LS_ERROR) <<
|
||||
"maxRetransmits and maxRetransmitTime should not be both set.";
|
||||
return false;
|
||||
}
|
||||
config_ = *config;
|
||||
config_ = config;
|
||||
|
||||
// Try to connect to the transport in case the transport channel already
|
||||
// exists.
|
||||
@@ -197,9 +198,44 @@ bool DataChannel::SendOpenMessage(const talk_base::Buffer* raw_buffer) {
|
||||
|
||||
cricket::SendDataResult send_result;
|
||||
bool retval = provider_->SendData(send_params, *buffer, &send_result);
|
||||
if (!retval && send_result == cricket::SDR_BLOCK) {
|
||||
if (retval) {
|
||||
LOG(LS_INFO) << "Sent OPEN message on channel " << config_.id;
|
||||
// Send data as ordered before we receive any mesage from the remote peer
|
||||
// to make sure the remote peer will not receive any data before it receives
|
||||
// the OPEN message.
|
||||
waiting_for_open_ack_ = true;
|
||||
} else if (send_result == cricket::SDR_BLOCK) {
|
||||
// Link is congested. Queue for later.
|
||||
QueueControl(buffer.release());
|
||||
} else {
|
||||
LOG(LS_ERROR) << "Failed to send OPEN message with result "
|
||||
<< send_result << " on channel " << config_.id;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool DataChannel::SendOpenAckMessage(const talk_base::Buffer* raw_buffer) {
|
||||
ASSERT(data_channel_type_ == cricket::DCT_SCTP &&
|
||||
was_ever_writable_ &&
|
||||
config_.id >= 0);
|
||||
|
||||
talk_base::scoped_ptr<const talk_base::Buffer> buffer(raw_buffer);
|
||||
|
||||
cricket::SendDataParams send_params;
|
||||
send_params.ssrc = config_.id;
|
||||
send_params.ordered = config_.ordered;
|
||||
send_params.type = cricket::DMT_CONTROL;
|
||||
|
||||
cricket::SendDataResult send_result;
|
||||
bool retval = provider_->SendData(send_params, *buffer, &send_result);
|
||||
if (retval) {
|
||||
LOG(LS_INFO) << "Sent OPEN_ACK message on channel " << config_.id;
|
||||
} else if (send_result == cricket::SDR_BLOCK) {
|
||||
// Link is congested. Queue for later.
|
||||
QueueControl(buffer.release());
|
||||
} else {
|
||||
LOG(LS_ERROR) << "Failed to send OPEN_ACK message with result "
|
||||
<< send_result << " on channel " << config_.id;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -254,6 +290,35 @@ void DataChannel::OnDataReceived(cricket::DataChannel* channel,
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.type == cricket::DMT_CONTROL) {
|
||||
ASSERT(data_channel_type_ == cricket::DCT_SCTP);
|
||||
if (!waiting_for_open_ack_) {
|
||||
// Ignore it if we are not expecting an ACK message.
|
||||
LOG(LS_WARNING) << "DataChannel received unexpected CONTROL message, "
|
||||
<< "sid = " << params.ssrc;
|
||||
return;
|
||||
}
|
||||
if (ParseDataChannelOpenAckMessage(payload)) {
|
||||
// We can send unordered as soon as we receive the ACK message.
|
||||
waiting_for_open_ack_ = false;
|
||||
LOG(LS_INFO) << "DataChannel received OPEN_ACK message, sid = "
|
||||
<< params.ssrc;
|
||||
} else {
|
||||
LOG(LS_WARNING) << "DataChannel failed to parse OPEN_ACK message, sid = "
|
||||
<< params.ssrc;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(params.type == cricket::DMT_BINARY ||
|
||||
params.type == cricket::DMT_TEXT);
|
||||
|
||||
LOG(LS_VERBOSE) << "DataChannel received DATA message, sid = " << params.ssrc;
|
||||
// We can send unordered as soon as we receive any DATA message since the
|
||||
// remote side must have received the OPEN (and old clients do not send
|
||||
// OPEN_ACK).
|
||||
waiting_for_open_ack_ = false;
|
||||
|
||||
bool binary = (params.type == cricket::DMT_BINARY);
|
||||
talk_base::scoped_ptr<DataBuffer> buffer(new DataBuffer(payload, binary));
|
||||
if (was_ever_writable_ && observer_) {
|
||||
@@ -279,14 +344,17 @@ void DataChannel::OnChannelReady(bool writable) {
|
||||
if (!was_ever_writable_) {
|
||||
was_ever_writable_ = true;
|
||||
|
||||
if (data_channel_type_ == cricket::DCT_SCTP && !config_.negotiated) {
|
||||
talk_base::Buffer* payload = new talk_base::Buffer;
|
||||
if (!cricket::WriteDataChannelOpenMessage(label_, config_, payload)) {
|
||||
// TODO(jiayl): close the data channel on this error.
|
||||
LOG(LS_ERROR) << "Could not write data channel OPEN message";
|
||||
return;
|
||||
if (data_channel_type_ == cricket::DCT_SCTP) {
|
||||
if (config_.open_handshake_role == InternalDataChannelInit::kOpener) {
|
||||
talk_base::Buffer* payload = new talk_base::Buffer;
|
||||
WriteDataChannelOpenMessage(label_, config_, payload);
|
||||
SendOpenMessage(payload);
|
||||
} else if (config_.open_handshake_role ==
|
||||
InternalDataChannelInit::kAcker) {
|
||||
talk_base::Buffer* payload = new talk_base::Buffer;
|
||||
WriteDataChannelOpenAckMessage(payload);
|
||||
SendOpenAckMessage(payload);
|
||||
}
|
||||
SendOpenMessage(payload);
|
||||
}
|
||||
|
||||
UpdateState();
|
||||
@@ -412,7 +480,12 @@ void DataChannel::DeliverQueuedControlData() {
|
||||
while (!queued_control_data_.empty()) {
|
||||
const talk_base::Buffer* buf = queued_control_data_.front();
|
||||
queued_control_data_.pop();
|
||||
SendOpenMessage(buf);
|
||||
if (config_.open_handshake_role == InternalDataChannelInit::kOpener) {
|
||||
SendOpenMessage(buf);
|
||||
} else {
|
||||
ASSERT(config_.open_handshake_role == InternalDataChannelInit::kAcker);
|
||||
SendOpenAckMessage(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,6 +503,13 @@ bool DataChannel::InternalSendWithoutQueueing(
|
||||
|
||||
if (data_channel_type_ == cricket::DCT_SCTP) {
|
||||
send_params.ordered = config_.ordered;
|
||||
// Send as ordered if it is waiting for the OPEN_ACK message.
|
||||
if (waiting_for_open_ack_ && !config_.ordered) {
|
||||
send_params.ordered = true;
|
||||
LOG(LS_VERBOSE) << "Sending data as ordered for unordered DataChannel "
|
||||
<< "because the OPEN_ACK message has not been received.";
|
||||
}
|
||||
|
||||
send_params.max_rtx_count = config_.maxRetransmits;
|
||||
send_params.max_rtx_ms = config_.maxRetransmitTime;
|
||||
send_params.ssrc = config_.id;
|
||||
|
||||
@@ -64,6 +64,25 @@ class DataChannelProviderInterface {
|
||||
virtual ~DataChannelProviderInterface() {}
|
||||
};
|
||||
|
||||
struct InternalDataChannelInit : public DataChannelInit {
|
||||
enum OpenHandshakeRole {
|
||||
kOpener,
|
||||
kAcker,
|
||||
kNone
|
||||
};
|
||||
// The default role is kOpener because the default |negotiated| is false.
|
||||
InternalDataChannelInit() : open_handshake_role(kOpener) {}
|
||||
explicit InternalDataChannelInit(const DataChannelInit& base)
|
||||
: DataChannelInit(base), open_handshake_role(kOpener) {
|
||||
// If the channel is externally negotiated, do not send the OPEN message.
|
||||
if (base.negotiated) {
|
||||
open_handshake_role = kNone;
|
||||
}
|
||||
}
|
||||
|
||||
OpenHandshakeRole open_handshake_role;
|
||||
};
|
||||
|
||||
// DataChannel is a an implementation of the DataChannelInterface based on
|
||||
// libjingle's data engine. It provides an implementation of unreliable or
|
||||
// reliabledata channels. Currently this class is specifically designed to use
|
||||
@@ -87,7 +106,7 @@ class DataChannel : public DataChannelInterface,
|
||||
DataChannelProviderInterface* provider,
|
||||
cricket::DataChannelType dct,
|
||||
const std::string& label,
|
||||
const DataChannelInit* config);
|
||||
const InternalDataChannelInit& config);
|
||||
|
||||
virtual void RegisterObserver(DataChannelObserver* observer);
|
||||
virtual void UnregisterObserver();
|
||||
@@ -156,7 +175,7 @@ class DataChannel : public DataChannelInterface,
|
||||
virtual ~DataChannel();
|
||||
|
||||
private:
|
||||
bool Init(const DataChannelInit* config);
|
||||
bool Init(const InternalDataChannelInit& config);
|
||||
void DoClose();
|
||||
void UpdateState();
|
||||
void SetState(DataState state);
|
||||
@@ -172,19 +191,20 @@ class DataChannel : public DataChannelInterface,
|
||||
cricket::SendDataResult* send_result);
|
||||
bool QueueSendData(const DataBuffer& buffer);
|
||||
bool SendOpenMessage(const talk_base::Buffer* buffer);
|
||||
|
||||
bool SendOpenAckMessage(const talk_base::Buffer* buffer);
|
||||
|
||||
std::string label_;
|
||||
DataChannelInit config_;
|
||||
InternalDataChannelInit config_;
|
||||
DataChannelObserver* observer_;
|
||||
DataState state_;
|
||||
bool was_ever_writable_;
|
||||
bool connected_to_provider_;
|
||||
cricket::DataChannelType data_channel_type_;
|
||||
DataChannelProviderInterface* provider_;
|
||||
bool waiting_for_open_ack_;
|
||||
bool was_ever_writable_;
|
||||
bool connected_to_provider_;
|
||||
bool send_ssrc_set_;
|
||||
uint32 send_ssrc_;
|
||||
bool receive_ssrc_set_;
|
||||
uint32 send_ssrc_;
|
||||
uint32 receive_ssrc_;
|
||||
// Control messages that always have to get sent out before any queued
|
||||
// data.
|
||||
@@ -197,7 +217,7 @@ class DataChannelFactory {
|
||||
public:
|
||||
virtual talk_base::scoped_refptr<DataChannel> CreateDataChannel(
|
||||
const std::string& label,
|
||||
const DataChannelInit* config) = 0;
|
||||
const InternalDataChannelInit* config) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DataChannelFactory() {}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include "talk/app/webrtc/datachannel.h"
|
||||
#include "talk/app/webrtc/sctputils.h"
|
||||
#include "talk/app/webrtc/test/fakedatachannelprovider.h"
|
||||
#include "talk/base/gunit.h"
|
||||
#include "testing/base/public/gmock.h"
|
||||
@@ -42,7 +43,8 @@ class SctpDataChannelTest : public testing::Test {
|
||||
protected:
|
||||
SctpDataChannelTest()
|
||||
: webrtc_data_channel_(
|
||||
DataChannel::Create(&provider_, cricket::DCT_SCTP, "test", &init_)) {
|
||||
DataChannel::Create(
|
||||
&provider_, cricket::DCT_SCTP, "test", init_)) {
|
||||
}
|
||||
|
||||
void SetChannelReady() {
|
||||
@@ -59,7 +61,7 @@ class SctpDataChannelTest : public testing::Test {
|
||||
webrtc_data_channel_->RegisterObserver(observer_.get());
|
||||
}
|
||||
|
||||
webrtc::DataChannelInit init_;
|
||||
webrtc::InternalDataChannelInit init_;
|
||||
FakeDataChannelProvider provider_;
|
||||
talk_base::scoped_ptr<FakeDataChannelObserver> observer_;
|
||||
talk_base::scoped_refptr<DataChannel> webrtc_data_channel_;
|
||||
@@ -69,7 +71,7 @@ class SctpDataChannelTest : public testing::Test {
|
||||
TEST_F(SctpDataChannelTest, ConnectedToTransportOnCreated) {
|
||||
provider_.set_transport_available(true);
|
||||
talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
|
||||
&provider_, cricket::DCT_SCTP, "test1", &init_);
|
||||
&provider_, cricket::DCT_SCTP, "test1", init_);
|
||||
|
||||
EXPECT_TRUE(provider_.IsConnected(dc.get()));
|
||||
// The sid is not set yet, so it should not have added the streams.
|
||||
@@ -153,15 +155,69 @@ TEST_F(SctpDataChannelTest, OpenMessageSent) {
|
||||
// state.
|
||||
TEST_F(SctpDataChannelTest, LateCreatedChannelTransitionToOpen) {
|
||||
SetChannelReady();
|
||||
webrtc::DataChannelInit init;
|
||||
webrtc::InternalDataChannelInit init;
|
||||
init.id = 1;
|
||||
talk_base::scoped_refptr<DataChannel> dc =
|
||||
DataChannel::Create(&provider_, cricket::DCT_SCTP, "test1", &init);
|
||||
talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
|
||||
&provider_, cricket::DCT_SCTP, "test1", init);
|
||||
EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, dc->state());
|
||||
EXPECT_TRUE_WAIT(webrtc::DataChannelInterface::kOpen == dc->state(),
|
||||
1000);
|
||||
}
|
||||
|
||||
// Tests that an unordered DataChannel sends data as ordered until the OPEN_ACK
|
||||
// message is received.
|
||||
TEST_F(SctpDataChannelTest, SendUnorderedAfterReceivesOpenAck) {
|
||||
SetChannelReady();
|
||||
webrtc::InternalDataChannelInit init;
|
||||
init.id = 1;
|
||||
init.ordered = false;
|
||||
talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
|
||||
&provider_, cricket::DCT_SCTP, "test1", init);
|
||||
|
||||
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
|
||||
|
||||
// Sends a message and verifies it's ordered.
|
||||
webrtc::DataBuffer buffer("some data");
|
||||
ASSERT_TRUE(dc->Send(buffer));
|
||||
EXPECT_TRUE(provider_.last_send_data_params().ordered);
|
||||
|
||||
// Emulates receiving an OPEN_ACK message.
|
||||
cricket::ReceiveDataParams params;
|
||||
params.ssrc = init.id;
|
||||
params.type = cricket::DMT_CONTROL;
|
||||
talk_base::Buffer payload;
|
||||
webrtc::WriteDataChannelOpenAckMessage(&payload);
|
||||
dc->OnDataReceived(NULL, params, payload);
|
||||
|
||||
// Sends another message and verifies it's unordered.
|
||||
ASSERT_TRUE(dc->Send(buffer));
|
||||
EXPECT_FALSE(provider_.last_send_data_params().ordered);
|
||||
}
|
||||
|
||||
// Tests that an unordered DataChannel sends unordered data after any DATA
|
||||
// message is received.
|
||||
TEST_F(SctpDataChannelTest, SendUnorderedAfterReceiveData) {
|
||||
SetChannelReady();
|
||||
webrtc::InternalDataChannelInit init;
|
||||
init.id = 1;
|
||||
init.ordered = false;
|
||||
talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
|
||||
&provider_, cricket::DCT_SCTP, "test1", init);
|
||||
|
||||
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
|
||||
|
||||
// Emulates receiving a DATA message.
|
||||
cricket::ReceiveDataParams params;
|
||||
params.ssrc = init.id;
|
||||
params.type = cricket::DMT_TEXT;
|
||||
webrtc::DataBuffer buffer("data");
|
||||
dc->OnDataReceived(NULL, params, buffer.data);
|
||||
|
||||
// Sends a message and verifies it's unordered.
|
||||
ASSERT_TRUE(dc->Send(buffer));
|
||||
EXPECT_FALSE(provider_.last_send_data_params().ordered);
|
||||
}
|
||||
|
||||
// Tests that messages are sent with the right ssrc.
|
||||
TEST_F(SctpDataChannelTest, SendDataSsrc) {
|
||||
webrtc_data_channel_->SetSctpSid(1);
|
||||
@@ -199,3 +255,50 @@ TEST_F(SctpDataChannelTest, ReceiveDataWithValidSsrc) {
|
||||
|
||||
webrtc_data_channel_->OnDataReceived(NULL, params, buffer.data);
|
||||
}
|
||||
|
||||
// Tests that no CONTROL message is sent if the datachannel is negotiated and
|
||||
// not created from an OPEN message.
|
||||
TEST_F(SctpDataChannelTest, NoMsgSentIfNegotiatedAndNotFromOpenMsg) {
|
||||
webrtc::InternalDataChannelInit config;
|
||||
config.id = 1;
|
||||
config.negotiated = true;
|
||||
config.open_handshake_role = webrtc::InternalDataChannelInit::kNone;
|
||||
|
||||
SetChannelReady();
|
||||
talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
|
||||
&provider_, cricket::DCT_SCTP, "test1", config);
|
||||
|
||||
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
|
||||
EXPECT_EQ(0U, provider_.last_send_data_params().ssrc);
|
||||
}
|
||||
|
||||
// Tests that OPEN_ACK message is sent if the datachannel is created from an
|
||||
// OPEN message.
|
||||
TEST_F(SctpDataChannelTest, OpenAckSentIfCreatedFromOpenMessage) {
|
||||
webrtc::InternalDataChannelInit config;
|
||||
config.id = 1;
|
||||
config.negotiated = true;
|
||||
config.open_handshake_role = webrtc::InternalDataChannelInit::kAcker;
|
||||
|
||||
SetChannelReady();
|
||||
talk_base::scoped_refptr<DataChannel> dc = DataChannel::Create(
|
||||
&provider_, cricket::DCT_SCTP, "test1", config);
|
||||
|
||||
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, dc->state(), 1000);
|
||||
|
||||
EXPECT_EQ(static_cast<unsigned int>(config.id),
|
||||
provider_.last_send_data_params().ssrc);
|
||||
EXPECT_EQ(cricket::DMT_CONTROL, provider_.last_send_data_params().type);
|
||||
}
|
||||
|
||||
// Tests the OPEN_ACK role assigned by InternalDataChannelInit.
|
||||
TEST_F(SctpDataChannelTest, OpenAckRoleInitialization) {
|
||||
webrtc::InternalDataChannelInit init;
|
||||
EXPECT_EQ(webrtc::InternalDataChannelInit::kOpener, init.open_handshake_role);
|
||||
EXPECT_FALSE(init.negotiated);
|
||||
|
||||
webrtc::DataChannelInit base;
|
||||
base.negotiated = true;
|
||||
webrtc::InternalDataChannelInit init2(base);
|
||||
EXPECT_EQ(webrtc::InternalDataChannelInit::kNone, init2.open_handshake_role);
|
||||
}
|
||||
|
||||
@@ -37,24 +37,6 @@ using webrtc::MediaSourceInterface;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Constraint keys.
|
||||
// They are declared as static members in mediaconstraintsinterface.h
|
||||
const char MediaConstraintsInterface::kEchoCancellation[] =
|
||||
"googEchoCancellation";
|
||||
const char MediaConstraintsInterface::kExperimentalEchoCancellation[] =
|
||||
"googEchoCancellation2";
|
||||
const char MediaConstraintsInterface::kAutoGainControl[] =
|
||||
"googAutoGainControl";
|
||||
const char MediaConstraintsInterface::kExperimentalAutoGainControl[] =
|
||||
"googAutoGainControl2";
|
||||
const char MediaConstraintsInterface::kNoiseSuppression[] =
|
||||
"googNoiseSuppression";
|
||||
const char MediaConstraintsInterface::kHighpassFilter[] =
|
||||
"googHighpassFilter";
|
||||
const char MediaConstraintsInterface::kTypingNoiseDetection[] =
|
||||
"googTypingNoiseDetection";
|
||||
const char MediaConstraintsInterface::kAudioMirroring[] = "googAudioMirroring";
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert constraints to audio options. Return false if constraints are
|
||||
|
||||
@@ -34,6 +34,64 @@ namespace webrtc {
|
||||
const char MediaConstraintsInterface::kValueTrue[] = "true";
|
||||
const char MediaConstraintsInterface::kValueFalse[] = "false";
|
||||
|
||||
// Constraints declared as static members in mediastreaminterface.h
|
||||
// Specified by draft-alvestrand-constraints-resolution-00b
|
||||
const char MediaConstraintsInterface::kMinAspectRatio[] = "minAspectRatio";
|
||||
const char MediaConstraintsInterface::kMaxAspectRatio[] = "maxAspectRatio";
|
||||
const char MediaConstraintsInterface::kMaxWidth[] = "maxWidth";
|
||||
const char MediaConstraintsInterface::kMinWidth[] = "minWidth";
|
||||
const char MediaConstraintsInterface::kMaxHeight[] = "maxHeight";
|
||||
const char MediaConstraintsInterface::kMinHeight[] = "minHeight";
|
||||
const char MediaConstraintsInterface::kMaxFrameRate[] = "maxFrameRate";
|
||||
const char MediaConstraintsInterface::kMinFrameRate[] = "minFrameRate";
|
||||
|
||||
// Audio constraints.
|
||||
const char MediaConstraintsInterface::kEchoCancellation[] =
|
||||
"googEchoCancellation";
|
||||
const char MediaConstraintsInterface::kExperimentalEchoCancellation[] =
|
||||
"googEchoCancellation2";
|
||||
const char MediaConstraintsInterface::kAutoGainControl[] =
|
||||
"googAutoGainControl";
|
||||
const char MediaConstraintsInterface::kExperimentalAutoGainControl[] =
|
||||
"googAutoGainControl2";
|
||||
const char MediaConstraintsInterface::kNoiseSuppression[] =
|
||||
"googNoiseSuppression";
|
||||
const char MediaConstraintsInterface::kHighpassFilter[] =
|
||||
"googHighpassFilter";
|
||||
const char MediaConstraintsInterface::kTypingNoiseDetection[] =
|
||||
"googTypingNoiseDetection";
|
||||
const char MediaConstraintsInterface::kAudioMirroring[] = "googAudioMirroring";
|
||||
|
||||
// Google-specific constraint keys for a local video source (getUserMedia).
|
||||
const char MediaConstraintsInterface::kNoiseReduction[] = "googNoiseReduction";
|
||||
const char MediaConstraintsInterface::kLeakyBucket[] = "googLeakyBucket";
|
||||
const char MediaConstraintsInterface::kTemporalLayeredScreencast[] =
|
||||
"googTemporalLayeredScreencast";
|
||||
// TODO(ronghuawu): Remove once cpu overuse detection is stable.
|
||||
const char MediaConstraintsInterface::kCpuOveruseDetection[] =
|
||||
"googCpuOveruseDetection";
|
||||
|
||||
// Constraint keys for CreateOffer / CreateAnswer defined in W3C specification.
|
||||
const char MediaConstraintsInterface::kOfferToReceiveAudio[] =
|
||||
"OfferToReceiveAudio";
|
||||
const char MediaConstraintsInterface::kOfferToReceiveVideo[] =
|
||||
"OfferToReceiveVideo";
|
||||
const char MediaConstraintsInterface::kVoiceActivityDetection[] =
|
||||
"VoiceActivityDetection";
|
||||
const char MediaConstraintsInterface::kIceRestart[] =
|
||||
"IceRestart";
|
||||
// Google specific constraint for BUNDLE enable/disable.
|
||||
const char MediaConstraintsInterface::kUseRtpMux[] =
|
||||
"googUseRtpMUX";
|
||||
|
||||
// Below constraints should be used during PeerConnection construction.
|
||||
const char MediaConstraintsInterface::kEnableDtlsSrtp[] =
|
||||
"DtlsSrtpKeyAgreement";
|
||||
const char MediaConstraintsInterface::kEnableRtpDataChannels[] =
|
||||
"RtpDataChannels";
|
||||
const char MediaConstraintsInterface::kEnableDscp[] = "googDscp";
|
||||
const char MediaConstraintsInterface::kEnableIPv6[] = "googIPv6";
|
||||
|
||||
// Set |value| to the value associated with the first appearance of |key|, or
|
||||
// return false if |key| is not found.
|
||||
bool MediaConstraintsInterface::Constraints::FindFirst(
|
||||
|
||||
@@ -107,11 +107,10 @@ class MediaConstraintsInterface {
|
||||
static const char kEnableDtlsSrtp[]; // Enable DTLS-SRTP
|
||||
// Temporary pseudo-constraints used to enable DataChannels
|
||||
static const char kEnableRtpDataChannels[]; // Enable RTP DataChannels
|
||||
// TODO(perkj): Remove kEnableSctpDataChannels once Chrome use
|
||||
// PeerConnectionFactory::SetOptions.
|
||||
static const char kEnableSctpDataChannels[]; // Enable SCTP DataChannels
|
||||
// Temporary pseudo-constraint for enabling DSCP through JS.
|
||||
static const char kEnableDscp[];
|
||||
// Constraint to enable IPv6 through JS.
|
||||
static const char kEnableIPv6[];
|
||||
|
||||
// The prefix of internal-only constraints whose JS set values should be
|
||||
// stripped by Chrome before passed down to Libjingle.
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "talk/app/webrtc/mediaconstraintsinterface.h"
|
||||
#include "talk/app/webrtc/mediastreamtrackproxy.h"
|
||||
#include "talk/app/webrtc/remotevideocapturer.h"
|
||||
#include "talk/app/webrtc/sctputils.h"
|
||||
#include "talk/app/webrtc/videosource.h"
|
||||
#include "talk/app/webrtc/videotrack.h"
|
||||
#include "talk/base/bytebuffer.h"
|
||||
@@ -49,18 +50,6 @@ namespace webrtc {
|
||||
using talk_base::scoped_ptr;
|
||||
using talk_base::scoped_refptr;
|
||||
|
||||
// Supported MediaConstraints.
|
||||
const char MediaConstraintsInterface::kOfferToReceiveAudio[] =
|
||||
"OfferToReceiveAudio";
|
||||
const char MediaConstraintsInterface::kOfferToReceiveVideo[] =
|
||||
"OfferToReceiveVideo";
|
||||
const char MediaConstraintsInterface::kIceRestart[] =
|
||||
"IceRestart";
|
||||
const char MediaConstraintsInterface::kUseRtpMux[] =
|
||||
"googUseRtpMUX";
|
||||
const char MediaConstraintsInterface::kVoiceActivityDetection[] =
|
||||
"VoiceActivityDetection";
|
||||
|
||||
static bool ParseConstraints(
|
||||
const MediaConstraintsInterface* constraints,
|
||||
cricket::MediaSessionOptions* options, bool is_answer) {
|
||||
@@ -261,13 +250,24 @@ bool MediaStreamSignaling::AddDataChannel(DataChannel* data_channel) {
|
||||
}
|
||||
|
||||
bool MediaStreamSignaling::AddDataChannelFromOpenMessage(
|
||||
const std::string& label,
|
||||
const DataChannelInit& config) {
|
||||
const cricket::ReceiveDataParams& params,
|
||||
const talk_base::Buffer& payload) {
|
||||
if (!data_channel_factory_) {
|
||||
LOG(LS_WARNING) << "Remote peer requested a DataChannel but DataChannels "
|
||||
<< "are not supported.";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string label;
|
||||
InternalDataChannelInit config;
|
||||
config.id = params.ssrc;
|
||||
if (!ParseDataChannelOpenMessage(payload, &label, &config)) {
|
||||
LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
|
||||
<< params.ssrc;
|
||||
return false;
|
||||
}
|
||||
config.open_handshake_role = InternalDataChannelInit::kAcker;
|
||||
|
||||
scoped_refptr<DataChannel> channel(
|
||||
data_channel_factory_->CreateDataChannel(label, &config));
|
||||
if (!channel.get()) {
|
||||
|
||||
@@ -194,8 +194,8 @@ class MediaStreamSignaling {
|
||||
// be offered in a SessionDescription.
|
||||
bool AddDataChannel(DataChannel* data_channel);
|
||||
// After we receive an OPEN message, create a data channel and add it.
|
||||
bool AddDataChannelFromOpenMessage(
|
||||
const std::string& label, const DataChannelInit& config);
|
||||
bool AddDataChannelFromOpenMessage(const cricket::ReceiveDataParams& params,
|
||||
const talk_base::Buffer& payload);
|
||||
|
||||
// Returns a MediaSessionOptions struct with options decided by |constraints|,
|
||||
// the local MediaStreams and DataChannels.
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "talk/app/webrtc/audiotrack.h"
|
||||
#include "talk/app/webrtc/mediastream.h"
|
||||
#include "talk/app/webrtc/mediastreamsignaling.h"
|
||||
#include "talk/app/webrtc/sctputils.h"
|
||||
#include "talk/app/webrtc/streamcollection.h"
|
||||
#include "talk/app/webrtc/test/fakeconstraints.h"
|
||||
#include "talk/app/webrtc/test/fakedatachannelprovider.h"
|
||||
@@ -246,13 +247,19 @@ class FakeDataChannelFactory : public webrtc::DataChannelFactory {
|
||||
|
||||
virtual talk_base::scoped_refptr<webrtc::DataChannel> CreateDataChannel(
|
||||
const std::string& label,
|
||||
const webrtc::DataChannelInit* config) {
|
||||
return webrtc::DataChannel::Create(provider_, type_, label, config);
|
||||
const webrtc::InternalDataChannelInit* config) {
|
||||
last_init_ = *config;
|
||||
return webrtc::DataChannel::Create(provider_, type_, label, *config);
|
||||
}
|
||||
|
||||
const webrtc::InternalDataChannelInit& last_init() const {
|
||||
return last_init_;
|
||||
}
|
||||
|
||||
private:
|
||||
FakeDataChannelProvider* provider_;
|
||||
cricket::DataChannelType type_;
|
||||
webrtc::InternalDataChannelInit last_init_;
|
||||
};
|
||||
|
||||
class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
|
||||
@@ -528,11 +535,11 @@ class MediaStreamSignalingTest: public testing::Test {
|
||||
|
||||
talk_base::scoped_refptr<webrtc::DataChannel> AddDataChannel(
|
||||
cricket::DataChannelType type, const std::string& label, int id) {
|
||||
webrtc::DataChannelInit config;
|
||||
webrtc::InternalDataChannelInit config;
|
||||
config.id = id;
|
||||
talk_base::scoped_refptr<webrtc::DataChannel> data_channel(
|
||||
webrtc::DataChannel::Create(
|
||||
data_channel_provider_.get(), type, label, &config));
|
||||
data_channel_provider_.get(), type, label, config));
|
||||
EXPECT_TRUE(data_channel.get() != NULL);
|
||||
EXPECT_TRUE(signaling_->AddDataChannel(data_channel.get()));
|
||||
return data_channel;
|
||||
@@ -1078,10 +1085,10 @@ TEST_F(MediaStreamSignalingTest, SctpIdAllocationNoReuse) {
|
||||
TEST_F(MediaStreamSignalingTest, RtpDuplicatedLabelNotAllowed) {
|
||||
AddDataChannel(cricket::DCT_RTP, "a", -1);
|
||||
|
||||
webrtc::DataChannelInit config;
|
||||
webrtc::InternalDataChannelInit config;
|
||||
talk_base::scoped_refptr<webrtc::DataChannel> data_channel =
|
||||
webrtc::DataChannel::Create(
|
||||
data_channel_provider_.get(), cricket::DCT_RTP, "a", &config);
|
||||
data_channel_provider_.get(), cricket::DCT_RTP, "a", config);
|
||||
ASSERT_TRUE(data_channel.get() != NULL);
|
||||
EXPECT_FALSE(signaling_->AddDataChannel(data_channel.get()));
|
||||
}
|
||||
@@ -1092,6 +1099,25 @@ TEST_F(MediaStreamSignalingTest, SctpDuplicatedLabelAllowed) {
|
||||
AddDataChannel(cricket::DCT_SCTP, "a", -1);
|
||||
}
|
||||
|
||||
// Verifies the correct configuration is used to create DataChannel from an OPEN
|
||||
// message.
|
||||
TEST_F(MediaStreamSignalingTest, CreateDataChannelFromOpenMessage) {
|
||||
FakeDataChannelFactory fake_factory(data_channel_provider_.get(),
|
||||
cricket::DCT_SCTP);
|
||||
signaling_->SetDataChannelFactory(&fake_factory);
|
||||
webrtc::DataChannelInit config;
|
||||
config.id = 1;
|
||||
talk_base::Buffer payload;
|
||||
webrtc::WriteDataChannelOpenMessage("a", config, &payload);
|
||||
cricket::ReceiveDataParams params;
|
||||
params.ssrc = config.id;
|
||||
EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage(params, payload));
|
||||
EXPECT_EQ(config.id, fake_factory.last_init().id);
|
||||
EXPECT_FALSE(fake_factory.last_init().negotiated);
|
||||
EXPECT_EQ(webrtc::InternalDataChannelInit::kAcker,
|
||||
fake_factory.last_init().open_handshake_role);
|
||||
}
|
||||
|
||||
// Verifies that duplicated label from OPEN message is allowed.
|
||||
TEST_F(MediaStreamSignalingTest, DuplicatedLabelFromOpenMessageAllowed) {
|
||||
AddDataChannel(cricket::DCT_SCTP, "a", -1);
|
||||
@@ -1101,5 +1127,9 @@ TEST_F(MediaStreamSignalingTest, DuplicatedLabelFromOpenMessageAllowed) {
|
||||
signaling_->SetDataChannelFactory(&fake_factory);
|
||||
webrtc::DataChannelInit config;
|
||||
config.id = 0;
|
||||
EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage("a", config));
|
||||
talk_base::Buffer payload;
|
||||
webrtc::WriteDataChannelOpenMessage("a", config, &payload);
|
||||
cricket::ReceiveDataParams params;
|
||||
params.ssrc = config.id;
|
||||
EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage(params, payload));
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "talk/app/webrtc/dtmfsender.h"
|
||||
#include "talk/app/webrtc/jsepicecandidate.h"
|
||||
#include "talk/app/webrtc/jsepsessiondescription.h"
|
||||
#include "talk/app/webrtc/mediaconstraintsinterface.h"
|
||||
#include "talk/app/webrtc/mediastreamhandler.h"
|
||||
#include "talk/app/webrtc/streamcollection.h"
|
||||
#include "talk/base/logging.h"
|
||||
@@ -359,11 +360,21 @@ bool PeerConnection::DoInitialize(
|
||||
observer_ = observer;
|
||||
port_allocator_.reset(
|
||||
allocator_factory->CreatePortAllocator(stun_config, turn_config));
|
||||
|
||||
// To handle both internal and externally created port allocator, we will
|
||||
// enable BUNDLE here. Also enabling TURN and disable legacy relay service.
|
||||
port_allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE |
|
||||
cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
|
||||
cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
|
||||
// enable BUNDLE here.
|
||||
int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE |
|
||||
cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
|
||||
cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
|
||||
bool value;
|
||||
if (FindConstraint(
|
||||
constraints,
|
||||
MediaConstraintsInterface::kEnableIPv6,
|
||||
&value, NULL) && value) {
|
||||
portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
|
||||
}
|
||||
|
||||
port_allocator_->set_flags(portallocator_flags);
|
||||
// No step delay is used while allocating ports.
|
||||
port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
|
||||
|
||||
@@ -485,8 +496,12 @@ talk_base::scoped_refptr<DataChannelInterface>
|
||||
PeerConnection::CreateDataChannel(
|
||||
const std::string& label,
|
||||
const DataChannelInit* config) {
|
||||
talk_base::scoped_ptr<InternalDataChannelInit> internal_config;
|
||||
if (config) {
|
||||
internal_config.reset(new InternalDataChannelInit(*config));
|
||||
}
|
||||
talk_base::scoped_refptr<DataChannelInterface> channel(
|
||||
session_->CreateDataChannel(label, config));
|
||||
session_->CreateDataChannel(label, internal_config.get()));
|
||||
if (!channel.get())
|
||||
return NULL;
|
||||
|
||||
|
||||
194
talk/app/webrtc/sctputils.cc
Normal file
194
talk/app/webrtc/sctputils.cc
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/app/webrtc/sctputils.h"
|
||||
|
||||
#include "talk/base/buffer.h"
|
||||
#include "talk/base/bytebuffer.h"
|
||||
#include "talk/base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Format defined at
|
||||
// http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-01#section
|
||||
|
||||
static const uint8 DATA_CHANNEL_OPEN_MESSAGE_TYPE = 0x03;
|
||||
static const uint8 DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE = 0x02;
|
||||
|
||||
enum DataChannelOpenMessageChannelType {
|
||||
DCOMCT_ORDERED_RELIABLE = 0x00,
|
||||
DCOMCT_ORDERED_PARTIAL_RTXS = 0x01,
|
||||
DCOMCT_ORDERED_PARTIAL_TIME = 0x02,
|
||||
DCOMCT_UNORDERED_RELIABLE = 0x80,
|
||||
DCOMCT_UNORDERED_PARTIAL_RTXS = 0x81,
|
||||
DCOMCT_UNORDERED_PARTIAL_TIME = 0x82,
|
||||
};
|
||||
|
||||
bool ParseDataChannelOpenMessage(const talk_base::Buffer& payload,
|
||||
std::string* label,
|
||||
DataChannelInit* config) {
|
||||
// Format defined at
|
||||
// http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
|
||||
|
||||
talk_base::ByteBuffer buffer(payload.data(), payload.length());
|
||||
|
||||
uint8 message_type;
|
||||
if (!buffer.ReadUInt8(&message_type)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN message type.";
|
||||
return false;
|
||||
}
|
||||
if (message_type != DATA_CHANNEL_OPEN_MESSAGE_TYPE) {
|
||||
LOG(LS_WARNING) << "Data Channel OPEN message of unexpected type: "
|
||||
<< message_type;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 channel_type;
|
||||
if (!buffer.ReadUInt8(&channel_type)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN message channel type.";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16 priority;
|
||||
if (!buffer.ReadUInt16(&priority)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN message reliabilility prioirty.";
|
||||
return false;
|
||||
}
|
||||
uint32 reliability_param;
|
||||
if (!buffer.ReadUInt32(&reliability_param)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN message reliabilility param.";
|
||||
return false;
|
||||
}
|
||||
uint16 label_length;
|
||||
if (!buffer.ReadUInt16(&label_length)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN message label length.";
|
||||
return false;
|
||||
}
|
||||
uint16 protocol_length;
|
||||
if (!buffer.ReadUInt16(&protocol_length)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN message protocol length.";
|
||||
return false;
|
||||
}
|
||||
if (!buffer.ReadString(label, (size_t) label_length)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN message label";
|
||||
return false;
|
||||
}
|
||||
if (!buffer.ReadString(&config->protocol, protocol_length)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN message protocol.";
|
||||
return false;
|
||||
}
|
||||
|
||||
config->ordered = true;
|
||||
switch (channel_type) {
|
||||
case DCOMCT_UNORDERED_RELIABLE:
|
||||
case DCOMCT_UNORDERED_PARTIAL_RTXS:
|
||||
case DCOMCT_UNORDERED_PARTIAL_TIME:
|
||||
config->ordered = false;
|
||||
}
|
||||
|
||||
config->maxRetransmits = -1;
|
||||
config->maxRetransmitTime = -1;
|
||||
switch (channel_type) {
|
||||
case DCOMCT_ORDERED_PARTIAL_RTXS:
|
||||
case DCOMCT_UNORDERED_PARTIAL_RTXS:
|
||||
config->maxRetransmits = reliability_param;
|
||||
break;
|
||||
case DCOMCT_ORDERED_PARTIAL_TIME:
|
||||
case DCOMCT_UNORDERED_PARTIAL_TIME:
|
||||
config->maxRetransmitTime = reliability_param;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseDataChannelOpenAckMessage(const talk_base::Buffer& payload) {
|
||||
talk_base::ByteBuffer buffer(payload.data(), payload.length());
|
||||
|
||||
uint8 message_type;
|
||||
if (!buffer.ReadUInt8(&message_type)) {
|
||||
LOG(LS_WARNING) << "Could not read OPEN_ACK message type.";
|
||||
return false;
|
||||
}
|
||||
if (message_type != DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE) {
|
||||
LOG(LS_WARNING) << "Data Channel OPEN_ACK message of unexpected type: "
|
||||
<< message_type;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteDataChannelOpenMessage(const std::string& label,
|
||||
const DataChannelInit& config,
|
||||
talk_base::Buffer* payload) {
|
||||
// Format defined at
|
||||
// http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1
|
||||
uint8 channel_type = 0;
|
||||
uint32 reliability_param = 0;
|
||||
uint16 priority = 0;
|
||||
if (config.ordered) {
|
||||
if (config.maxRetransmits > -1) {
|
||||
channel_type = DCOMCT_ORDERED_PARTIAL_RTXS;
|
||||
reliability_param = config.maxRetransmits;
|
||||
} else if (config.maxRetransmitTime > -1) {
|
||||
channel_type = DCOMCT_ORDERED_PARTIAL_TIME;
|
||||
reliability_param = config.maxRetransmitTime;
|
||||
} else {
|
||||
channel_type = DCOMCT_ORDERED_RELIABLE;
|
||||
}
|
||||
} else {
|
||||
if (config.maxRetransmits > -1) {
|
||||
channel_type = DCOMCT_UNORDERED_PARTIAL_RTXS;
|
||||
reliability_param = config.maxRetransmits;
|
||||
} else if (config.maxRetransmitTime > -1) {
|
||||
channel_type = DCOMCT_UNORDERED_PARTIAL_TIME;
|
||||
reliability_param = config.maxRetransmitTime;
|
||||
} else {
|
||||
channel_type = DCOMCT_UNORDERED_RELIABLE;
|
||||
}
|
||||
}
|
||||
|
||||
talk_base::ByteBuffer buffer(
|
||||
NULL, 20 + label.length() + config.protocol.length(),
|
||||
talk_base::ByteBuffer::ORDER_NETWORK);
|
||||
buffer.WriteUInt8(DATA_CHANNEL_OPEN_MESSAGE_TYPE);
|
||||
buffer.WriteUInt8(channel_type);
|
||||
buffer.WriteUInt16(priority);
|
||||
buffer.WriteUInt32(reliability_param);
|
||||
buffer.WriteUInt16(static_cast<uint16>(label.length()));
|
||||
buffer.WriteUInt16(static_cast<uint16>(config.protocol.length()));
|
||||
buffer.WriteString(label);
|
||||
buffer.WriteString(config.protocol);
|
||||
payload->SetData(buffer.Data(), buffer.Length());
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteDataChannelOpenAckMessage(talk_base::Buffer* payload) {
|
||||
talk_base::ByteBuffer buffer(talk_base::ByteBuffer::ORDER_NETWORK);
|
||||
buffer.WriteUInt8(DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE);
|
||||
payload->SetData(buffer.Data(), buffer.Length());
|
||||
}
|
||||
} // namespace webrtc
|
||||
55
talk/app/webrtc/sctputils.h
Normal file
55
talk/app/webrtc/sctputils.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TALK_APP_WEBRTC_SCTPUTILS_H_
|
||||
#define TALK_APP_WEBRTC_SCTPUTILS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "talk/app/webrtc/datachannelinterface.h"
|
||||
|
||||
namespace talk_base {
|
||||
class Buffer;
|
||||
} // namespace talk_base
|
||||
|
||||
namespace webrtc {
|
||||
struct DataChannelInit;
|
||||
|
||||
bool ParseDataChannelOpenMessage(const talk_base::Buffer& payload,
|
||||
std::string* label,
|
||||
DataChannelInit* config);
|
||||
|
||||
bool ParseDataChannelOpenAckMessage(const talk_base::Buffer& payload);
|
||||
|
||||
bool WriteDataChannelOpenMessage(const std::string& label,
|
||||
const DataChannelInit& config,
|
||||
talk_base::Buffer* payload);
|
||||
|
||||
void WriteDataChannelOpenAckMessage(talk_base::Buffer* payload);
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TALK_APP_WEBRTC_SCTPUTILS_H_
|
||||
161
talk/app/webrtc/sctputils_unittest.cc
Normal file
161
talk/app/webrtc/sctputils_unittest.cc
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2013 Google Inc
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/base/bytebuffer.h"
|
||||
#include "talk/base/gunit.h"
|
||||
#include "talk/app/webrtc/sctputils.h"
|
||||
|
||||
class SctpUtilsTest : public testing::Test {
|
||||
public:
|
||||
void VerifyOpenMessageFormat(const talk_base::Buffer& packet,
|
||||
const std::string& label,
|
||||
const webrtc::DataChannelInit& config) {
|
||||
uint8 message_type;
|
||||
uint8 channel_type;
|
||||
uint32 reliability;
|
||||
uint16 priority;
|
||||
uint16 label_length;
|
||||
uint16 protocol_length;
|
||||
|
||||
talk_base::ByteBuffer buffer(packet.data(), packet.length());
|
||||
ASSERT_TRUE(buffer.ReadUInt8(&message_type));
|
||||
EXPECT_EQ(0x03, message_type);
|
||||
|
||||
ASSERT_TRUE(buffer.ReadUInt8(&channel_type));
|
||||
if (config.ordered) {
|
||||
EXPECT_EQ(config.maxRetransmits > -1 ?
|
||||
0x01 : (config.maxRetransmitTime > -1 ? 0x02 : 0),
|
||||
channel_type);
|
||||
} else {
|
||||
EXPECT_EQ(config.maxRetransmits > -1 ?
|
||||
0x81 : (config.maxRetransmitTime > -1 ? 0x82 : 0x80),
|
||||
channel_type);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(buffer.ReadUInt16(&priority));
|
||||
|
||||
ASSERT_TRUE(buffer.ReadUInt32(&reliability));
|
||||
if (config.maxRetransmits > -1 || config.maxRetransmitTime > -1) {
|
||||
EXPECT_EQ(config.maxRetransmits > -1 ?
|
||||
config.maxRetransmits : config.maxRetransmitTime,
|
||||
static_cast<int>(reliability));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(buffer.ReadUInt16(&label_length));
|
||||
ASSERT_TRUE(buffer.ReadUInt16(&protocol_length));
|
||||
EXPECT_EQ(label.size(), label_length);
|
||||
EXPECT_EQ(config.protocol.size(), protocol_length);
|
||||
|
||||
std::string label_output;
|
||||
ASSERT_TRUE(buffer.ReadString(&label_output, label_length));
|
||||
EXPECT_EQ(label, label_output);
|
||||
std::string protocol_output;
|
||||
ASSERT_TRUE(buffer.ReadString(&protocol_output, protocol_length));
|
||||
EXPECT_EQ(config.protocol, protocol_output);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SctpUtilsTest, WriteParseOpenMessageWithOrderedReliable) {
|
||||
webrtc::DataChannelInit config;
|
||||
std::string label = "abc";
|
||||
config.protocol = "y";
|
||||
|
||||
talk_base::Buffer packet;
|
||||
ASSERT_TRUE(webrtc::WriteDataChannelOpenMessage(label, config, &packet));
|
||||
|
||||
VerifyOpenMessageFormat(packet, label, config);
|
||||
|
||||
std::string output_label;
|
||||
webrtc::DataChannelInit output_config;
|
||||
ASSERT_TRUE(webrtc::ParseDataChannelOpenMessage(
|
||||
packet, &output_label, &output_config));
|
||||
|
||||
EXPECT_EQ(label, output_label);
|
||||
EXPECT_EQ(config.protocol, output_config.protocol);
|
||||
EXPECT_EQ(config.ordered, output_config.ordered);
|
||||
EXPECT_EQ(config.maxRetransmitTime, output_config.maxRetransmitTime);
|
||||
EXPECT_EQ(config.maxRetransmits, output_config.maxRetransmits);
|
||||
}
|
||||
|
||||
TEST_F(SctpUtilsTest, WriteParseOpenMessageWithMaxRetransmitTime) {
|
||||
webrtc::DataChannelInit config;
|
||||
std::string label = "abc";
|
||||
config.ordered = false;
|
||||
config.maxRetransmitTime = 10;
|
||||
config.protocol = "y";
|
||||
|
||||
talk_base::Buffer packet;
|
||||
ASSERT_TRUE(webrtc::WriteDataChannelOpenMessage(label, config, &packet));
|
||||
|
||||
VerifyOpenMessageFormat(packet, label, config);
|
||||
|
||||
std::string output_label;
|
||||
webrtc::DataChannelInit output_config;
|
||||
ASSERT_TRUE(webrtc::ParseDataChannelOpenMessage(
|
||||
packet, &output_label, &output_config));
|
||||
|
||||
EXPECT_EQ(label, output_label);
|
||||
EXPECT_EQ(config.protocol, output_config.protocol);
|
||||
EXPECT_EQ(config.ordered, output_config.ordered);
|
||||
EXPECT_EQ(config.maxRetransmitTime, output_config.maxRetransmitTime);
|
||||
EXPECT_EQ(-1, output_config.maxRetransmits);
|
||||
}
|
||||
|
||||
TEST_F(SctpUtilsTest, WriteParseOpenMessageWithMaxRetransmits) {
|
||||
webrtc::DataChannelInit config;
|
||||
std::string label = "abc";
|
||||
config.maxRetransmits = 10;
|
||||
config.protocol = "y";
|
||||
|
||||
talk_base::Buffer packet;
|
||||
ASSERT_TRUE(webrtc::WriteDataChannelOpenMessage(label, config, &packet));
|
||||
|
||||
VerifyOpenMessageFormat(packet, label, config);
|
||||
|
||||
std::string output_label;
|
||||
webrtc::DataChannelInit output_config;
|
||||
ASSERT_TRUE(webrtc::ParseDataChannelOpenMessage(
|
||||
packet, &output_label, &output_config));
|
||||
|
||||
EXPECT_EQ(label, output_label);
|
||||
EXPECT_EQ(config.protocol, output_config.protocol);
|
||||
EXPECT_EQ(config.ordered, output_config.ordered);
|
||||
EXPECT_EQ(config.maxRetransmits, output_config.maxRetransmits);
|
||||
EXPECT_EQ(-1, output_config.maxRetransmitTime);
|
||||
}
|
||||
|
||||
TEST_F(SctpUtilsTest, WriteParseAckMessage) {
|
||||
talk_base::Buffer packet;
|
||||
webrtc::WriteDataChannelOpenAckMessage(&packet);
|
||||
|
||||
uint8 message_type;
|
||||
talk_base::ByteBuffer buffer(packet.data(), packet.length());
|
||||
ASSERT_TRUE(buffer.ReadUInt8(&message_type));
|
||||
EXPECT_EQ(0x02, message_type);
|
||||
|
||||
EXPECT_TRUE(webrtc::ParseDataChannelOpenAckMessage(packet));
|
||||
}
|
||||
@@ -36,30 +36,6 @@ using cricket::CaptureState;
|
||||
using webrtc::MediaConstraintsInterface;
|
||||
using webrtc::MediaSourceInterface;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Constraint keys. Specified by draft-alvestrand-constraints-resolution-00b
|
||||
// They are declared as static members in mediastreaminterface.h
|
||||
const char MediaConstraintsInterface::kMinAspectRatio[] = "minAspectRatio";
|
||||
const char MediaConstraintsInterface::kMaxAspectRatio[] = "maxAspectRatio";
|
||||
const char MediaConstraintsInterface::kMaxWidth[] = "maxWidth";
|
||||
const char MediaConstraintsInterface::kMinWidth[] = "minWidth";
|
||||
const char MediaConstraintsInterface::kMaxHeight[] = "maxHeight";
|
||||
const char MediaConstraintsInterface::kMinHeight[] = "minHeight";
|
||||
const char MediaConstraintsInterface::kMaxFrameRate[] = "maxFrameRate";
|
||||
const char MediaConstraintsInterface::kMinFrameRate[] = "minFrameRate";
|
||||
|
||||
// Google-specific keys
|
||||
const char MediaConstraintsInterface::kNoiseReduction[] = "googNoiseReduction";
|
||||
const char MediaConstraintsInterface::kLeakyBucket[] = "googLeakyBucket";
|
||||
const char MediaConstraintsInterface::kTemporalLayeredScreencast[] =
|
||||
"googTemporalLayeredScreencast";
|
||||
// TODO(ronghuawu): Remove once cpu overuse detection is stable.
|
||||
const char MediaConstraintsInterface::kCpuOveruseDetection[] =
|
||||
"googCpuOveruseDetection";
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
namespace {
|
||||
|
||||
const double kRoundingTruncation = 0.0005;
|
||||
|
||||
@@ -1172,6 +1172,7 @@ class WebRtcSdpTest : public testing::Test {
|
||||
"m=video 3457 RTP/SAVPF 101\r\n"
|
||||
"a=rtpmap:101 VP8/90000\r\n"
|
||||
"a=rtcp-fb:101 nack\r\n"
|
||||
"a=rtcp-fb:101 nack pli\r\n"
|
||||
"a=rtcp-fb:101 goog-remb\r\n"
|
||||
"a=rtcp-fb:101 ccm fir\r\n";
|
||||
std::ostringstream os;
|
||||
@@ -1203,6 +1204,9 @@ class WebRtcSdpTest : public testing::Test {
|
||||
EXPECT_TRUE(vp8.HasFeedbackParam(
|
||||
cricket::FeedbackParam(cricket::kRtcpFbParamNack,
|
||||
cricket::kParamValueEmpty)));
|
||||
EXPECT_TRUE(vp8.HasFeedbackParam(
|
||||
cricket::FeedbackParam(cricket::kRtcpFbParamNack,
|
||||
cricket::kRtcpFbNackParamPli)));
|
||||
EXPECT_TRUE(vp8.HasFeedbackParam(
|
||||
cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
|
||||
cricket::kParamValueEmpty)));
|
||||
@@ -1902,6 +1906,9 @@ TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
|
||||
// Missing space.
|
||||
const char kSdpInvalidLine6[] = "a=fingerprint:sha-1"
|
||||
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB";
|
||||
// MD5 is not allowed in fingerprints.
|
||||
const char kSdpInvalidLine7[] = "a=fingerprint:md5 "
|
||||
"4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B";
|
||||
|
||||
// Broken session description
|
||||
ReplaceAndTryToParse("v=", kSdpDestroyer);
|
||||
@@ -1925,6 +1932,7 @@ TEST_F(WebRtcSdpTest, DeserializeBrokenSdp) {
|
||||
ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine4);
|
||||
ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine5);
|
||||
ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine6);
|
||||
ReplaceAndTryToParse("a=sendrecv", kSdpInvalidLine7);
|
||||
}
|
||||
|
||||
TEST_F(WebRtcSdpTest, DeserializeSdpWithReorderedPltypes) {
|
||||
|
||||
@@ -54,23 +54,6 @@ using cricket::TransportInfo;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const char MediaConstraintsInterface::kInternalConstraintPrefix[] = "internal";
|
||||
|
||||
// Supported MediaConstraints.
|
||||
// DSCP constraints.
|
||||
const char MediaConstraintsInterface::kEnableDscp[] = "googDscp";
|
||||
// DTLS-SRTP pseudo-constraints.
|
||||
const char MediaConstraintsInterface::kEnableDtlsSrtp[] =
|
||||
"DtlsSrtpKeyAgreement";
|
||||
// DataChannel pseudo constraints.
|
||||
const char MediaConstraintsInterface::kEnableRtpDataChannels[] =
|
||||
"RtpDataChannels";
|
||||
// This constraint is for internal use only, representing the Chrome command
|
||||
// line flag. So it is prefixed with kInternalConstraintPrefix so JS values
|
||||
// will be removed.
|
||||
const char MediaConstraintsInterface::kEnableSctpDataChannels[] =
|
||||
"deprecatedSctpDataChannels";
|
||||
|
||||
// Error messages
|
||||
const char kSetLocalSdpFailed[] = "SetLocalDescription failed: ";
|
||||
const char kSetRemoteSdpFailed[] = "SetRemoteDescription failed: ";
|
||||
@@ -1022,7 +1005,7 @@ bool WebRtcSession::ReadyToSendData() const {
|
||||
|
||||
talk_base::scoped_refptr<DataChannel> WebRtcSession::CreateDataChannel(
|
||||
const std::string& label,
|
||||
const DataChannelInit* config) {
|
||||
const InternalDataChannelInit* config) {
|
||||
if (state() == STATE_RECEIVEDTERMINATE) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -1030,8 +1013,8 @@ talk_base::scoped_refptr<DataChannel> WebRtcSession::CreateDataChannel(
|
||||
LOG(LS_ERROR) << "CreateDataChannel: Data is not supported in this call.";
|
||||
return NULL;
|
||||
}
|
||||
DataChannelInit new_config = config ? (*config) : DataChannelInit();
|
||||
|
||||
InternalDataChannelInit new_config =
|
||||
config ? (*config) : InternalDataChannelInit();
|
||||
if (data_channel_type_ == cricket::DCT_SCTP) {
|
||||
if (new_config.id < 0) {
|
||||
talk_base::SSLRole role;
|
||||
@@ -1047,8 +1030,8 @@ talk_base::scoped_refptr<DataChannel> WebRtcSession::CreateDataChannel(
|
||||
}
|
||||
}
|
||||
|
||||
talk_base::scoped_refptr<DataChannel> channel(
|
||||
DataChannel::Create(this, data_channel_type_, label, &new_config));
|
||||
talk_base::scoped_refptr<DataChannel> channel(DataChannel::Create(
|
||||
this, data_channel_type_, label, new_config));
|
||||
if (channel && !mediastream_signaling_->AddDataChannel(channel))
|
||||
return NULL;
|
||||
|
||||
@@ -1398,8 +1381,8 @@ bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content) {
|
||||
}
|
||||
if (sctp) {
|
||||
mediastream_signaling_->OnDataTransportCreatedForSctp();
|
||||
data_channel_->SignalNewStreamReceived.connect(
|
||||
this, &WebRtcSession::OnNewDataChannelReceived);
|
||||
data_channel_->SignalDataReceived.connect(
|
||||
this, &WebRtcSession::OnDataChannelMessageReceived);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1417,14 +1400,17 @@ void WebRtcSession::CopySavedCandidates(
|
||||
saved_candidates_.clear();
|
||||
}
|
||||
|
||||
void WebRtcSession::OnNewDataChannelReceived(
|
||||
const std::string& label, const DataChannelInit& init) {
|
||||
void WebRtcSession::OnDataChannelMessageReceived(
|
||||
cricket::DataChannel* channel,
|
||||
const cricket::ReceiveDataParams& params,
|
||||
const talk_base::Buffer& payload) {
|
||||
ASSERT(data_channel_type_ == cricket::DCT_SCTP);
|
||||
if (!mediastream_signaling_->AddDataChannelFromOpenMessage(
|
||||
label, init)) {
|
||||
LOG(LS_WARNING) << "Failed to create data channel from OPEN message.";
|
||||
return;
|
||||
if (params.type == cricket::DMT_CONTROL &&
|
||||
mediastream_signaling_->IsSctpSidAvailable(params.ssrc)) {
|
||||
// Received CONTROL on unused sid, process as an OPEN message.
|
||||
mediastream_signaling_->AddDataChannelFromOpenMessage(params, payload);
|
||||
}
|
||||
// otherwise ignore the message.
|
||||
}
|
||||
|
||||
// Returns false if bundle is enabled and rtcp_mux is disabled.
|
||||
|
||||
@@ -195,9 +195,10 @@ class WebRtcSession : public cricket::BaseSession,
|
||||
virtual void RemoveSctpDataStream(uint32 sid) OVERRIDE;
|
||||
virtual bool ReadyToSendData() const OVERRIDE;
|
||||
|
||||
// Implements DataChannelFactory.
|
||||
talk_base::scoped_refptr<DataChannel> CreateDataChannel(
|
||||
const std::string& label,
|
||||
const DataChannelInit* config);
|
||||
const InternalDataChannelInit* config) OVERRIDE;
|
||||
|
||||
cricket::DataChannelType data_channel_type() const;
|
||||
|
||||
@@ -275,8 +276,11 @@ class WebRtcSession : public cricket::BaseSession,
|
||||
// The |saved_candidates_| will be cleared after this function call.
|
||||
void CopySavedCandidates(SessionDescriptionInterface* dest_desc);
|
||||
|
||||
void OnNewDataChannelReceived(const std::string& label,
|
||||
const DataChannelInit& init);
|
||||
// Listens to SCTP CONTROL messages on unused SIDs and process them as OPEN
|
||||
// messages.
|
||||
void OnDataChannelMessageReceived(cricket::DataChannel* channel,
|
||||
const cricket::ReceiveDataParams& params,
|
||||
const talk_base::Buffer& payload);
|
||||
|
||||
bool GetLocalTrackId(uint32 ssrc, std::string* track_id);
|
||||
bool GetRemoteTrackId(uint32 ssrc, std::string* track_id);
|
||||
|
||||
@@ -874,7 +874,7 @@ class WebRtcSessionTest : public testing::Test {
|
||||
}
|
||||
|
||||
void SetLocalDescriptionWithDataChannel() {
|
||||
webrtc::DataChannelInit dci;
|
||||
webrtc::InternalDataChannelInit dci;
|
||||
dci.reliable = false;
|
||||
session_->CreateDataChannel("datachannel", &dci);
|
||||
SessionDescriptionInterface* offer = CreateOffer(NULL);
|
||||
@@ -2675,7 +2675,7 @@ TEST_F(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) {
|
||||
|
||||
// TEST PLAN: Set the port number to something new, set it in the SDP,
|
||||
// and pass it all the way down.
|
||||
webrtc::DataChannelInit dci;
|
||||
webrtc::InternalDataChannelInit dci;
|
||||
dci.reliable = true;
|
||||
EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
|
||||
talk_base::scoped_refptr<webrtc::DataChannel> dc =
|
||||
|
||||
Reference in New Issue
Block a user