diff --git a/talk/app/webrtc/datachannel.cc b/talk/app/webrtc/datachannel.cc index 345cd5f10..497242422 100644 --- a/talk/app/webrtc/datachannel.cc +++ b/talk/app/webrtc/datachannel.cc @@ -34,7 +34,8 @@ namespace webrtc { -static size_t kMaxQueuedDataPackets = 100; +static size_t kMaxQueuedReceivedDataPackets = 100; +static size_t kMaxQueuedSendDataPackets = 100; talk_base::scoped_refptr DataChannel::Create( WebRtcSession* session, @@ -95,12 +96,13 @@ bool DataChannel::HasNegotiationCompleted() { } DataChannel::~DataChannel() { - ClearQueuedData(); + ClearQueuedReceivedData(); + ClearQueuedSendData(); } void DataChannel::RegisterObserver(DataChannelObserver* observer) { observer_ = observer; - DeliverQueuedData(); + DeliverQueuedReceivedData(); } void DataChannel::UnregisterObserver() { @@ -117,7 +119,13 @@ bool DataChannel::reliable() const { } uint64 DataChannel::buffered_amount() const { - return 0; + uint64 buffered_amount = 0; + for (std::deque::const_iterator it = queued_send_data_.begin(); + it != queued_send_data_.end(); + ++it) { + buffered_amount += (*it)->size(); + } + return buffered_amount; } void DataChannel::Close() { @@ -133,20 +141,22 @@ bool DataChannel::Send(const DataBuffer& buffer) { if (state_ != kOpen) { return false; } - cricket::SendDataParams send_params; - - send_params.ssrc = send_ssrc_; - if (session_->data_channel_type() == cricket::DCT_SCTP) { - send_params.ordered = config_.ordered; - send_params.max_rtx_count = config_.maxRetransmits; - send_params.max_rtx_ms = config_.maxRetransmitTime; + // If the queue is non-empty, we're waiting for SignalReadyToSend, + // so just add to the end of the queue and keep waiting. + if (!queued_send_data_.empty()) { + return QueueSendData(buffer); } - send_params.type = buffer.binary ? cricket::DMT_BINARY : cricket::DMT_TEXT; cricket::SendDataResult send_result; - // TODO(pthatcher): Use send_result.would_block for buffering. - return session_->data_channel()->SendData( - send_params, buffer.data, &send_result); + if (!InternalSendWithoutQueueing(buffer, &send_result)) { + if (send_result == cricket::SDR_BLOCK) { + return QueueSendData(buffer); + } + // Fail for other results. + // TODO(jiayl): We should close the data channel in this case. + return false; + } + return true; } void DataChannel::SetReceiveSsrc(uint32 receive_ssrc) { @@ -183,6 +193,43 @@ void DataChannel::OnDataEngineClose() { DoClose(); } +void DataChannel::OnDataReceived(cricket::DataChannel* channel, + const cricket::ReceiveDataParams& params, + const talk_base::Buffer& payload) { + if (params.ssrc != receive_ssrc_) { + return; + } + + bool binary = (params.type == cricket::DMT_BINARY); + talk_base::scoped_ptr buffer(new DataBuffer(payload, binary)); + if (was_ever_writable_ && observer_) { + observer_->OnMessage(*buffer.get()); + } else { + if (queued_received_data_.size() > kMaxQueuedReceivedDataPackets) { + // TODO(jiayl): We should close the data channel in this case. + LOG(LS_ERROR) + << "Queued received data exceeds the max number of packes."; + ClearQueuedReceivedData(); + } + queued_received_data_.push(buffer.release()); + } +} + +void DataChannel::OnChannelReady(bool writable) { + if (!writable) { + return; + } + // Update the readyState if the channel is writable for the first time; + // otherwise it means the channel was blocked for sending and now unblocked, + // so send the queued data now. + if (!was_ever_writable_) { + was_ever_writable_ = true; + UpdateState(); + } else if (state_ == kOpen) { + SendQueuedSendData(); + } +} + void DataChannel::DoClose() { receive_ssrc_set_ = false; send_ssrc_set_ = false; @@ -201,7 +248,7 @@ void DataChannel::UpdateState() { SetState(kOpen); // If we have received buffers before the channel got writable. // Deliver them now. - DeliverQueuedData(); + DeliverQueuedReceivedData(); } } break; @@ -249,47 +296,76 @@ void DataChannel::DisconnectFromDataSession() { data_session_ = NULL; } -void DataChannel::DeliverQueuedData() { - if (was_ever_writable_ && observer_) { - while (!queued_data_.empty()) { - DataBuffer* buffer = queued_data_.front(); - observer_->OnMessage(*buffer); - queued_data_.pop(); - delete buffer; - } +void DataChannel::DeliverQueuedReceivedData() { + if (!was_ever_writable_ || !observer_) { + return; } -} -void DataChannel::ClearQueuedData() { - while (!queued_data_.empty()) { - DataBuffer* buffer = queued_data_.front(); - queued_data_.pop(); + while (!queued_received_data_.empty()) { + DataBuffer* buffer = queued_received_data_.front(); + observer_->OnMessage(*buffer); + queued_received_data_.pop(); delete buffer; } } -void DataChannel::OnDataReceived(cricket::DataChannel* channel, - const cricket::ReceiveDataParams& params, - const talk_base::Buffer& payload) { - if (params.ssrc == receive_ssrc_) { - bool binary = false; - talk_base::scoped_ptr buffer(new DataBuffer(payload, binary)); - if (was_ever_writable_ && observer_) { - observer_->OnMessage(*buffer.get()); - } else { - if (queued_data_.size() > kMaxQueuedDataPackets) { - ClearQueuedData(); - } - queued_data_.push(buffer.release()); - } +void DataChannel::ClearQueuedReceivedData() { + while (!queued_received_data_.empty()) { + DataBuffer* buffer = queued_received_data_.front(); + queued_received_data_.pop(); + delete buffer; } } -void DataChannel::OnChannelReady(bool writable) { - if (!was_ever_writable_ && writable) { - was_ever_writable_ = true; - UpdateState(); +void DataChannel::SendQueuedSendData() { + if (!was_ever_writable_) { + return; } + + while (!queued_send_data_.empty()) { + DataBuffer* buffer = queued_send_data_.front(); + cricket::SendDataResult send_result; + if (!InternalSendWithoutQueueing(*buffer, &send_result)) { + LOG(LS_WARNING) << "SendQueuedSendData aborted due to send_result " + << send_result; + break; + } + queued_send_data_.pop_front(); + delete buffer; + } +} + +void DataChannel::ClearQueuedSendData() { + while (!queued_received_data_.empty()) { + DataBuffer* buffer = queued_received_data_.front(); + queued_received_data_.pop(); + delete buffer; + } +} + +bool DataChannel::InternalSendWithoutQueueing( + const DataBuffer& buffer, cricket::SendDataResult* send_result) { + cricket::SendDataParams send_params; + + send_params.ssrc = send_ssrc_; + if (session_->data_channel_type() == cricket::DCT_SCTP) { + send_params.ordered = config_.ordered; + send_params.max_rtx_count = config_.maxRetransmits; + send_params.max_rtx_ms = config_.maxRetransmitTime; + } + send_params.type = buffer.binary ? cricket::DMT_BINARY : cricket::DMT_TEXT; + + return session_->data_channel()->SendData(send_params, buffer.data, + send_result); +} + +bool DataChannel::QueueSendData(const DataBuffer& buffer) { + if (queued_send_data_.size() > kMaxQueuedSendDataPackets) { + LOG(LS_ERROR) << "Can't buffer any more data in the data channel."; + return false; + } + queued_send_data_.push_back(new DataBuffer(buffer)); + return true; } } // namespace webrtc diff --git a/talk/app/webrtc/datachannel.h b/talk/app/webrtc/datachannel.h index c79c491c9..440ee15ca 100644 --- a/talk/app/webrtc/datachannel.h +++ b/talk/app/webrtc/datachannel.h @@ -109,8 +109,13 @@ class DataChannel : public DataChannelInterface, void ConnectToDataSession(); void DisconnectFromDataSession(); bool IsConnectedToDataSession() { return data_session_ != NULL; } - void DeliverQueuedData(); - void ClearQueuedData(); + void DeliverQueuedReceivedData(); + void ClearQueuedReceivedData(); + void SendQueuedSendData(); + void ClearQueuedSendData(); + bool InternalSendWithoutQueueing(const DataBuffer& buffer, + cricket::SendDataResult* send_result); + bool QueueSendData(const DataBuffer& buffer); std::string label_; DataChannelInit config_; @@ -123,7 +128,8 @@ class DataChannel : public DataChannelInterface, uint32 send_ssrc_; bool receive_ssrc_set_; uint32 receive_ssrc_; - std::queue queued_data_; + std::queue queued_received_data_; + std::deque queued_send_data_; }; class DataChannelFactory { diff --git a/talk/app/webrtc/datachannel_unittest.cc b/talk/app/webrtc/datachannel_unittest.cc new file mode 100644 index 000000000..d3faf177a --- /dev/null +++ b/talk/app/webrtc/datachannel_unittest.cc @@ -0,0 +1,129 @@ +/* + * 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/datachannel.h" +#include "talk/app/webrtc/mediastreamsignaling.h" +#include "talk/app/webrtc/test/fakeconstraints.h" +#include "talk/app/webrtc/webrtcsession.h" +#include "talk/base/gunit.h" +#include "talk/media/base/fakemediaengine.h" +#include "talk/media/devices/fakedevicemanager.h" +#include "talk/session/media/channelmanager.h" + +using webrtc::MediaConstraintsInterface; + +const uint32 kFakeSsrc = 1; + +class SctpDataChannelTest : public testing::Test { + protected: + SctpDataChannelTest() + : media_engine_(new cricket::FakeMediaEngine), + data_engine_(new cricket::FakeDataEngine), + channel_manager_( + new cricket::ChannelManager(media_engine_, + data_engine_, + new cricket::FakeDeviceManager(), + new cricket::CaptureManager(), + talk_base::Thread::Current())), + session_(channel_manager_.get(), + talk_base::Thread::Current(), + talk_base::Thread::Current(), + NULL, + new webrtc::MediaStreamSignaling(talk_base::Thread::Current(), + NULL)), + webrtc_data_channel_(NULL) {} + + virtual void SetUp() { + if (!talk_base::SSLStreamAdapter::HaveDtlsSrtp()) { + return; + } + channel_manager_->Init(); + webrtc::FakeConstraints constraints; + constraints.AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, true); + constraints.AddMandatory(MediaConstraintsInterface::kEnableSctpDataChannels, + true); + ASSERT_TRUE(session_.Initialize(&constraints)); + webrtc::SessionDescriptionInterface* offer = session_.CreateOffer(NULL); + ASSERT_TRUE(offer != NULL); + ASSERT_TRUE(session_.SetLocalDescription(offer, NULL)); + + webrtc_data_channel_ = webrtc::DataChannel::Create(&session_, "test", NULL); + // Connect to the media channel. + webrtc_data_channel_->SetSendSsrc(kFakeSsrc); + webrtc_data_channel_->SetReceiveSsrc(kFakeSsrc); + + session_.data_channel()->SignalReadyToSendData(true); + } + + void SetSendBlocked(bool blocked) { + bool was_blocked = data_engine_->GetChannel(0)->is_send_blocked(); + data_engine_->GetChannel(0)->set_send_blocked(blocked); + if (!blocked && was_blocked) { + session_.data_channel()->SignalReadyToSendData(true); + } + } + + cricket::FakeMediaEngine* media_engine_; + cricket::FakeDataEngine* data_engine_; + talk_base::scoped_ptr channel_manager_; + webrtc::WebRtcSession session_; + talk_base::scoped_refptr webrtc_data_channel_; +}; + +// Tests that DataChannel::buffered_amount() is correct after the channel is +// blocked. +TEST_F(SctpDataChannelTest, BufferedAmountWhenBlocked) { + if (!talk_base::SSLStreamAdapter::HaveDtlsSrtp()) { + return; + } + webrtc::DataBuffer buffer("abcd"); + EXPECT_TRUE(webrtc_data_channel_->Send(buffer)); + + EXPECT_EQ(0U, webrtc_data_channel_->buffered_amount()); + + SetSendBlocked(true); + const int number_of_packets = 3; + for (int i = 0; i < number_of_packets; ++i) { + EXPECT_TRUE(webrtc_data_channel_->Send(buffer)); + } + EXPECT_EQ(buffer.data.length() * number_of_packets, + webrtc_data_channel_->buffered_amount()); +} + +// Tests that the queued data are sent when the channel transitions from blocked +// to unblocked. +TEST_F(SctpDataChannelTest, QueuedDataSentWhenUnblocked) { + if (!talk_base::SSLStreamAdapter::HaveDtlsSrtp()) { + return; + } + webrtc::DataBuffer buffer("abcd"); + SetSendBlocked(true); + EXPECT_TRUE(webrtc_data_channel_->Send(buffer)); + + SetSendBlocked(false); + EXPECT_EQ(0U, webrtc_data_channel_->buffered_amount()); +} diff --git a/talk/app/webrtc/datachannelinterface.h b/talk/app/webrtc/datachannelinterface.h index 6054e1be1..82d375c19 100644 --- a/talk/app/webrtc/datachannelinterface.h +++ b/talk/app/webrtc/datachannelinterface.h @@ -75,6 +75,8 @@ struct DataBuffer { : data(text.data(), text.length()), binary(false) { } + size_t size() const { return data.length(); } + talk_base::Buffer data; // Indicates if the received data contains UTF-8 or binary data. // Note that the upper layers are left to verify the UTF-8 encoding. diff --git a/talk/base/host.cc b/talk/base/host.cc deleted file mode 100644 index 7decc49e6..000000000 --- a/talk/base/host.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, 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/host.h" - -#ifdef POSIX -#include -#endif // POSIX - -#include - -namespace talk_base { - -std::string GetHostName() { - // TODO: fix or get rid of this -#if 0 - struct utsname nm; - if (uname(&nm) < 0) - FatalError("uname", LAST_SYSTEM_ERROR); - return std::string(nm.nodename); -#endif - return "cricket"; -} - -} // namespace talk_base diff --git a/talk/base/host.h b/talk/base/host.h deleted file mode 100644 index 8528240a2..000000000 --- a/talk/base/host.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, 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_BASE_HOST_H_ -#define TALK_BASE_HOST_H_ - -#include - -namespace talk_base { - -// Returns the name of the local host. -std::string GetHostName(); - -} // namespace talk_base - -#endif // TALK_BASE_HOST_H_ diff --git a/talk/base/host_unittest.cc b/talk/base/host_unittest.cc deleted file mode 100644 index aba87af8f..000000000 --- a/talk/base/host_unittest.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * libjingle - * Copyright 2004--2011, 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/gunit.h" -#include "talk/base/host.h" - -TEST(Host, GetHostName) { - EXPECT_NE("", talk_base::GetHostName()); -} diff --git a/talk/base/httpcommon.cc b/talk/base/httpcommon.cc index 458f2f9f8..ec7ffd288 100644 --- a/talk/base/httpcommon.cc +++ b/talk/base/httpcommon.cc @@ -528,11 +528,14 @@ HttpRequestData::formatLeader(char* buffer, size_t size) const { HttpError HttpRequestData::parseLeader(const char* line, size_t len) { - UNUSED(len); unsigned int vmajor, vminor; int vend, dstart, dend; - if ((sscanf(line, "%*s%n %n%*s%n HTTP/%u.%u", &vend, &dstart, &dend, - &vmajor, &vminor) != 2) + // sscanf isn't safe with strings that aren't null-terminated, and there is + // no guarantee that |line| is. Create a local copy that is null-terminated. + std::string line_str(line, len); + line = line_str.c_str(); + if ((sscanf(line, "%*s%n %n%*s%n HTTP/%u.%u", + &vend, &dstart, &dend, &vmajor, &vminor) != 2) || (vmajor != 1)) { return HE_PROTOCOL; } @@ -649,6 +652,10 @@ HttpResponseData::parseLeader(const char* line, size_t len) { size_t pos = 0; unsigned int vmajor, vminor, temp_scode; int temp_pos; + // sscanf isn't safe with strings that aren't null-terminated, and there is + // no guarantee that |line| is. Create a local copy that is null-terminated. + std::string line_str(line, len); + line = line_str.c_str(); if (sscanf(line, "HTTP %u%n", &temp_scode, &temp_pos) == 1) { // This server's response has no version. :( NOTE: This happens for every diff --git a/talk/base/nat_unittest.cc b/talk/base/nat_unittest.cc index 03170ca0e..97712352c 100644 --- a/talk/base/nat_unittest.cc +++ b/talk/base/nat_unittest.cc @@ -28,7 +28,6 @@ #include #include "talk/base/gunit.h" -#include "talk/base/host.h" #include "talk/base/logging.h" #include "talk/base/natserver.h" #include "talk/base/natsocketfactory.h" diff --git a/talk/base/network.cc b/talk/base/network.cc index 9351b873f..d6367c32b 100644 --- a/talk/base/network.cc +++ b/talk/base/network.cc @@ -53,7 +53,6 @@ #include #include -#include "talk/base/host.h" #include "talk/base/logging.h" #include "talk/base/scoped_ptr.h" #include "talk/base/socket.h" // includes something that makes windows happy @@ -174,8 +173,7 @@ void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks, } BasicNetworkManager::BasicNetworkManager() - : thread_(NULL), - start_count_(0) { + : thread_(NULL), sent_first_update_(false), start_count_(0) { } BasicNetworkManager::~BasicNetworkManager() { diff --git a/talk/base/testclient_unittest.cc b/talk/base/testclient_unittest.cc index 126923673..c1411f029 100644 --- a/talk/base/testclient_unittest.cc +++ b/talk/base/testclient_unittest.cc @@ -26,7 +26,6 @@ */ #include "talk/base/gunit.h" -#include "talk/base/host.h" #include "talk/base/nethelpers.h" #include "talk/base/physicalsocketserver.h" #include "talk/base/testclient.h" diff --git a/talk/base/thread_unittest.cc b/talk/base/thread_unittest.cc index 11b493da9..246faa4a5 100644 --- a/talk/base/thread_unittest.cc +++ b/talk/base/thread_unittest.cc @@ -28,7 +28,6 @@ #include "talk/base/asyncudpsocket.h" #include "talk/base/event.h" #include "talk/base/gunit.h" -#include "talk/base/host.h" #include "talk/base/physicalsocketserver.h" #include "talk/base/socketaddress.h" #include "talk/base/thread.h" diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp index 09e4316c1..0944f76b5 100755 --- a/talk/libjingle.gyp +++ b/talk/libjingle.gyp @@ -300,8 +300,6 @@ 'base/gunit_prod.h', 'base/helpers.cc', 'base/helpers.h', - 'base/host.cc', - 'base/host.h', 'base/httpbase.cc', 'base/httpbase.h', 'base/httpclient.cc', diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp index d248750d0..aba09ed57 100755 --- a/talk/libjingle_tests.gyp +++ b/talk/libjingle_tests.gyp @@ -121,7 +121,6 @@ 'base/filelock_unittest.cc', 'base/fileutils_unittest.cc', 'base/helpers_unittest.cc', - 'base/host_unittest.cc', 'base/httpbase_unittest.cc', 'base/httpcommon_unittest.cc', 'base/httpserver_unittest.cc', @@ -376,6 +375,7 @@ ], # TODO(ronghuawu): Reenable below unit tests that require gmock. 'sources': [ + 'app/webrtc/datachannel_unittest.cc', 'app/webrtc/dtmfsender_unittest.cc', 'app/webrtc/jsepsessiondescription_unittest.cc', 'app/webrtc/localaudiosource_unittest.cc', diff --git a/talk/media/base/capturemanager.cc b/talk/media/base/capturemanager.cc index 5705bcd66..85bfa54b8 100644 --- a/talk/media/base/capturemanager.cc +++ b/talk/media/base/capturemanager.cc @@ -145,12 +145,19 @@ int VideoCapturerState::DecCaptureStartRef() { } CaptureManager::~CaptureManager() { - while (!capture_states_.empty()) { - // There may have been multiple calls to StartVideoCapture which means that - // an equal number of calls to StopVideoCapture must be made. Note that - // StopVideoCapture will remove the element from |capture_states_| when a - // successfull stop has been made. - UnregisterVideoCapturer(capture_states_.begin()->second); + // Since we don't own any of the capturers, all capturers should have been + // cleaned up before we get here. In fact, in the normal shutdown sequence, + // all capturers *will* be shut down by now, so trying to stop them here + // will crash. If we're still tracking any, it's a dangling pointer. + if (!capture_states_.empty()) { + ASSERT(false && + "CaptureManager destructing while still tracking capturers!"); + // Delete remaining VideoCapturerStates, but don't touch the capturers. + do { + CaptureStates::iterator it = capture_states_.begin(); + delete it->second; + capture_states_.erase(it); + } while (!capture_states_.empty()); } } diff --git a/talk/media/base/capturemanager_unittest.cc b/talk/media/base/capturemanager_unittest.cc index e9d9cfb13..8025e56ce 100644 --- a/talk/media/base/capturemanager_unittest.cc +++ b/talk/media/base/capturemanager_unittest.cc @@ -180,6 +180,10 @@ TEST_F(CaptureManagerTest, KeepFirstResolutionLow) { EXPECT_TRUE(video_capturer_.CaptureFrame()); EXPECT_EQ(1, NumFramesRendered()); EXPECT_TRUE(WasRenderedResolution(format_qvga_)); + EXPECT_TRUE(capture_manager_.StopVideoCapture(&video_capturer_, + format_qvga_)); + EXPECT_TRUE(capture_manager_.StopVideoCapture(&video_capturer_, + format_vga_)); } // Ensure that the reference counting is working when multiple start and @@ -230,6 +234,8 @@ TEST_F(CaptureManagerTest, TestForceRestart) { EXPECT_TRUE(video_capturer_.CaptureFrame()); EXPECT_EQ(2, NumFramesRendered()); EXPECT_TRUE(WasRenderedResolution(format_vga_)); + EXPECT_TRUE(capture_manager_.StopVideoCapture(&video_capturer_, + format_vga_)); } TEST_F(CaptureManagerTest, TestRequestRestart) { @@ -248,4 +254,6 @@ TEST_F(CaptureManagerTest, TestRequestRestart) { EXPECT_TRUE(video_capturer_.CaptureFrame()); EXPECT_EQ(2, NumFramesRendered()); EXPECT_TRUE(WasRenderedResolution(format_vga_)); + EXPECT_TRUE(capture_manager_.StopVideoCapture(&video_capturer_, + format_qvga_)); } diff --git a/talk/media/base/fakemediaengine.h b/talk/media/base/fakemediaengine.h index 7f4c9e3ac..ded5698ba 100644 --- a/talk/media/base/fakemediaengine.h +++ b/talk/media/base/fakemediaengine.h @@ -599,7 +599,7 @@ class FakeSoundclipMedia : public SoundclipMedia { class FakeDataMediaChannel : public RtpHelper { public: explicit FakeDataMediaChannel(void* unused) - : auto_bandwidth_(false), max_bps_(-1) {} + : auto_bandwidth_(false), send_blocked_(false), max_bps_(-1) {} ~FakeDataMediaChannel() {} const std::vector& recv_codecs() const { return recv_codecs_; } const std::vector& send_codecs() const { return send_codecs_; } @@ -647,13 +647,20 @@ class FakeDataMediaChannel : public RtpHelper { virtual bool SendData(const SendDataParams& params, const talk_base::Buffer& payload, SendDataResult* result) { - last_sent_data_params_ = params; - last_sent_data_ = std::string(payload.data(), payload.length()); - return true; + if (send_blocked_) { + *result = SDR_BLOCK; + return false; + } else { + last_sent_data_params_ = params; + last_sent_data_ = std::string(payload.data(), payload.length()); + return true; + } } SendDataParams last_sent_data_params() { return last_sent_data_params_; } std::string last_sent_data() { return last_sent_data_; } + bool is_send_blocked() { return send_blocked_; } + void set_send_blocked(bool blocked) { send_blocked_ = blocked; } private: std::vector recv_codecs_; @@ -661,6 +668,7 @@ class FakeDataMediaChannel : public RtpHelper { SendDataParams last_sent_data_params_; std::string last_sent_data_; bool auto_bandwidth_; + bool send_blocked_; int max_bps_; }; diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h index 07d5f905a..a9e37781b 100644 --- a/talk/media/base/mediachannel.h +++ b/talk/media/base/mediachannel.h @@ -957,6 +957,9 @@ class DataMediaChannel : public MediaChannel { // Signal errors from MediaChannel. Arguments are: // ssrc(uint32), and error(DataMediaChannel::Error). sigslot::signal2 SignalMediaError; + // Signal when the media channel is ready to send the stream. Arguments are: + // writable(bool) + sigslot::signal1 SignalReadyToSend; }; } // namespace cricket diff --git a/talk/media/sctp/sctpdataengine.cc b/talk/media/sctp/sctpdataengine.cc index 7fcb2398e..71ef73c83 100644 --- a/talk/media/sctp/sctpdataengine.cc +++ b/talk/media/sctp/sctpdataengine.cc @@ -270,7 +270,8 @@ bool SctpDataMediaChannel::OpenSctpSocket() { // Subscribe to SCTP event notifications. int event_types[] = {SCTP_ASSOC_CHANGE, SCTP_PEER_ADDR_CHANGE, - SCTP_SEND_FAILED_EVENT}; + SCTP_SEND_FAILED_EVENT, + SCTP_SENDER_DRY_EVENT}; struct sctp_event event = {0}; event.se_assoc_id = SCTP_ALL_ASSOC; event.se_on = 1; @@ -479,11 +480,14 @@ bool SctpDataMediaChannel::SendData( static_cast(sizeof(sndinfo)), SCTP_SENDV_SNDINFO, 0); if (res < 0) { - LOG_ERRNO(LS_ERROR) << "ERROR:" << debug_name_ - << "SendData->(...): " - << " usrsctp_sendv: "; - // TODO(pthatcher): Make result SDR_BLOCK if the error is because - // it would block. + if (errno == EWOULDBLOCK) { + *result = SDR_BLOCK; + LOG(LS_INFO) << debug_name_ << "->SendData(...): EWOULDBLOCK returned"; + } else { + LOG_ERRNO(LS_ERROR) << "ERROR:" << debug_name_ + << "->SendData(...): " + << " usrsctp_sendv: "; + } return false; } if (result) { @@ -562,8 +566,7 @@ void SctpDataMediaChannel::OnDataFromSctpToChannel( } } -void SctpDataMediaChannel::OnNotificationFromSctp( - talk_base::Buffer* buffer) { +void SctpDataMediaChannel::OnNotificationFromSctp(talk_base::Buffer* buffer) { const sctp_notification& notification = reinterpret_cast(*buffer->data()); ASSERT(notification.sn_header.sn_length == buffer->length()); @@ -591,6 +594,7 @@ void SctpDataMediaChannel::OnNotificationFromSctp( break; case SCTP_SENDER_DRY_EVENT: LOG(LS_INFO) << "SCTP_SENDER_DRY_EVENT"; + SignalReadyToSend(true); break; // TODO(ldixon): Unblock after congestion. case SCTP_NOTIFICATIONS_STOPPED_EVENT: diff --git a/talk/media/sctp/sctpdataengine_unittest.cc b/talk/media/sctp/sctpdataengine_unittest.cc index 071fbbb02..2b8787f3a 100644 --- a/talk/media/sctp/sctpdataengine_unittest.cc +++ b/talk/media/sctp/sctpdataengine_unittest.cc @@ -137,6 +137,24 @@ class SctpFakeDataReceiver : public sigslot::has_slots<> { cricket::ReceiveDataParams last_params_; }; +class SignalReadyToSendObserver : public sigslot::has_slots<> { + public: + SignalReadyToSendObserver() : signaled_(false), writable_(false) {} + + void OnSignaled(bool writable) { + signaled_ = true; + writable_ = writable; + } + + bool IsSignaled(bool writable) { + return signaled_ && (writable_ == writable); + } + + private: + bool signaled_; + bool writable_; +}; + // SCTP Data Engine testing framework. class SctpDataMediaChannelTest : public testing::Test { protected: @@ -144,6 +162,42 @@ class SctpDataMediaChannelTest : public testing::Test { engine_.reset(new cricket::SctpDataEngine()); } + void SetupConnectedChannels() { + net1_.reset(new SctpFakeNetworkInterface(talk_base::Thread::Current())); + net2_.reset(new SctpFakeNetworkInterface(talk_base::Thread::Current())); + recv1_.reset(new SctpFakeDataReceiver()); + recv2_.reset(new SctpFakeDataReceiver()); + chan1_.reset(CreateChannel(net1_.get(), recv1_.get())); + chan1_->set_debug_name("chan1/connector"); + chan2_.reset(CreateChannel(net2_.get(), recv2_.get())); + chan2_->set_debug_name("chan2/listener"); + // Setup two connected channels ready to send and receive. + net1_->SetDestination(chan2_.get()); + net2_->SetDestination(chan1_.get()); + + LOG(LS_VERBOSE) << "Channel setup ----------------------------- "; + chan1_->AddSendStream(cricket::StreamParams::CreateLegacy(1)); + chan2_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)); + + chan2_->AddSendStream(cricket::StreamParams::CreateLegacy(2)); + chan1_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)); + + LOG(LS_VERBOSE) << "Connect the channels -----------------------------"; + // chan1 wants to setup a data connection. + chan1_->SetReceive(true); + // chan1 will have sent chan2 a request to setup a data connection. After + // chan2 accepts the offer, chan2 connects to chan1 with the following. + chan2_->SetReceive(true); + chan2_->SetSend(true); + // Makes sure that network packets are delivered and simulates a + // deterministic and realistic small timing delay between the SetSend calls. + ProcessMessagesUntilIdle(); + + // chan1 and chan2 are now connected so chan1 enables sending to complete + // the creation of the connection. + chan1_->SetSend(true); + } + cricket::SctpDataMediaChannel* CreateChannel( SctpFakeNetworkInterface* net, SctpFakeDataReceiver* recv) { cricket::SctpDataMediaChannel* channel = @@ -182,79 +236,78 @@ class SctpDataMediaChannelTest : public testing::Test { return !thread->IsQuitting(); } + cricket::SctpDataMediaChannel* channel1() { return chan1_.get(); } + cricket::SctpDataMediaChannel* channel2() { return chan2_.get(); } + SctpFakeDataReceiver* receiver1() { return recv1_.get(); } + SctpFakeDataReceiver* receiver2() { return recv2_.get(); } + private: talk_base::scoped_ptr engine_; + talk_base::scoped_ptr net1_; + talk_base::scoped_ptr net2_; + talk_base::scoped_ptr recv1_; + talk_base::scoped_ptr recv2_; + talk_base::scoped_ptr chan1_; + talk_base::scoped_ptr chan2_; }; +// Verifies that SignalReadyToSend is fired. +TEST_F(SctpDataMediaChannelTest, SignalReadyToSend) { + SetupConnectedChannels(); + + SignalReadyToSendObserver signal_observer_1; + SignalReadyToSendObserver signal_observer_2; + + channel1()->SignalReadyToSend.connect(&signal_observer_1, + &SignalReadyToSendObserver::OnSignaled); + channel2()->SignalReadyToSend.connect(&signal_observer_2, + &SignalReadyToSendObserver::OnSignaled); + + cricket::SendDataResult result; + ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result)); + EXPECT_EQ(cricket::SDR_SUCCESS, result); + EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000); + ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result)); + EXPECT_EQ(cricket::SDR_SUCCESS, result); + EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000); + + EXPECT_TRUE_WAIT(signal_observer_1.IsSignaled(true), 1000); + EXPECT_TRUE_WAIT(signal_observer_2.IsSignaled(true), 1000); +} + TEST_F(SctpDataMediaChannelTest, SendData) { - talk_base::scoped_ptr net1( - new SctpFakeNetworkInterface(talk_base::Thread::Current())); - talk_base::scoped_ptr net2( - new SctpFakeNetworkInterface(talk_base::Thread::Current())); - talk_base::scoped_ptr recv1( - new SctpFakeDataReceiver()); - talk_base::scoped_ptr recv2( - new SctpFakeDataReceiver()); - talk_base::scoped_ptr chan1( - CreateChannel(net1.get(), recv1.get())); - chan1->set_debug_name("chan1/connector"); - talk_base::scoped_ptr chan2( - CreateChannel(net2.get(), recv2.get())); - chan2->set_debug_name("chan2/listener"); - - net1->SetDestination(chan2.get()); - net2->SetDestination(chan1.get()); - - LOG(LS_VERBOSE) << "Channel setup ----------------------------- "; - chan1->AddSendStream(cricket::StreamParams::CreateLegacy(1)); - chan2->AddRecvStream(cricket::StreamParams::CreateLegacy(1)); - - chan2->AddSendStream(cricket::StreamParams::CreateLegacy(2)); - chan1->AddRecvStream(cricket::StreamParams::CreateLegacy(2)); - - LOG(LS_VERBOSE) << "Connect the channels -----------------------------"; - // chan1 wants to setup a data connection. - chan1->SetReceive(true); - // chan1 will have sent chan2 a request to setup a data connection. After - // chan2 accepts the offer, chan2 connects to chan1 with the following. - chan2->SetReceive(true); - chan2->SetSend(true); - // Makes sure that network packets are delivered and simulates a - // deterministic and realistic small timing delay between the SetSend calls. - ProcessMessagesUntilIdle(); - - // chan1 and chan2 are now connected so chan1 enables sending to complete - // the creation of the connection. - chan1->SetSend(true); + SetupConnectedChannels(); cricket::SendDataResult result; LOG(LS_VERBOSE) << "chan1 sending: 'hello?' -----------------------------"; - ASSERT_TRUE(SendData(chan1.get(), 1, "hello?", &result)); + ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result)); EXPECT_EQ(cricket::SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(recv2.get(), 1, "hello?"), 1000); - LOG(LS_VERBOSE) << "recv2.received=" << recv2->received() - << "recv2.last_params.ssrc=" << recv2->last_params().ssrc + EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000); + LOG(LS_VERBOSE) << "recv2.received=" << receiver2()->received() + << "recv2.last_params.ssrc=" + << receiver2()->last_params().ssrc << "recv2.last_params.timestamp=" - << recv2->last_params().ssrc + << receiver2()->last_params().ssrc << "recv2.last_params.seq_num=" - << recv2->last_params().seq_num - << "recv2.last_data=" << recv2->last_data(); + << receiver2()->last_params().seq_num + << "recv2.last_data=" << receiver2()->last_data(); LOG(LS_VERBOSE) << "chan2 sending: 'hi chan1' -----------------------------"; - ASSERT_TRUE(SendData(chan2.get(), 2, "hi chan1", &result)); + ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result)); EXPECT_EQ(cricket::SDR_SUCCESS, result); - EXPECT_TRUE_WAIT(ReceivedData(recv1.get(), 2, "hi chan1"), 1000); - LOG(LS_VERBOSE) << "recv1.received=" << recv1->received() - << "recv1.last_params.ssrc=" << recv1->last_params().ssrc + EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000); + LOG(LS_VERBOSE) << "recv1.received=" << receiver1()->received() + << "recv1.last_params.ssrc=" + << receiver1()->last_params().ssrc << "recv1.last_params.timestamp=" - << recv1->last_params().ssrc + << receiver1()->last_params().ssrc << "recv1.last_params.seq_num=" - << recv1->last_params().seq_num - << "recv1.last_data=" << recv1->last_data(); + << receiver1()->last_params().seq_num + << "recv1.last_data=" << receiver1()->last_data(); LOG(LS_VERBOSE) << "Closing down. -----------------------------"; // Disconnects and closes socket, including setting receiving to false. - chan1->SetSend(false); - chan2->SetSend(false); + channel1()->SetSend(false); + channel2()->SetSend(false); LOG(LS_VERBOSE) << "Cleaning up. -----------------------------"; } diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc index 19ccebfa0..10cdd8e1e 100644 --- a/talk/media/webrtc/webrtcvideoengine.cc +++ b/talk/media/webrtc/webrtcvideoengine.cc @@ -429,7 +429,7 @@ class WebRtcVideoChannelRecvInfo { DecoderMap registered_decoders_; }; -class WebRtcVideoChannelSendInfo { +class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> { public: typedef std::map EncoderMap; // key: payload type WebRtcVideoChannelSendInfo(int channel_id, int capture_id, @@ -445,9 +445,7 @@ class WebRtcVideoChannelSendInfo { capturer_updated_(false), interval_(0), video_adapter_(new CoordinatedVideoAdapter) { - // TODO(asapersson): - // video_adapter_->SignalCpuAdaptationUnable.connect( - // this, &WebRtcVideoChannelSendInfo::OnCpuAdaptationUnable); + SignalCpuAdaptationUnable.repeat(video_adapter_->SignalCpuAdaptationUnable); if (cpu_monitor) { cpu_monitor->SignalUpdate.connect( video_adapter_.get(), &CoordinatedVideoAdapter::OnCpuLoadUpdated); @@ -585,6 +583,8 @@ class WebRtcVideoChannelSendInfo { registered_encoders_.clear(); } + sigslot::repeater0<> SignalCpuAdaptationUnable; + private: int channel_id_; int capture_id_; @@ -2931,6 +2931,8 @@ bool WebRtcVideoMediaChannel::ConfigureSending(int channel_id, external_capture, engine()->cpu_monitor())); send_channel->ApplyCpuOptions(options_); + send_channel->SignalCpuAdaptationUnable.connect(this, + &WebRtcVideoMediaChannel::OnCpuAdaptationUnable); // Register encoder observer for outgoing framerate and bitrate. if (engine()->vie()->codec()->RegisterEncoderObserver( @@ -3404,6 +3406,12 @@ void WebRtcVideoMediaChannel::FlushBlackFrame(uint32 ssrc, int64 timestamp) { } } +void WebRtcVideoMediaChannel::OnCpuAdaptationUnable() { + // ssrc is hardcoded to 0. This message is based on a system wide issue, + // so finding which ssrc caused it doesn't matter. + SignalMediaError(0, VideoMediaChannel::ERROR_REC_CPU_MAX_CANT_DOWNGRADE); +} + void WebRtcVideoMediaChannel::SetNetworkTransmissionState( bool is_transmitting) { LOG(LS_INFO) << "SetNetworkTransmissionState: " << is_transmitting; diff --git a/talk/media/webrtc/webrtcvideoengine.h b/talk/media/webrtc/webrtcvideoengine.h index 2f0fd3e5d..f0293bb5d 100644 --- a/talk/media/webrtc/webrtcvideoengine.h +++ b/talk/media/webrtc/webrtcvideoengine.h @@ -396,6 +396,9 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler, const std::vector& extensions, const char header_extension_uri[]); + // Signal when cpu adaptation has no further scope to adapt. + void OnCpuAdaptationUnable(); + // Global state. WebRtcVideoEngine* engine_; VoiceMediaChannel* voice_channel_; diff --git a/talk/media/webrtc/webrtcvideoengine_unittest.cc b/talk/media/webrtc/webrtcvideoengine_unittest.cc index 376f29583..840fcdd08 100644 --- a/talk/media/webrtc/webrtcvideoengine_unittest.cc +++ b/talk/media/webrtc/webrtcvideoengine_unittest.cc @@ -86,7 +86,9 @@ class FakeViEWrapper : public cricket::ViEWrapper { // Test fixture to test WebRtcVideoEngine with a fake webrtc::VideoEngine. // Useful for testing failure paths. -class WebRtcVideoEngineTestFake : public testing::Test { +class WebRtcVideoEngineTestFake : + public testing::Test, + public sigslot::has_slots<> { public: WebRtcVideoEngineTestFake() : vie_(kVideoCodecs, ARRAY_SIZE(kVideoCodecs)), @@ -95,16 +97,22 @@ class WebRtcVideoEngineTestFake : public testing::Test { engine_(NULL, // cricket::WebRtcVoiceEngine new FakeViEWrapper(&vie_), cpu_monitor_), channel_(NULL), - voice_channel_(NULL) { + voice_channel_(NULL), + last_error_(cricket::VideoMediaChannel::ERROR_NONE) { } bool SetupEngine() { bool result = engine_.Init(talk_base::Thread::Current()); if (result) { channel_ = engine_.CreateChannel(voice_channel_); + channel_->SignalMediaError.connect(this, + &WebRtcVideoEngineTestFake::OnMediaError); result = (channel_ != NULL); } return result; } + void OnMediaError(uint32 ssrc, cricket::VideoMediaChannel::Error error) { + last_error_ = error; + } bool SendI420Frame(int width, int height) { if (NULL == channel_) { return false; @@ -185,6 +193,7 @@ class WebRtcVideoEngineTestFake : public testing::Test { cricket::WebRtcVideoEngine engine_; cricket::WebRtcVideoMediaChannel* channel_; cricket::WebRtcVoiceMediaChannel* voice_channel_; + cricket::VideoMediaChannel::Error last_error_; }; // Test fixtures to test WebRtcVideoEngine with a real webrtc::VideoEngine. diff --git a/talk/p2p/base/port_unittest.cc b/talk/p2p/base/port_unittest.cc index 1c6752b84..2feeee2ed 100644 --- a/talk/p2p/base/port_unittest.cc +++ b/talk/p2p/base/port_unittest.cc @@ -28,7 +28,6 @@ #include "talk/base/crc32.h" #include "talk/base/gunit.h" #include "talk/base/helpers.h" -#include "talk/base/host.h" #include "talk/base/logging.h" #include "talk/base/natserver.h" #include "talk/base/natsocketfactory.h" diff --git a/talk/p2p/base/relayserver_unittest.cc b/talk/p2p/base/relayserver_unittest.cc index 7580e450d..86d2eef69 100644 --- a/talk/p2p/base/relayserver_unittest.cc +++ b/talk/p2p/base/relayserver_unittest.cc @@ -29,7 +29,6 @@ #include "talk/base/gunit.h" #include "talk/base/helpers.h" -#include "talk/base/host.h" #include "talk/base/logging.h" #include "talk/base/physicalsocketserver.h" #include "talk/base/socketaddress.h" diff --git a/talk/p2p/base/session_unittest.cc b/talk/p2p/base/session_unittest.cc index ae0c383fe..1d072ae0a 100644 --- a/talk/p2p/base/session_unittest.cc +++ b/talk/p2p/base/session_unittest.cc @@ -34,7 +34,6 @@ #include "talk/base/common.h" #include "talk/base/gunit.h" #include "talk/base/helpers.h" -#include "talk/base/host.h" #include "talk/base/logging.h" #include "talk/base/natserver.h" #include "talk/base/natsocketfactory.h" diff --git a/talk/p2p/base/stunserver_main.cc b/talk/p2p/base/stunserver_main.cc index e6977288d..446794486 100644 --- a/talk/p2p/base/stunserver_main.cc +++ b/talk/p2p/base/stunserver_main.cc @@ -31,7 +31,6 @@ #include -#include "talk/base/host.h" #include "talk/base/thread.h" #include "talk/p2p/base/stunserver.h" diff --git a/talk/p2p/client/basicportallocator.cc b/talk/p2p/client/basicportallocator.cc index 7a61093c9..a728d989b 100644 --- a/talk/p2p/client/basicportallocator.cc +++ b/talk/p2p/client/basicportallocator.cc @@ -32,7 +32,6 @@ #include "talk/base/common.h" #include "talk/base/helpers.h" -#include "talk/base/host.h" #include "talk/base/logging.h" #include "talk/p2p/base/basicpacketsocketfactory.h" #include "talk/p2p/base/common.h" diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc index 948a02c7b..379c55376 100644 --- a/talk/session/media/channel.cc +++ b/talk/session/media/channel.cc @@ -2294,6 +2294,7 @@ void VideoChannel::OnMessage(talk_base::Message *pmsg) { SetScreenCaptureFactoryMessageData* data = static_cast(pmsg->pdata); SetScreenCaptureFactory_w(data->screencapture_factory); + break; } case MSG_GETSTATS: { VideoStatsMessageData* data = @@ -2428,6 +2429,8 @@ bool DataChannel::Init() { this, &DataChannel::OnDataReceived); media_channel()->SignalMediaError.connect( this, &DataChannel::OnDataChannelError); + media_channel()->SignalReadyToSend.connect( + this, &DataChannel::OnDataChannelReadyToSend); srtp_filter()->SignalSrtpError.connect( this, &DataChannel::OnSrtpError); return true; @@ -2609,7 +2612,7 @@ void DataChannel::ChangeState() { // Post to trigger SignalReadyToSendData. signaling_thread()->Post(this, MSG_READYTOSENDDATA, - new BoolMessageData(send)); + new DataChannelReadyToSendMessageData(send)); LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send; } @@ -2617,7 +2620,8 @@ void DataChannel::ChangeState() { void DataChannel::OnMessage(talk_base::Message *pmsg) { switch (pmsg->message_id) { case MSG_READYTOSENDDATA: { - BoolMessageData* data = static_cast(pmsg->pdata); + DataChannelReadyToSendMessageData* data = + static_cast(pmsg->pdata); SignalReadyToSendData(data->data()); delete data; break; @@ -2690,6 +2694,14 @@ void DataChannel::OnDataChannelError( signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data); } +void DataChannel::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(this, MSG_READYTOSENDDATA, + new DataChannelReadyToSendMessageData(writable)); +} + void DataChannel::OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error) { switch (error) { diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h index 9bac96588..eccadd32d 100644 --- a/talk/session/media/channel.h +++ b/talk/session/media/channel.h @@ -595,9 +595,9 @@ class DataChannel : public BaseChannel { return static_cast(BaseChannel::media_channel()); } - bool SendData(const SendDataParams& params, - const talk_base::Buffer& payload, - SendDataResult* result); + virtual bool SendData(const SendDataParams& params, + const talk_base::Buffer& payload, + SendDataResult* result); void StartMediaMonitor(int cms); void StopMediaMonitor(); @@ -612,9 +612,8 @@ class DataChannel : public BaseChannel { const talk_base::Buffer&> SignalDataReceived; // Signal for notifying when the channel becomes ready to send data. - // That occurs when the channel is enabled, the transport is writable and - // both local and remote descriptions are set. - // TODO(perkj): Signal this per SSRC stream. + // 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 SignalReadyToSendData; private: @@ -647,6 +646,8 @@ class DataChannel : public BaseChannel { const talk_base::Buffer payload; }; + typedef talk_base::TypedMessageData DataChannelReadyToSendMessageData; + // overrides from BaseChannel virtual const ContentInfo* GetFirstContent(const SessionDescription* sdesc); // If data_channel_type_ is DCT_NONE, set it. Otherwise, check that @@ -674,6 +675,7 @@ class DataChannel : public BaseChannel { void OnDataReceived( const ReceiveDataParams& params, const char* data, size_t len); void OnDataChannelError(uint32 ssrc, DataMediaChannel::Error error); + void OnDataChannelReadyToSend(bool writable); void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error); talk_base::scoped_ptr media_monitor_; diff --git a/talk/session/media/channelmanager.h b/talk/session/media/channelmanager.h index e5e6e44a2..b1967bfcd 100644 --- a/talk/session/media/channelmanager.h +++ b/talk/session/media/channelmanager.h @@ -297,8 +297,6 @@ class ChannelManager : public talk_base::MessageHandler, bool capturing_; bool monitoring_; - talk_base::scoped_ptr video_capturer_; - // String containing currently set device. Note that this string is subtly // different from camera_device_. E.g. camera_device_ will list unplugged // but selected devices while this sting will be empty or contain current