diff --git a/talk/app/webrtc/fakemediacontroller.h b/talk/app/webrtc/fakemediacontroller.h new file mode 100644 index 0000000000..5bf3e5fcf8 --- /dev/null +++ b/talk/app/webrtc/fakemediacontroller.h @@ -0,0 +1,55 @@ +/* + * libjingle + * Copyright 2015 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_FAKEMEDIACONTROLLER_H_ +#define TALK_APP_WEBRTC_FAKEMEDIACONTROLLER_H_ + +#include "talk/app/webrtc/mediacontroller.h" +#include "webrtc/base/checks.h" + +namespace cricket { + +class FakeMediaController : public webrtc::MediaControllerInterface { + public: + explicit FakeMediaController(cricket::ChannelManager* channel_manager, + webrtc::Call* call) + : channel_manager_(channel_manager), call_(call) { + RTC_DCHECK(nullptr != channel_manager_); + RTC_DCHECK(nullptr != call_); + } + ~FakeMediaController() override {} + webrtc::Call* call_w() override { return call_; } + cricket::ChannelManager* channel_manager() const override { + return channel_manager_; + } + + private: + cricket::ChannelManager* channel_manager_; + webrtc::Call* call_; +}; +} // namespace cricket +#endif // TALK_APP_WEBRTC_FAKEMEDIACONTROLLER_H_ diff --git a/talk/app/webrtc/mediacontroller.cc b/talk/app/webrtc/mediacontroller.cc index 28b007e15b..f7d85116b1 100644 --- a/talk/app/webrtc/mediacontroller.cc +++ b/talk/app/webrtc/mediacontroller.cc @@ -27,6 +27,7 @@ #include "talk/app/webrtc/mediacontroller.h" +#include "talk/session/media/channelmanager.h" #include "webrtc/base/bind.h" #include "webrtc/base/checks.h" #include "webrtc/call.h" @@ -37,14 +38,16 @@ const int kMinBandwidthBps = 30000; const int kStartBandwidthBps = 300000; const int kMaxBandwidthBps = 2000000; -class MediaController : public webrtc::MediaControllerInterface { +class MediaController : public webrtc::MediaControllerInterface, + public sigslot::has_slots<> { public: MediaController(rtc::Thread* worker_thread, - webrtc::VoiceEngine* voice_engine) - : worker_thread_(worker_thread) { + cricket::ChannelManager* channel_manager) + : worker_thread_(worker_thread), channel_manager_(channel_manager) { RTC_DCHECK(nullptr != worker_thread); worker_thread_->Invoke( - rtc::Bind(&MediaController::Construct_w, this, voice_engine)); + rtc::Bind(&MediaController::Construct_w, this, + channel_manager_->media_engine()->GetVoE())); } ~MediaController() override { worker_thread_->Invoke( @@ -56,6 +59,10 @@ class MediaController : public webrtc::MediaControllerInterface { return call_.get(); } + cricket::ChannelManager* channel_manager() const override { + return channel_manager_; + } + private: void Construct_w(webrtc::VoiceEngine* voice_engine) { RTC_DCHECK(worker_thread_->IsCurrent()); @@ -68,10 +75,11 @@ class MediaController : public webrtc::MediaControllerInterface { } void Destruct_w() { RTC_DCHECK(worker_thread_->IsCurrent()); - call_.reset(nullptr); + call_.reset(); } - rtc::Thread* worker_thread_; + rtc::Thread* const worker_thread_; + cricket::ChannelManager* const channel_manager_; rtc::scoped_ptr call_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(MediaController); @@ -81,7 +89,8 @@ class MediaController : public webrtc::MediaControllerInterface { namespace webrtc { MediaControllerInterface* MediaControllerInterface::Create( - rtc::Thread* worker_thread, webrtc::VoiceEngine* voice_engine) { - return new MediaController(worker_thread, voice_engine); + rtc::Thread* worker_thread, + cricket::ChannelManager* channel_manager) { + return new MediaController(worker_thread, channel_manager); } } // namespace webrtc diff --git a/talk/app/webrtc/mediacontroller.h b/talk/app/webrtc/mediacontroller.h index 68798515d0..1b51be7ca2 100644 --- a/talk/app/webrtc/mediacontroller.h +++ b/talk/app/webrtc/mediacontroller.h @@ -30,6 +30,10 @@ #include "webrtc/base/thread.h" +namespace cricket { +class ChannelManager; +} // namespace cricket + namespace webrtc { class Call; class VoiceEngine; @@ -38,11 +42,13 @@ class VoiceEngine; // in the future will create and own RtpSenders and RtpReceivers. class MediaControllerInterface { public: - static MediaControllerInterface* Create(rtc::Thread* worker_thread, - webrtc::VoiceEngine* voice_engine); + static MediaControllerInterface* Create( + rtc::Thread* worker_thread, + cricket::ChannelManager* channel_manager); virtual ~MediaControllerInterface() {} virtual webrtc::Call* call_w() = 0; + virtual cricket::ChannelManager* channel_manager() const = 0; }; } // namespace webrtc diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc index e7b33c43ac..3c0dc83aa3 100644 --- a/talk/app/webrtc/peerconnection.cc +++ b/talk/app/webrtc/peerconnection.cc @@ -630,12 +630,14 @@ bool PeerConnection::Initialize( // No step delay is used while allocating ports. port_allocator_->set_step_delay(cricket::kMinimumStepDelay); - remote_stream_factory_.reset(new RemoteMediaStreamFactory( - factory_->signaling_thread(), factory_->channel_manager())); + media_controller_.reset(factory_->CreateMediaController()); - session_.reset(new WebRtcSession( - factory_->channel_manager(), factory_->signaling_thread(), - factory_->worker_thread(), port_allocator_.get())); + remote_stream_factory_.reset(new RemoteMediaStreamFactory( + factory_->signaling_thread(), media_controller_->channel_manager())); + + session_.reset( + new WebRtcSession(media_controller_.get(), factory_->signaling_thread(), + factory_->worker_thread(), port_allocator_.get())); stats_.reset(new StatsCollector(this)); // Initialize the WebRtcSession. It creates transport channels etc. diff --git a/talk/app/webrtc/peerconnection.h b/talk/app/webrtc/peerconnection.h index 6a66497859..c47f90372e 100644 --- a/talk/app/webrtc/peerconnection.h +++ b/talk/app/webrtc/peerconnection.h @@ -361,6 +361,7 @@ class PeerConnection : public PeerConnectionInterface, IceGatheringState ice_gathering_state_; rtc::scoped_ptr port_allocator_; + rtc::scoped_ptr media_controller_; // Streams added via AddStream. rtc::scoped_refptr local_streams_; diff --git a/talk/app/webrtc/peerconnectionfactory.cc b/talk/app/webrtc/peerconnectionfactory.cc index 08877546c4..6619f3101d 100644 --- a/talk/app/webrtc/peerconnectionfactory.cc +++ b/talk/app/webrtc/peerconnectionfactory.cc @@ -279,9 +279,11 @@ PeerConnectionFactory::CreateAudioTrack(const std::string& id, return AudioTrackProxy::Create(signaling_thread_, track); } -cricket::ChannelManager* PeerConnectionFactory::channel_manager() { +webrtc::MediaControllerInterface* PeerConnectionFactory::CreateMediaController() + const { RTC_DCHECK(signaling_thread_->IsCurrent()); - return channel_manager_.get(); + return MediaControllerInterface::Create(worker_thread_, + channel_manager_.get()); } rtc::Thread* PeerConnectionFactory::signaling_thread() { diff --git a/talk/app/webrtc/peerconnectionfactory.h b/talk/app/webrtc/peerconnectionfactory.h index c5855f452b..868919934b 100644 --- a/talk/app/webrtc/peerconnectionfactory.h +++ b/talk/app/webrtc/peerconnectionfactory.h @@ -31,6 +31,7 @@ #include #include "talk/app/webrtc/dtlsidentitystore.h" +#include "talk/app/webrtc/mediacontroller.h" #include "talk/app/webrtc/mediastreaminterface.h" #include "talk/app/webrtc/peerconnectioninterface.h" #include "talk/session/media/channelmanager.h" @@ -80,7 +81,7 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface { bool StartAecDump(rtc::PlatformFile file) override; - virtual cricket::ChannelManager* channel_manager(); + virtual webrtc::MediaControllerInterface* CreateMediaController() const; virtual rtc::Thread* signaling_thread(); virtual rtc::Thread* worker_thread(); const Options& options() const { return options_; } diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc index 8b0a9edc1b..9121c691b1 100644 --- a/talk/app/webrtc/statscollector_unittest.cc +++ b/talk/app/webrtc/statscollector_unittest.cc @@ -84,8 +84,8 @@ const uint32_t kSsrcOfTrack = 1234; class MockWebRtcSession : public webrtc::WebRtcSession { public: - explicit MockWebRtcSession(cricket::ChannelManager* channel_manager) - : WebRtcSession(channel_manager, + explicit MockWebRtcSession(webrtc::MediaControllerInterface* media_controller) + : WebRtcSession(media_controller, rtc::Thread::Current(), rtc::Thread::Current(), nullptr) {} @@ -506,7 +506,10 @@ class StatsCollectorTest : public testing::Test { : media_engine_(new cricket::FakeMediaEngine()), channel_manager_( new cricket::ChannelManager(media_engine_, rtc::Thread::Current())), - session_(channel_manager_.get()) { + media_controller_( + webrtc::MediaControllerInterface::Create(rtc::Thread::Current(), + channel_manager_.get())), + session_(media_controller_.get()) { // By default, we ignore session GetStats calls. EXPECT_CALL(session_, GetTransportStats(_)).WillRepeatedly(Return(false)); // Add default returns for mock classes. @@ -760,6 +763,7 @@ class StatsCollectorTest : public testing::Test { cricket::FakeMediaEngine* media_engine_; rtc::scoped_ptr channel_manager_; + rtc::scoped_ptr media_controller_; MockWebRtcSession session_; MockPeerConnection pc_; FakeDataChannelProvider data_channel_provider_; @@ -825,8 +829,8 @@ TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) { Return(true))); MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); - cricket::VideoChannel video_channel(rtc::Thread::Current(), - media_channel, NULL, kVideoChannelName, false); + cricket::VideoChannel video_channel(rtc::Thread::Current(), media_channel, + nullptr, kVideoChannelName, false); StatsReports reports; // returned values. cricket::VideoSenderInfo video_sender_info; cricket::VideoMediaInfo stats_read; @@ -871,8 +875,8 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) { Return(true))); MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); - cricket::VideoChannel video_channel(rtc::Thread::Current(), - media_channel, NULL, kVideoChannelName, false); + cricket::VideoChannel video_channel(rtc::Thread::Current(), media_channel, + nullptr, kVideoChannelName, false); StatsReports reports; // returned values. cricket::VideoSenderInfo video_sender_info; @@ -946,8 +950,8 @@ TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) { StatsCollectorForTest stats(&pc_); MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); - cricket::VideoChannel video_channel(rtc::Thread::Current(), - media_channel, NULL, "video", false); + cricket::VideoChannel video_channel(rtc::Thread::Current(), media_channel, + nullptr, "video", false); AddOutgoingVideoTrackStats(); stats.AddStream(stream_); @@ -982,8 +986,8 @@ TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) { Return(true))); MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); - cricket::VideoChannel video_channel(rtc::Thread::Current(), - media_channel, NULL, kVideoChannelName, false); + cricket::VideoChannel video_channel(rtc::Thread::Current(), media_channel, + nullptr, kVideoChannelName, false); AddOutgoingVideoTrackStats(); stats.AddStream(stream_); @@ -1046,8 +1050,8 @@ TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) { MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); // The transport_name known by the video channel. const std::string kVcName("vcname"); - cricket::VideoChannel video_channel(rtc::Thread::Current(), - media_channel, NULL, kVcName, false); + cricket::VideoChannel video_channel(rtc::Thread::Current(), media_channel, + nullptr, kVcName, false); AddOutgoingVideoTrackStats(); stats.AddStream(stream_); @@ -1104,8 +1108,8 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) { MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); // The transport_name known by the video channel. const std::string kVcName("vcname"); - cricket::VideoChannel video_channel(rtc::Thread::Current(), - media_channel, NULL, kVcName, false); + cricket::VideoChannel video_channel(rtc::Thread::Current(), media_channel, + nullptr, kVcName, false); AddOutgoingVideoTrackStats(); stats.AddStream(stream_); @@ -1130,8 +1134,8 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) { MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); // The transport_name known by the video channel. const std::string kVcName("vcname"); - cricket::VideoChannel video_channel(rtc::Thread::Current(), - media_channel, NULL, kVcName, false); + cricket::VideoChannel video_channel(rtc::Thread::Current(), media_channel, + nullptr, kVcName, false); AddOutgoingVideoTrackStats(); stats.AddStream(stream_); @@ -1185,8 +1189,8 @@ TEST_F(StatsCollectorTest, ReportsFromRemoteTrack) { Return(true))); MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); - cricket::VideoChannel video_channel(rtc::Thread::Current(), - media_channel, NULL, kVideoChannelName, false); + cricket::VideoChannel video_channel(rtc::Thread::Current(), media_channel, + nullptr, kVideoChannelName, false); AddIncomingVideoTrackStats(); stats.AddStream(stream_); @@ -1494,8 +1498,8 @@ TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) { MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); // The transport_name known by the voice channel. const std::string kVcName("vcname"); - cricket::VoiceChannel voice_channel(rtc::Thread::Current(), - media_engine_, media_channel, NULL, kVcName, false); + cricket::VoiceChannel voice_channel(rtc::Thread::Current(), media_engine_, + media_channel, nullptr, kVcName, false); AddOutgoingAudioTrackStats(); stats.AddStream(stream_); stats.AddLocalAudioTrack(audio_track_, kSsrcOfTrack); @@ -1529,8 +1533,8 @@ TEST_F(StatsCollectorTest, GetStatsFromRemoteStream) { MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); // The transport_name known by the voice channel. const std::string kVcName("vcname"); - cricket::VoiceChannel voice_channel(rtc::Thread::Current(), - media_engine_, media_channel, NULL, kVcName, false); + cricket::VoiceChannel voice_channel(rtc::Thread::Current(), media_engine_, + media_channel, nullptr, kVcName, false); AddIncomingAudioTrackStats(); stats.AddStream(stream_); @@ -1558,8 +1562,8 @@ TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) { MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); // The transport_name known by the voice channel. const std::string kVcName("vcname"); - cricket::VoiceChannel voice_channel(rtc::Thread::Current(), - media_engine_, media_channel, NULL, kVcName, false); + cricket::VoiceChannel voice_channel(rtc::Thread::Current(), media_engine_, + media_channel, nullptr, kVcName, false); AddOutgoingAudioTrackStats(); stats.AddStream(stream_); stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack); @@ -1619,8 +1623,8 @@ TEST_F(StatsCollectorTest, LocalAndRemoteTracksWithSameSsrc) { MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); // The transport_name known by the voice channel. const std::string kVcName("vcname"); - cricket::VoiceChannel voice_channel(rtc::Thread::Current(), - media_engine_, media_channel, NULL, kVcName, false); + cricket::VoiceChannel voice_channel(rtc::Thread::Current(), media_engine_, + media_channel, nullptr, kVcName, false); // Create a local stream with a local audio track and adds it to the stats. AddOutgoingAudioTrackStats(); @@ -1706,8 +1710,8 @@ TEST_F(StatsCollectorTest, TwoLocalTracksWithSameSsrc) { MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); // The transport_name known by the voice channel. const std::string kVcName("vcname"); - cricket::VoiceChannel voice_channel(rtc::Thread::Current(), - media_engine_, media_channel, NULL, kVcName, false); + cricket::VoiceChannel voice_channel(rtc::Thread::Current(), media_engine_, + media_channel, nullptr, kVcName, false); // Create a local stream with a local audio track and adds it to the stats. AddOutgoingAudioTrackStats(); diff --git a/talk/app/webrtc/test/fakedatachannelprovider.h b/talk/app/webrtc/test/fakedatachannelprovider.h index 9a8352e1cd..ff44e585fe 100644 --- a/talk/app/webrtc/test/fakedatachannelprovider.h +++ b/talk/app/webrtc/test/fakedatachannelprovider.h @@ -25,6 +25,9 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef TALK_APP_WEBRTC_TEST_FAKEDATACHANNELPROVIDER_H_ +#define TALK_APP_WEBRTC_TEST_FAKEDATACHANNELPROVIDER_H_ + #include "talk/app/webrtc/datachannel.h" class FakeDataChannelProvider : public webrtc::DataChannelProviderInterface { @@ -155,3 +158,4 @@ class FakeDataChannelProvider : public webrtc::DataChannelProviderInterface { std::set send_ssrcs_; std::set recv_ssrcs_; }; +#endif // TALK_APP_WEBRTC_TEST_FAKEDATACHANNELPROVIDER_H_ diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc index f17dd34b75..af1dc61a93 100644 --- a/talk/app/webrtc/webrtcsession.cc +++ b/talk/app/webrtc/webrtcsession.cc @@ -51,7 +51,9 @@ #include "webrtc/base/logging.h" #include "webrtc/base/stringencode.h" #include "webrtc/base/stringutils.h" +#include "webrtc/call.h" #include "webrtc/p2p/base/portallocator.h" +#include "webrtc/p2p/base/transportchannel.h" using cricket::ContentInfo; using cricket::ContentInfos; @@ -529,7 +531,7 @@ class IceRestartAnswerLatch { bool ice_restart_; }; -WebRtcSession::WebRtcSession(cricket::ChannelManager* channel_manager, +WebRtcSession::WebRtcSession(webrtc::MediaControllerInterface* media_controller, rtc::Thread* signaling_thread, rtc::Thread* worker_thread, cricket::PortAllocator* port_allocator) @@ -543,7 +545,8 @@ WebRtcSession::WebRtcSession(cricket::ChannelManager* channel_manager, transport_controller_(new cricket::TransportController(signaling_thread, worker_thread, port_allocator)), - channel_manager_(channel_manager), + media_controller_(media_controller), + channel_manager_(media_controller_->channel_manager()), ice_observer_(NULL), ice_connection_state_(PeerConnectionInterface::kIceConnectionNew), ice_connection_receiving_(true), @@ -763,9 +766,6 @@ bool WebRtcSession::Initialize( cricket::PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE); } - media_controller_.reset(MediaControllerInterface::Create( - worker_thread(), channel_manager_->media_engine()->GetVoE())); - return true; } @@ -1844,7 +1844,7 @@ bool WebRtcSession::CreateChannels(const SessionDescription* desc) { bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content) { voice_channel_.reset(channel_manager_->CreateVoiceChannel( - media_controller_.get(), transport_controller_.get(), content->name, true, + media_controller_, transport_controller_.get(), content->name, true, audio_options_)); if (!voice_channel_) { return false; @@ -1854,12 +1854,14 @@ bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content) { this, &WebRtcSession::OnDtlsSetupFailure); SignalVoiceChannelCreated(); + voice_channel_->transport_channel()->SignalSentPacket.connect( + this, &WebRtcSession::OnSentPacket_w); return true; } bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content) { video_channel_.reset(channel_manager_->CreateVideoChannel( - media_controller_.get(), transport_controller_.get(), content->name, true, + media_controller_, transport_controller_.get(), content->name, true, video_options_)); if (!video_channel_) { return false; @@ -1869,6 +1871,8 @@ bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content) { this, &WebRtcSession::OnDtlsSetupFailure); SignalVideoChannelCreated(); + video_channel_->transport_channel()->SignalSentPacket.connect( + this, &WebRtcSession::OnSentPacket_w); return true; } @@ -1889,6 +1893,8 @@ bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content) { this, &WebRtcSession::OnDtlsSetupFailure); SignalDataChannelCreated(); + data_channel_->transport_channel()->SignalSentPacket.connect( + this, &WebRtcSession::OnSentPacket_w); return true; } @@ -2205,4 +2211,10 @@ void WebRtcSession::ReportNegotiatedCiphers( } } +void WebRtcSession::OnSentPacket_w(cricket::TransportChannel* channel, + const rtc::SentPacket& sent_packet) { + RTC_DCHECK(worker_thread()->IsCurrent()); + media_controller_->call_w()->OnSentPacket(sent_packet); +} + } // namespace webrtc diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h index f3dd602eba..d9c40d1a83 100644 --- a/talk/app/webrtc/webrtcsession.h +++ b/talk/app/webrtc/webrtcsession.h @@ -151,7 +151,7 @@ class WebRtcSession : public AudioProviderInterface, ERROR_TRANSPORT = 2, // transport error of some kind }; - WebRtcSession(cricket::ChannelManager* channel_manager, + WebRtcSession(webrtc::MediaControllerInterface* media_controller, rtc::Thread* signaling_thread, rtc::Thread* worker_thread, cricket::PortAllocator* port_allocator); @@ -458,6 +458,9 @@ class WebRtcSession : public AudioProviderInterface, void ReportNegotiatedCiphers(const cricket::TransportStats& stats); + void OnSentPacket_w(cricket::TransportChannel* channel, + const rtc::SentPacket& sent_packet); + rtc::Thread* const signaling_thread_; rtc::Thread* const worker_thread_; cricket::PortAllocator* const port_allocator_; @@ -470,7 +473,7 @@ class WebRtcSession : public AudioProviderInterface, bool initial_offerer_ = false; rtc::scoped_ptr transport_controller_; - rtc::scoped_ptr media_controller_; + MediaControllerInterface* media_controller_; rtc::scoped_ptr voice_channel_; rtc::scoped_ptr video_channel_; rtc::scoped_ptr data_channel_; diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc index f998ca8848..9618db9d80 100644 --- a/talk/app/webrtc/webrtcsession_unittest.cc +++ b/talk/app/webrtc/webrtcsession_unittest.cc @@ -28,6 +28,7 @@ #include #include "talk/app/webrtc/audiotrack.h" +#include "talk/app/webrtc/fakemediacontroller.h" #include "talk/app/webrtc/fakemetricsobserver.h" #include "talk/app/webrtc/jsepicecandidate.h" #include "talk/app/webrtc/jsepsessiondescription.h" @@ -44,6 +45,7 @@ #include "talk/media/base/fakemediaengine.h" #include "talk/media/base/fakevideorenderer.h" #include "talk/media/base/mediachannel.h" +#include "talk/media/webrtc/fakewebrtccall.h" #include "webrtc/p2p/base/stunserver.h" #include "webrtc/p2p/base/teststunserver.h" #include "webrtc/p2p/base/testturnserver.h" @@ -245,12 +247,15 @@ class MockIceObserver : public webrtc::IceObserver { class WebRtcSessionForTest : public webrtc::WebRtcSession { public: - WebRtcSessionForTest(cricket::ChannelManager* cmgr, + WebRtcSessionForTest(webrtc::MediaControllerInterface* media_controller, rtc::Thread* signaling_thread, rtc::Thread* worker_thread, cricket::PortAllocator* port_allocator, webrtc::IceObserver* ice_observer) - : WebRtcSession(cmgr, signaling_thread, worker_thread, port_allocator) { + : WebRtcSession(media_controller, + signaling_thread, + worker_thread, + port_allocator) { RegisterIceObserver(ice_observer); } virtual ~WebRtcSessionForTest() {} @@ -360,24 +365,31 @@ class WebRtcSessionTest // TODO Investigate why ChannelManager crashes, if it's created // after stun_server. WebRtcSessionTest() - : media_engine_(new cricket::FakeMediaEngine()), - data_engine_(new cricket::FakeDataEngine()), - channel_manager_(new cricket::ChannelManager( - media_engine_, data_engine_, new cricket::CaptureManager(), - rtc::Thread::Current())), - tdesc_factory_(new cricket::TransportDescriptionFactory()), - desc_factory_(new cricket::MediaSessionDescriptionFactory( - channel_manager_.get(), tdesc_factory_.get())), - pss_(new rtc::PhysicalSocketServer), - vss_(new rtc::VirtualSocketServer(pss_.get())), - fss_(new rtc::FirewallSocketServer(vss_.get())), - ss_scope_(fss_.get()), - stun_socket_addr_(rtc::SocketAddress(kStunAddrHost, - cricket::STUN_SERVER_PORT)), - stun_server_(cricket::TestStunServer::Create(Thread::Current(), - stun_socket_addr_)), - turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr), - metrics_observer_(new rtc::RefCountedObject()) { + : media_engine_(new cricket::FakeMediaEngine()), + data_engine_(new cricket::FakeDataEngine()), + channel_manager_( + new cricket::ChannelManager(media_engine_, + data_engine_, + new cricket::CaptureManager(), + rtc::Thread::Current())), + fake_call_(webrtc::Call::Config()), + media_controller_( + webrtc::MediaControllerInterface::Create(rtc::Thread::Current(), + channel_manager_.get())), + tdesc_factory_(new cricket::TransportDescriptionFactory()), + desc_factory_( + new cricket::MediaSessionDescriptionFactory(channel_manager_.get(), + tdesc_factory_.get())), + pss_(new rtc::PhysicalSocketServer), + vss_(new rtc::VirtualSocketServer(pss_.get())), + fss_(new rtc::FirewallSocketServer(vss_.get())), + ss_scope_(fss_.get()), + stun_socket_addr_( + rtc::SocketAddress(kStunAddrHost, cricket::STUN_SERVER_PORT)), + stun_server_(cricket::TestStunServer::Create(Thread::Current(), + stun_socket_addr_)), + turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr), + metrics_observer_(new rtc::RefCountedObject()) { cricket::ServerAddresses stun_servers; stun_servers.insert(stun_socket_addr_); allocator_.reset(new cricket::BasicPortAllocator( @@ -405,7 +417,7 @@ class WebRtcSessionTest const PeerConnectionInterface::RTCConfiguration& rtc_configuration) { ASSERT_TRUE(session_.get() == NULL); session_.reset(new WebRtcSessionForTest( - channel_manager_.get(), rtc::Thread::Current(), rtc::Thread::Current(), + media_controller_.get(), rtc::Thread::Current(), rtc::Thread::Current(), allocator_.get(), &observer_)); session_->SignalDataChannelOpenMessage.connect( this, &WebRtcSessionTest::OnDataChannelOpenMessage); @@ -1226,8 +1238,7 @@ class WebRtcSessionTest // -> Failed. // The Gathering state should go: New -> Gathering -> Completed. - void TestLoopbackCall(const LoopbackNetworkConfiguration& config) { - LoopbackNetworkManager loopback_network_manager(this, config); + void SetupLoopbackCall() { Init(); SendAudioVideoStream1(); SessionDescriptionInterface* offer = CreateOffer(); @@ -1238,30 +1249,29 @@ class WebRtcSessionTest EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew, observer_.ice_connection_state_); EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringGathering, - observer_.ice_gathering_state_, - kIceCandidatesTimeout); + observer_.ice_gathering_state_, kIceCandidatesTimeout); EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout); EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringComplete, - observer_.ice_gathering_state_, - kIceCandidatesTimeout); + observer_.ice_gathering_state_, kIceCandidatesTimeout); std::string sdp; offer->ToString(&sdp); - SessionDescriptionInterface* desc = - webrtc::CreateSessionDescription( - JsepSessionDescription::kAnswer, sdp, nullptr); + SessionDescriptionInterface* desc = webrtc::CreateSessionDescription( + JsepSessionDescription::kAnswer, sdp, nullptr); ASSERT_TRUE(desc != NULL); SetRemoteDescriptionWithoutError(desc); EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionChecking, - observer_.ice_connection_state_, - kIceCandidatesTimeout); + observer_.ice_connection_state_, kIceCandidatesTimeout); // The ice connection state is "Connected" too briefly to catch in a test. EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted, - observer_.ice_connection_state_, - kIceCandidatesTimeout); + observer_.ice_connection_state_, kIceCandidatesTimeout); + } + void TestLoopbackCall(const LoopbackNetworkConfiguration& config) { + LoopbackNetworkManager loopback_network_manager(this, config); + SetupLoopbackCall(); config.VerifyBestConnectionAfterIceConverge(metrics_observer_); // Adding firewall rule to block ping requests, which should cause // transport channel failure. @@ -1300,6 +1310,25 @@ class WebRtcSessionTest TestLoopbackCall(config); } + void TestPacketOptions() { + media_controller_.reset( + new cricket::FakeMediaController(channel_manager_.get(), &fake_call_)); + LoopbackNetworkConfiguration config; + LoopbackNetworkManager loopback_network_manager(this, config); + + SetupLoopbackCall(); + + uint8_t test_packet[15] = {0}; + rtc::PacketOptions options; + options.packet_id = 10; + media_engine_->GetVideoChannel(0) + ->SendRtp(test_packet, sizeof(test_packet), options); + + const int kPacketTimeout = 2000; + EXPECT_EQ_WAIT(fake_call_.last_sent_packet().packet_id, 10, kPacketTimeout); + EXPECT_GT(fake_call_.last_sent_packet().send_time_ms, -1); + } + // Adds CN codecs to FakeMediaEngine and MediaDescriptionFactory. void AddCNCodecs() { const cricket::AudioCodec kCNCodec1(102, "CN", 8000, 0, 1, 0); @@ -1406,6 +1435,8 @@ class WebRtcSessionTest cricket::FakeMediaEngine* media_engine_; cricket::FakeDataEngine* data_engine_; rtc::scoped_ptr channel_manager_; + cricket::FakeCall fake_call_; + rtc::scoped_ptr media_controller_; rtc::scoped_ptr tdesc_factory_; rtc::scoped_ptr desc_factory_; rtc::scoped_ptr pss_; @@ -4154,6 +4185,10 @@ TEST_F(WebRtcSessionTest, CreateOffersAndShutdown) { } } +TEST_F(WebRtcSessionTest, TestPacketOptionsAndOnPacketSent) { + TestPacketOptions(); +} + // TODO(bemasc): Add a TestIceStatesBundle with BUNDLE enabled. That test // currently fails because upon disconnection and reconnection OnIceComplete is // called more than once without returning to IceGatheringGathering. diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp index 3268d01493..fdf06312d6 100755 --- a/talk/libjingle.gyp +++ b/talk/libjingle.gyp @@ -46,6 +46,7 @@ 'target_name': 'libjingle_peerconnection_so', 'type': 'shared_library', 'dependencies': [ + '<(webrtc_root)/system_wrappers/system_wrappers.gyp:field_trial_default', 'libjingle_peerconnection', ], 'sources': [ @@ -432,8 +433,8 @@ '<(webrtc_root)/webrtc.gyp:webrtc', '<(webrtc_root)/voice_engine/voice_engine.gyp:voice_engine', '<(webrtc_root)/sound/sound.gyp:rtc_sound', + '<(webrtc_root)/system_wrappers/system_wrappers.gyp:metrics_default', '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers', - '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers_default', '<(webrtc_root)/libjingle/xmllite/xmllite.gyp:rtc_xmllite', '<(webrtc_root)/libjingle/xmpp/xmpp.gyp:rtc_xmpp', '<(webrtc_root)/p2p/p2p.gyp:rtc_p2p', diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp index 2e4204784a..7440e47b06 100755 --- a/talk/libjingle_tests.gyp +++ b/talk/libjingle_tests.gyp @@ -142,6 +142,7 @@ 'dependencies': [ '<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils', 'libjingle.gyp:libjingle', + 'libjingle.gyp:libjingle_peerconnection', 'libjingle.gyp:libjingle_p2p', 'libjingle_unittest_main', ], @@ -344,6 +345,7 @@ 'includes': [ 'build/objc_app.gypi' ], 'dependencies': [ '<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils', + '<(webrtc_root)/system_wrappers/system_wrappers.gyp:field_trial_default', 'libjingle.gyp:libjingle_peerconnection_objc', ], 'sources': [ @@ -375,6 +377,7 @@ 'includes': [ 'build/objc_app.gypi' ], 'dependencies': [ '<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils', + '<(webrtc_root)/system_wrappers/system_wrappers.gyp:field_trial_default', '<(DEPTH)/third_party/ocmock/ocmock.gyp:ocmock', '<(webrtc_root)/libjingle_examples.gyp:apprtc_signaling', ], diff --git a/talk/media/base/constants.cc b/talk/media/base/constants.cc index 0d0a33c18a..4063004968 100644 --- a/talk/media/base/constants.cc +++ b/talk/media/base/constants.cc @@ -124,6 +124,10 @@ const char kRtpVideoRotationHeaderExtension[] = "urn:3gpp:video-orientation"; const char kRtpVideoRotation6BitsHeaderExtensionForTesting[] = "urn:3gpp:video-orientation:6"; +const int kRtpTransportSequenceNumberHeaderExtensionDefaultId = 5; +const char kRtpTransportSequenceNumberHeaderExtension[] = + "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions"; + const int kNumDefaultUnsignalledVideoRecvStreams = 0; const char kVp8CodecName[] = "VP8"; diff --git a/talk/media/base/constants.h b/talk/media/base/constants.h index d92cb22514..b6a9e5681f 100644 --- a/talk/media/base/constants.h +++ b/talk/media/base/constants.h @@ -154,6 +154,11 @@ extern const char kRtpVideoRotationHeaderExtension[]; // We don't support 6 bit CVO. Added here for testing purpose. extern const char kRtpVideoRotation6BitsHeaderExtensionForTesting[]; +// Header extension for transport sequence number, see url for details: +// http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions +extern const int kRtpTransportSequenceNumberHeaderExtensionDefaultId; +extern const char kRtpTransportSequenceNumberHeaderExtension[]; + extern const int kNumDefaultUnsignalledVideoRecvStreams; extern const char kVp8CodecName[]; diff --git a/talk/media/base/fakemediaengine.h b/talk/media/base/fakemediaengine.h index 2728c7d325..57d0145a9d 100644 --- a/talk/media/base/fakemediaengine.h +++ b/talk/media/base/fakemediaengine.h @@ -69,18 +69,18 @@ template class RtpHelper : public Base { const std::list& rtp_packets() const { return rtp_packets_; } const std::list& rtcp_packets() const { return rtcp_packets_; } - bool SendRtp(const void* data, int len) { + bool SendRtp(const void* data, int len, const rtc::PacketOptions& options) { if (!sending_) { return false; } rtc::Buffer packet(reinterpret_cast(data), len, kMaxRtpPacketLen); - return Base::SendPacket(&packet); + return Base::SendPacket(&packet, options); } bool SendRtcp(const void* data, int len) { rtc::Buffer packet(reinterpret_cast(data), len, kMaxRtpPacketLen); - return Base::SendRtcp(&packet); + return Base::SendRtcp(&packet, rtc::PacketOptions()); } bool CheckRtp(const void* data, int len) { diff --git a/talk/media/base/fakenetworkinterface.h b/talk/media/base/fakenetworkinterface.h index 275f5981ce..418dfef63c 100644 --- a/talk/media/base/fakenetworkinterface.h +++ b/talk/media/base/fakenetworkinterface.h @@ -129,7 +129,7 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, protected: virtual bool SendPacket(rtc::Buffer* packet, - rtc::DiffServCodePoint dscp) { + const rtc::PacketOptions& options) { rtc::CritScope cs(&crit_); uint32_t cur_ssrc = 0; @@ -155,7 +155,7 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, } virtual bool SendRtcp(rtc::Buffer* packet, - rtc::DiffServCodePoint dscp) { + const rtc::PacketOptions& options) { rtc::CritScope cs(&crit_); rtcp_packets_.push_back(*packet); if (!conf_) { diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h index 05d56cf9e0..900c51ae9d 100644 --- a/talk/media/base/mediachannel.h +++ b/talk/media/base/mediachannel.h @@ -504,12 +504,10 @@ class MediaChannel : public sigslot::has_slots<> { class NetworkInterface { public: enum SocketType { ST_RTP, ST_RTCP }; - virtual bool SendPacket( - rtc::Buffer* packet, - rtc::DiffServCodePoint dscp = rtc::DSCP_NO_CHANGE) = 0; - virtual bool SendRtcp( - rtc::Buffer* packet, - rtc::DiffServCodePoint dscp = rtc::DSCP_NO_CHANGE) = 0; + virtual bool SendPacket(rtc::Buffer* packet, + const rtc::PacketOptions& options) = 0; + virtual bool SendRtcp(rtc::Buffer* packet, + const rtc::PacketOptions& options) = 0; virtual int SetOption(SocketType type, rtc::Socket::Option opt, int option) = 0; virtual ~NetworkInterface() {} @@ -553,12 +551,12 @@ class MediaChannel : public sigslot::has_slots<> { } // Base method to send packet using NetworkInterface. - bool SendPacket(rtc::Buffer* packet) { - return DoSendPacket(packet, false); + bool SendPacket(rtc::Buffer* packet, const rtc::PacketOptions& options) { + return DoSendPacket(packet, false, options); } - bool SendRtcp(rtc::Buffer* packet) { - return DoSendPacket(packet, true); + bool SendRtcp(rtc::Buffer* packet, const rtc::PacketOptions& options) { + return DoSendPacket(packet, true, options); } int SetOption(NetworkInterface::SocketType type, @@ -587,13 +585,15 @@ class MediaChannel : public sigslot::has_slots<> { } private: - bool DoSendPacket(rtc::Buffer* packet, bool rtcp) { + bool DoSendPacket(rtc::Buffer* packet, + bool rtcp, + const rtc::PacketOptions& options) { rtc::CritScope cs(&network_interface_crit_); if (!network_interface_) return false; - return (!rtcp) ? network_interface_->SendPacket(packet) : - network_interface_->SendRtcp(packet); + return (!rtcp) ? network_interface_->SendPacket(packet, options) + : network_interface_->SendRtcp(packet, options); } // |network_interface_| can be accessed from the worker_thread and diff --git a/talk/media/base/rtpdataengine.cc b/talk/media/base/rtpdataengine.cc index b2b84b965f..9b26280560 100644 --- a/talk/media/base/rtpdataengine.cc +++ b/talk/media/base/rtpdataengine.cc @@ -359,7 +359,7 @@ bool RtpDataMediaChannel::SendData( << ", timestamp=" << header.timestamp << ", len=" << payload.size(); - MediaChannel::SendPacket(&packet); + MediaChannel::SendPacket(&packet, rtc::PacketOptions()); send_limiter_->Use(packet_len, now); if (result) { *result = SDR_SUCCESS; diff --git a/talk/media/sctp/sctpdataengine.cc b/talk/media/sctp/sctpdataengine.cc index 739383d379..c88882d42d 100644 --- a/talk/media/sctp/sctpdataengine.cc +++ b/talk/media/sctp/sctpdataengine.cc @@ -984,7 +984,7 @@ void SctpDataMediaChannel::OnPacketFromSctpToNetwork( << " even after adding " << kSctpOverhead << " extra SCTP overhead"; } - MediaChannel::SendPacket(buffer); + MediaChannel::SendPacket(buffer, rtc::PacketOptions()); } bool SctpDataMediaChannel::SendQueuedStreamResets() { diff --git a/talk/media/sctp/sctpdataengine_unittest.cc b/talk/media/sctp/sctpdataengine_unittest.cc index 2cd0302f56..4706368b9d 100644 --- a/talk/media/sctp/sctpdataengine_unittest.cc +++ b/talk/media/sctp/sctpdataengine_unittest.cc @@ -64,7 +64,7 @@ class SctpFakeNetworkInterface : public cricket::MediaChannel::NetworkInterface, protected: // Called to send raw packet down the wire (e.g. SCTP an packet). virtual bool SendPacket(rtc::Buffer* packet, - rtc::DiffServCodePoint dscp) { + const rtc::PacketOptions& options) { LOG(LS_VERBOSE) << "SctpFakeNetworkInterface::SendPacket"; // TODO(ldixon): Can/should we use Buffer.TransferTo here? @@ -93,7 +93,7 @@ class SctpFakeNetworkInterface : public cricket::MediaChannel::NetworkInterface, // TODO(ldixon): Refactor parent NetworkInterface class so these are not // required. They are RTC specific and should be in an appropriate subclass. virtual bool SendRtcp(rtc::Buffer* packet, - rtc::DiffServCodePoint dscp) { + const rtc::PacketOptions& options) { LOG(LS_WARNING) << "Unsupported: SctpFakeNetworkInterface::SendRtcp."; return false; } diff --git a/talk/media/webrtc/fakewebrtccall.cc b/talk/media/webrtc/fakewebrtccall.cc index 9f2c8e53df..a0386b011e 100644 --- a/talk/media/webrtc/fakewebrtccall.cc +++ b/talk/media/webrtc/fakewebrtccall.cc @@ -202,8 +202,7 @@ FakeCall::FakeCall(const webrtc::Call::Config& config) : config_(config), network_state_(webrtc::kNetworkUp), num_created_send_streams_(0), - num_created_receive_streams_(0) { -} + num_created_receive_streams_(0) {} FakeCall::~FakeCall() { EXPECT_EQ(0u, video_send_streams_.size()); @@ -367,4 +366,8 @@ void FakeCall::SetBitrateConfig( void FakeCall::SignalNetworkState(webrtc::NetworkState state) { network_state_ = state; } + +void FakeCall::OnSentPacket(const rtc::SentPacket& sent_packet) { + last_sent_packet_ = sent_packet; +} } // namespace cricket diff --git a/talk/media/webrtc/fakewebrtccall.h b/talk/media/webrtc/fakewebrtccall.h index 422848dda1..fb271f2215 100644 --- a/talk/media/webrtc/fakewebrtccall.h +++ b/talk/media/webrtc/fakewebrtccall.h @@ -164,6 +164,7 @@ class FakeCall : public webrtc::Call, public webrtc::PacketReceiver { const std::vector& GetAudioReceiveStreams(); const FakeAudioReceiveStream* GetAudioReceiveStream(uint32_t ssrc); + rtc::SentPacket last_sent_packet() const { return last_sent_packet_; } webrtc::NetworkState GetNetworkState() const; int GetNumCreatedSendStreams() const; int GetNumCreatedReceiveStreams() const; @@ -200,9 +201,11 @@ class FakeCall : public webrtc::Call, public webrtc::PacketReceiver { void SetBitrateConfig( const webrtc::Call::Config::BitrateConfig& bitrate_config) override; void SignalNetworkState(webrtc::NetworkState state) override; + void OnSentPacket(const rtc::SentPacket& sent_packet) override; webrtc::Call::Config config_; webrtc::NetworkState network_state_; + rtc::SentPacket last_sent_packet_; webrtc::Call::Stats stats_; std::vector video_send_streams_; std::vector video_receive_streams_; diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc index 5ee0119dcf..7239d7a3ea 100644 --- a/talk/media/webrtc/webrtcvideoengine2.cc +++ b/talk/media/webrtc/webrtcvideoengine2.cc @@ -557,6 +557,11 @@ WebRtcVideoEngine2::WebRtcVideoEngine2() rtp_header_extensions_.push_back( RtpHeaderExtension(kRtpVideoRotationHeaderExtension, kRtpVideoRotationHeaderExtensionDefaultId)); + if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe") == "Enabled") { + rtp_header_extensions_.push_back(RtpHeaderExtension( + kRtpTransportSequenceNumberHeaderExtension, + kRtpTransportSequenceNumberHeaderExtensionDefaultId)); + } } WebRtcVideoEngine2::~WebRtcVideoEngine2() { @@ -1651,12 +1656,14 @@ bool WebRtcVideoChannel2::SendRtp(const uint8_t* data, size_t len, const webrtc::PacketOptions& options) { rtc::Buffer packet(data, len, kMaxRtpPacketLen); - return MediaChannel::SendPacket(&packet); + rtc::PacketOptions rtc_options; + rtc_options.packet_id = options.packet_id; + return MediaChannel::SendPacket(&packet, rtc_options); } bool WebRtcVideoChannel2::SendRtcp(const uint8_t* data, size_t len) { rtc::Buffer packet(data, len, kMaxRtpPacketLen); - return MediaChannel::SendRtcp(&packet); + return MediaChannel::SendRtcp(&packet, rtc::PacketOptions()); } void WebRtcVideoChannel2::StartAllSendStreams() { diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc index 5dab1d6f15..558bbe85f2 100644 --- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc +++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc @@ -40,6 +40,7 @@ #include "webrtc/base/arraysize.h" #include "webrtc/base/gunit.h" #include "webrtc/base/stringutils.h" +#include "webrtc/test/field_trial.h" #include "webrtc/video_encoder.h" namespace { @@ -108,9 +109,13 @@ void VerifySendStreamHasRtxTypes(const webrtc::VideoSendStream::Config& config, namespace cricket { class WebRtcVideoEngine2Test : public ::testing::Test { public: - WebRtcVideoEngine2Test() : WebRtcVideoEngine2Test(nullptr) {} - WebRtcVideoEngine2Test(WebRtcVoiceEngine* voice_engine) - : call_(webrtc::Call::Create(webrtc::Call::Config())), + WebRtcVideoEngine2Test() : WebRtcVideoEngine2Test("") {} + explicit WebRtcVideoEngine2Test(const char* field_trials) + : WebRtcVideoEngine2Test(nullptr, field_trials) {} + WebRtcVideoEngine2Test(WebRtcVoiceEngine* voice_engine, + const char* field_trials) + : override_field_trials_(field_trials), + call_(webrtc::Call::Create(webrtc::Call::Config())), engine_() { std::vector engine_codecs = engine_.codecs(); RTC_DCHECK(!engine_codecs.empty()); @@ -144,6 +149,7 @@ class WebRtcVideoEngine2Test : public ::testing::Test { cricket::WebRtcVideoDecoderFactory* decoder_factory, const std::vector& codecs); + webrtc::test::ScopedFieldTrials override_field_trials_; // Used in WebRtcVideoEngine2VoiceTest, but defined here so it's properly // initialized when the constructor is called. rtc::scoped_ptr call_; @@ -258,6 +264,26 @@ TEST_F(WebRtcVideoEngine2Test, SupportsAbsoluteSenderTimeHeaderExtension) { FAIL() << "Absolute Sender Time extension not in header-extension list."; } +class WebRtcVideoEngine2WithSendSideBweTest : public WebRtcVideoEngine2Test { + public: + WebRtcVideoEngine2WithSendSideBweTest() + : WebRtcVideoEngine2Test("WebRTC-SendSideBwe/Enabled/") {} +}; + +TEST_F(WebRtcVideoEngine2WithSendSideBweTest, + SupportsTransportSequenceNumberHeaderExtension) { + std::vector extensions = engine_.rtp_header_extensions(); + ASSERT_FALSE(extensions.empty()); + for (size_t i = 0; i < extensions.size(); ++i) { + if (extensions[i].uri == kRtpTransportSequenceNumberHeaderExtension) { + EXPECT_EQ(kRtpTransportSequenceNumberHeaderExtensionDefaultId, + extensions[i].id); + return; + } + } + FAIL() << "Transport sequence number extension not in header-extension list."; +} + TEST_F(WebRtcVideoEngine2Test, SupportsVideoRotationHeaderExtension) { std::vector extensions = engine_.rtp_header_extensions(); ASSERT_FALSE(extensions.empty()); @@ -895,7 +921,9 @@ TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_SendVp8HdAndReceiveAdaptedVp8Vga) { class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test { public: - WebRtcVideoChannel2Test() : last_ssrc_(0) {} + WebRtcVideoChannel2Test() : WebRtcVideoChannel2Test("") {} + explicit WebRtcVideoChannel2Test(const char* field_trials) + : WebRtcVideoEngine2Test(field_trials), last_ssrc_(0) {} void SetUp() override { fake_call_.reset(new FakeCall(webrtc::Call::Config())); engine_.Init(); @@ -1171,6 +1199,26 @@ TEST_F(WebRtcVideoChannel2Test, RecvAbsoluteSendTimeHeaderExtensions) { webrtc::RtpExtension::kAbsSendTime); } +class WebRtcVideoChannel2WithSendSideBweTest : public WebRtcVideoChannel2Test { + public: + WebRtcVideoChannel2WithSendSideBweTest() + : WebRtcVideoChannel2Test("WebRTC-SendSideBwe/Enabled/") {} +}; + +// Test support for transport sequence number header extension. +TEST_F(WebRtcVideoChannel2WithSendSideBweTest, + SendTransportSequenceNumberHeaderExtensions) { + TestSetSendRtpHeaderExtensions( + kRtpTransportSequenceNumberHeaderExtension, + webrtc::RtpExtension::kTransportSequenceNumber); +} +TEST_F(WebRtcVideoChannel2WithSendSideBweTest, + RecvTransportSequenceNumberHeaderExtensions) { + TestSetRecvRtpHeaderExtensions( + kRtpTransportSequenceNumberHeaderExtension, + webrtc::RtpExtension::kTransportSequenceNumber); +} + // Test support for video rotation header extension. TEST_F(WebRtcVideoChannel2Test, SendVideoRotationHeaderExtensions) { TestSetSendRtpHeaderExtensions(kRtpVideoRotationHeaderExtension, diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index a3ea0f9a74..caaf87ea07 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc @@ -52,6 +52,7 @@ #include "webrtc/base/stringutils.h" #include "webrtc/common.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" +#include "webrtc/system_wrappers/interface/field_trial.h" namespace cricket { namespace { @@ -431,6 +432,11 @@ void WebRtcVoiceEngine::Construct() { rtp_header_extensions_.push_back( RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); + if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe") == "Enabled") { + rtp_header_extensions_.push_back(RtpHeaderExtension( + kRtpTransportSequenceNumberHeaderExtension, + kRtpTransportSequenceNumberHeaderExtensionDefaultId)); + } options_ = GetDefaultEngineOptions(); } diff --git a/talk/media/webrtc/webrtcvoiceengine.h b/talk/media/webrtc/webrtcvoiceengine.h index 5121c08b79..cba945657c 100644 --- a/talk/media/webrtc/webrtcvoiceengine.h +++ b/talk/media/webrtc/webrtcvoiceengine.h @@ -226,13 +226,15 @@ class WebRtcVoiceMediaChannel : public VoiceMediaChannel, const webrtc::PacketOptions& options) override { rtc::Buffer packet(reinterpret_cast(data), len, kMaxRtpPacketLen); - return VoiceMediaChannel::SendPacket(&packet); + rtc::PacketOptions rtc_options; + rtc_options.packet_id = options.packet_id; + return VoiceMediaChannel::SendPacket(&packet, rtc_options); } bool SendRtcp(const uint8_t* data, size_t len) override { rtc::Buffer packet(reinterpret_cast(data), len, kMaxRtpPacketLen); - return VoiceMediaChannel::SendRtcp(&packet); + return VoiceMediaChannel::SendRtcp(&packet, rtc::PacketOptions()); } void OnError(int error); diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc index c0f7f23f33..91a6d8cb5a 100644 --- a/talk/session/media/channel.cc +++ b/talk/session/media/channel.cc @@ -67,7 +67,7 @@ static void SafeSetError(const std::string& message, std::string* error_desc) { struct PacketMessageData : public rtc::MessageData { rtc::Buffer packet; - rtc::DiffServCodePoint dscp; + rtc::PacketOptions options; }; struct ScreencastEventMessageData : public rtc::MessageData { @@ -423,13 +423,13 @@ bool BaseChannel::IsReadyToSend() const { } bool BaseChannel::SendPacket(rtc::Buffer* packet, - rtc::DiffServCodePoint dscp) { - return SendPacket(false, packet, dscp); + const rtc::PacketOptions& options) { + return SendPacket(false, packet, options); } bool BaseChannel::SendRtcp(rtc::Buffer* packet, - rtc::DiffServCodePoint dscp) { - return SendPacket(true, packet, dscp); + const rtc::PacketOptions& options) { + return SendPacket(true, packet, options); } int BaseChannel::SetOption(SocketType type, rtc::Socket::Option opt, @@ -498,8 +498,9 @@ bool BaseChannel::PacketIsRtcp(const TransportChannel* channel, rtcp_mux_filter_.DemuxRtcp(data, static_cast(len))); } -bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet, - rtc::DiffServCodePoint dscp) { +bool BaseChannel::SendPacket(bool rtcp, + rtc::Buffer* packet, + const rtc::PacketOptions& options) { // SendPacket gets called from MediaEngine, typically on an encoder thread. // If the thread is not our worker thread, we will post to our worker // so that the real work happens on our worker. This avoids us having to @@ -512,7 +513,7 @@ bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet, int message_id = (!rtcp) ? MSG_RTPPACKET : MSG_RTCPPACKET; PacketMessageData* data = new PacketMessageData; data->packet = packet->Pass(); - data->dscp = dscp; + data->options = options; worker_thread_->Post(this, message_id, data); return true; } @@ -535,7 +536,8 @@ bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet, return false; } - rtc::PacketOptions options(dscp); + rtc::PacketOptions updated_options; + updated_options = options; // Protect if needed. if (srtp_filter_.IsActive()) { bool res; @@ -551,21 +553,22 @@ bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet, res = srtp_filter_.ProtectRtp( data, len, static_cast(packet->capacity()), &len); #else - options.packet_time_params.rtp_sendtime_extension_id = + updated_options.packet_time_params.rtp_sendtime_extension_id = rtp_abs_sendtime_extn_id_; res = srtp_filter_.ProtectRtp( data, len, static_cast(packet->capacity()), &len, - &options.packet_time_params.srtp_packet_index); + &updated_options.packet_time_params.srtp_packet_index); // If protection succeeds, let's get auth params from srtp. if (res) { uint8_t* auth_key = NULL; int key_len; res = srtp_filter_.GetRtpAuthParams( - &auth_key, &key_len, &options.packet_time_params.srtp_auth_tag_len); + &auth_key, &key_len, + &updated_options.packet_time_params.srtp_auth_tag_len); if (res) { - options.packet_time_params.srtp_auth_key.resize(key_len); - options.packet_time_params.srtp_auth_key.assign(auth_key, - auth_key + key_len); + updated_options.packet_time_params.srtp_auth_key.resize(key_len); + updated_options.packet_time_params.srtp_auth_key.assign( + auth_key, auth_key + key_len); } } #endif @@ -605,7 +608,7 @@ bool BaseChannel::SendPacket(bool rtcp, rtc::Buffer* packet, // Bon voyage. int ret = - channel->SendPacket(packet->data(), packet->size(), options, + channel->SendPacket(packet->data(), packet->size(), updated_options, (secure() && secure_dtls()) ? PF_SRTP_BYPASS : 0); if (ret != static_cast(packet->size())) { if (channel->GetError() == EWOULDBLOCK) { @@ -1143,7 +1146,7 @@ bool BaseChannel::UpdateLocalStreams_w(const std::vector& streams, it != streams.end(); ++it) { if (!GetStreamBySsrc(local_streams_, it->first_ssrc())) { if (media_channel()->AddSendStream(*it)) { - LOG(LS_INFO) << "Add send ssrc: " << it->ssrcs[0]; + LOG(LS_INFO) << "Add send stream ssrc: " << it->ssrcs[0]; } else { std::ostringstream desc; desc << "Failed to add send stream ssrc: " << it->first_ssrc(); @@ -1244,7 +1247,8 @@ void BaseChannel::OnMessage(rtc::Message *pmsg) { case MSG_RTPPACKET: case MSG_RTCPPACKET: { PacketMessageData* data = static_cast(pmsg->pdata); - SendPacket(pmsg->message_id == MSG_RTCPPACKET, &data->packet, data->dscp); + SendPacket(pmsg->message_id == MSG_RTCPPACKET, &data->packet, + data->options); delete data; // because it is Posted break; } diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h index d7f93c73b4..27088c921c 100644 --- a/talk/session/media/channel.h +++ b/talk/session/media/channel.h @@ -199,9 +199,8 @@ class BaseChannel // NetworkInterface implementation, called by MediaEngine virtual bool SendPacket(rtc::Buffer* packet, - rtc::DiffServCodePoint dscp); - virtual bool SendRtcp(rtc::Buffer* packet, - rtc::DiffServCodePoint dscp); + const rtc::PacketOptions& options); + virtual bool SendRtcp(rtc::Buffer* packet, const rtc::PacketOptions& options); // From TransportChannel void OnWritableState(TransportChannel* channel); @@ -214,8 +213,9 @@ class BaseChannel bool PacketIsRtcp(const TransportChannel* channel, const char* data, size_t len); - bool SendPacket(bool rtcp, rtc::Buffer* packet, - rtc::DiffServCodePoint dscp); + bool SendPacket(bool rtcp, + rtc::Buffer* packet, + const rtc::PacketOptions& options); virtual bool WantsPacket(bool rtcp, rtc::Buffer* packet); void HandlePacket(bool rtcp, rtc::Buffer* packet, const rtc::PacketTime& packet_time); @@ -261,7 +261,7 @@ class BaseChannel // Helper method to get RTP Absoulute SendTime extension header id if // present in remote supported extensions list. void MaybeCacheRtpAbsSendTimeHeaderExtension( - const std::vector& extensions); + const std::vector& extensions); bool CheckSrtpConfig(const std::vector& cryptos, bool* dtls, @@ -470,8 +470,6 @@ class VideoChannel : public BaseChannel { bool SendIntraFrame(); bool RequestIntraFrame(); - // Configure sending media on the stream with SSRC |ssrc| - // If there is only one sending stream SSRC 0 can be used. bool SetVideoSend(uint32_t ssrc, bool enable, const VideoOptions* options); private: diff --git a/talk/session/media/channel_unittest.cc b/talk/session/media/channel_unittest.cc index 1b14cdac9e..18233202b6 100644 --- a/talk/session/media/channel_unittest.cc +++ b/talk/session/media/channel_unittest.cc @@ -294,11 +294,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { bool SendRtp1() { return media_channel1_->SendRtp(rtp_packet_.c_str(), - static_cast(rtp_packet_.size())); + static_cast(rtp_packet_.size()), + rtc::PacketOptions()); } bool SendRtp2() { return media_channel2_->SendRtp(rtp_packet_.c_str(), - static_cast(rtp_packet_.size())); + static_cast(rtp_packet_.size()), + rtc::PacketOptions()); } bool SendRtcp1() { return media_channel1_->SendRtcp(rtcp_packet_.c_str(), @@ -311,13 +313,13 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Methods to send custom data. bool SendCustomRtp1(uint32_t ssrc, int sequence_number, int pl_type = -1) { std::string data(CreateRtpData(ssrc, sequence_number, pl_type)); - return media_channel1_->SendRtp(data.c_str(), - static_cast(data.size())); + return media_channel1_->SendRtp(data.c_str(), static_cast(data.size()), + rtc::PacketOptions()); } bool SendCustomRtp2(uint32_t ssrc, int sequence_number, int pl_type = -1) { std::string data(CreateRtpData(ssrc, sequence_number, pl_type)); - return media_channel2_->SendRtp(data.c_str(), - static_cast(data.size())); + return media_channel2_->SendRtp(data.c_str(), static_cast(data.size()), + rtc::PacketOptions()); } bool SendCustomRtcp1(uint32_t ssrc) { std::string data(CreateRtcpData(ssrc)); @@ -957,7 +959,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { public: LastWordMediaChannel() : T::MediaChannel(NULL, typename T::Options()) {} ~LastWordMediaChannel() { - T::MediaChannel::SendRtp(kPcmuFrame, sizeof(kPcmuFrame)); + T::MediaChannel::SendRtp(kPcmuFrame, sizeof(kPcmuFrame), + rtc::PacketOptions()); T::MediaChannel::SendRtcp(kRtcpReport, sizeof(kRtcpReport)); } }; @@ -1709,21 +1712,24 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { &error_handler, &SrtpErrorHandler::OnSrtpError); // Testing failures in sending packets. - EXPECT_FALSE(media_channel2_->SendRtp(kBadPacket, sizeof(kBadPacket))); + EXPECT_FALSE(media_channel2_->SendRtp(kBadPacket, sizeof(kBadPacket), + rtc::PacketOptions())); // The first failure will trigger an error. EXPECT_EQ_WAIT(cricket::SrtpFilter::ERROR_FAIL, error_handler.error_, 500); EXPECT_EQ(cricket::SrtpFilter::PROTECT, error_handler.mode_); error_handler.error_ = cricket::SrtpFilter::ERROR_NONE; error_handler.mode_ = cricket::SrtpFilter::UNPROTECT; // The next 250 ms failures will not trigger an error. - EXPECT_FALSE(media_channel2_->SendRtp(kBadPacket, sizeof(kBadPacket))); + EXPECT_FALSE(media_channel2_->SendRtp(kBadPacket, sizeof(kBadPacket), + rtc::PacketOptions())); // Wait for a while to ensure no message comes in. rtc::Thread::Current()->ProcessMessages(200); EXPECT_EQ(cricket::SrtpFilter::ERROR_NONE, error_handler.error_); EXPECT_EQ(cricket::SrtpFilter::UNPROTECT, error_handler.mode_); // Wait for a little more - the error will be triggered again. rtc::Thread::Current()->ProcessMessages(200); - EXPECT_FALSE(media_channel2_->SendRtp(kBadPacket, sizeof(kBadPacket))); + EXPECT_FALSE(media_channel2_->SendRtp(kBadPacket, sizeof(kBadPacket), + rtc::PacketOptions())); EXPECT_EQ_WAIT(cricket::SrtpFilter::ERROR_FAIL, error_handler.error_, 500); EXPECT_EQ(cricket::SrtpFilter::PROTECT, error_handler.mode_); diff --git a/talk/session/media/channelmanager_unittest.cc b/talk/session/media/channelmanager_unittest.cc index 6074d6431a..fa6aa2cab6 100644 --- a/talk/session/media/channelmanager_unittest.cc +++ b/talk/session/media/channelmanager_unittest.cc @@ -25,7 +25,7 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "talk/app/webrtc/mediacontroller.h" +#include "talk/app/webrtc/fakemediacontroller.h" #include "talk/media/base/fakecapturemanager.h" #include "talk/media/base/fakemediaengine.h" #include "talk/media/base/fakevideocapturer.h" @@ -50,37 +50,24 @@ static const VideoCodec kVideoCodecs[] = { VideoCodec(96, "rtx", 100, 200, 300, 0), }; -class FakeMediaController : public webrtc::MediaControllerInterface { - public: - explicit FakeMediaController(webrtc::Call* call) : call_(call) { - RTC_DCHECK(nullptr != call); - } - ~FakeMediaController() override {} - webrtc::Call* call_w() override { return call_; } - - private: - webrtc::Call* call_; -}; - class ChannelManagerTest : public testing::Test { protected: ChannelManagerTest() - : fake_call_(webrtc::Call::Config()), - fake_mc_(&fake_call_), - fme_(NULL), - fcm_(NULL), - cm_(NULL) {} + : fme_(new cricket::FakeMediaEngine()), + fdme_(new cricket::FakeDataEngine()), + fcm_(new cricket::FakeCaptureManager()), + cm_(new cricket::ChannelManager(fme_, + fdme_, + fcm_, + rtc::Thread::Current())), + fake_call_(webrtc::Call::Config()), + fake_mc_(cm_, &fake_call_), + transport_controller_( + new cricket::FakeTransportController(ICEROLE_CONTROLLING)) {} virtual void SetUp() { - fme_ = new cricket::FakeMediaEngine(); fme_->SetAudioCodecs(MAKE_VECTOR(kAudioCodecs)); fme_->SetVideoCodecs(MAKE_VECTOR(kVideoCodecs)); - fdme_ = new cricket::FakeDataEngine(); - fcm_ = new cricket::FakeCaptureManager(); - cm_ = new cricket::ChannelManager( - fme_, fdme_, fcm_, rtc::Thread::Current()); - transport_controller_ = - new cricket::FakeTransportController(ICEROLE_CONTROLLING); } virtual void TearDown() { @@ -93,12 +80,12 @@ class ChannelManagerTest : public testing::Test { } rtc::Thread worker_; - cricket::FakeCall fake_call_; - cricket::FakeMediaController fake_mc_; cricket::FakeMediaEngine* fme_; cricket::FakeDataEngine* fdme_; cricket::FakeCaptureManager* fcm_; cricket::ChannelManager* cm_; + cricket::FakeCall fake_call_; + cricket::FakeMediaController fake_mc_; cricket::FakeTransportController* transport_controller_; }; diff --git a/webrtc/base/asyncpacketsocket.h b/webrtc/base/asyncpacketsocket.h index 07cacf751f..949ec67c83 100644 --- a/webrtc/base/asyncpacketsocket.h +++ b/webrtc/base/asyncpacketsocket.h @@ -34,10 +34,11 @@ struct PacketTimeUpdateParams { // This structure holds meta information for the packet which is about to send // over network. struct PacketOptions { - PacketOptions() : dscp(DSCP_NO_CHANGE) {} - explicit PacketOptions(DiffServCodePoint dscp) : dscp(dscp) {} + PacketOptions() : dscp(DSCP_NO_CHANGE), packet_id(-1) {} + explicit PacketOptions(DiffServCodePoint dscp) : dscp(dscp), packet_id(-1) {} DiffServCodePoint dscp; + int packet_id; // 16 bits, -1 represents "not set". PacketTimeUpdateParams packet_time_params; }; @@ -109,6 +110,9 @@ class AsyncPacketSocket : public sigslot::has_slots<> { const SocketAddress&, const PacketTime&> SignalReadPacket; + // Emitted each time a packet is sent. + sigslot::signal2 SignalSentPacket; + // Emitted when the socket is currently able to send. sigslot::signal1 SignalReadyToSend; diff --git a/webrtc/base/asynctcpsocket.cc b/webrtc/base/asynctcpsocket.cc index 66fd3f1e00..8e83cd1ea2 100644 --- a/webrtc/base/asynctcpsocket.cc +++ b/webrtc/base/asynctcpsocket.cc @@ -268,6 +268,9 @@ int AsyncTCPSocket::Send(const void *pv, size_t cb, return res; } + rtc::SentPacket sent_packet(options.packet_id, rtc::Time()); + SignalSentPacket(this, sent_packet); + // We claim to have sent the whole thing, even if we only sent partial return static_cast(cb); } diff --git a/webrtc/base/asyncudpsocket.cc b/webrtc/base/asyncudpsocket.cc index 3e2ecc4cda..51a8fa0af0 100644 --- a/webrtc/base/asyncudpsocket.cc +++ b/webrtc/base/asyncudpsocket.cc @@ -60,13 +60,19 @@ SocketAddress AsyncUDPSocket::GetRemoteAddress() const { int AsyncUDPSocket::Send(const void *pv, size_t cb, const rtc::PacketOptions& options) { - return socket_->Send(pv, cb); + rtc::SentPacket sent_packet(options.packet_id, rtc::Time()); + int ret = socket_->Send(pv, cb); + SignalSentPacket(this, sent_packet); + return ret; } int AsyncUDPSocket::SendTo(const void *pv, size_t cb, const SocketAddress& addr, const rtc::PacketOptions& options) { - return socket_->SendTo(pv, cb, addr); + rtc::SentPacket sent_packet(options.packet_id, rtc::Time()); + int ret = socket_->SendTo(pv, cb, addr); + SignalSentPacket(this, sent_packet); + return ret; } int AsyncUDPSocket::Close() { diff --git a/webrtc/base/base_tests.gyp b/webrtc/base/base_tests.gyp index 4d7d74c506..f25f3e7b80 100644 --- a/webrtc/base/base_tests.gyp +++ b/webrtc/base/base_tests.gyp @@ -29,6 +29,7 @@ 'dependencies': [ 'base.gyp:rtc_base', '<(DEPTH)/testing/gtest.gyp:gtest', + '<(webrtc_root)/test/test.gyp:field_trial', ], 'direct_dependent_settings': { 'defines': [ diff --git a/webrtc/base/socket.h b/webrtc/base/socket.h index 8d98d273df..22326cb997 100644 --- a/webrtc/base/socket.h +++ b/webrtc/base/socket.h @@ -124,6 +124,15 @@ inline bool IsBlockingError(int e) { return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS); } +struct SentPacket { + SentPacket() : packet_id(-1), send_time_ms(-1) {} + SentPacket(int packet_id, int64_t send_time_ms) + : packet_id(packet_id), send_time_ms(send_time_ms) {} + + int packet_id; + int64_t send_time_ms; +}; + // General interface for the socket implementations of various networks. The // methods match those of normal UNIX sockets very closely. class Socket { diff --git a/webrtc/base/unittest_main.cc b/webrtc/base/unittest_main.cc index e243c52e2c..f952b2d547 100644 --- a/webrtc/base/unittest_main.cc +++ b/webrtc/base/unittest_main.cc @@ -19,9 +19,16 @@ #include "webrtc/base/gunit.h" #include "webrtc/base/logging.h" #include "webrtc/base/ssladapter.h" +#include "webrtc/test/field_trial.h" DEFINE_bool(help, false, "prints this message"); DEFINE_string(log, "", "logging options to use"); +DEFINE_string( + force_fieldtrials, + "", + "Field trials control experimental feature code which can be forced. " + "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/" + " will assign the group Enable to field trial WebRTC-FooFeature."); #if defined(WEBRTC_WIN) DEFINE_int(crt_break_alloc, -1, "memory allocation to break on"); DEFINE_bool(default_error_handlers, false, @@ -61,6 +68,8 @@ int main(int argc, char** argv) { return 0; } + webrtc::test::InitFieldTrialsFromString(FLAG_force_fieldtrials); + #if defined(WEBRTC_WIN) if (!FLAG_default_error_handlers) { // Make sure any errors don't throw dialogs hanging the test run. diff --git a/webrtc/call.h b/webrtc/call.h index 033e1a20db..e6e8cdee0b 100644 --- a/webrtc/call.h +++ b/webrtc/call.h @@ -16,6 +16,7 @@ #include "webrtc/common_types.h" #include "webrtc/audio_receive_stream.h" #include "webrtc/audio_send_stream.h" +#include "webrtc/base/socket.h" #include "webrtc/video_receive_stream.h" #include "webrtc/video_send_stream.h" @@ -137,6 +138,8 @@ class Call { const Config::BitrateConfig& bitrate_config) = 0; virtual void SignalNetworkState(NetworkState state) = 0; + virtual void OnSentPacket(const rtc::SentPacket& sent_packet) = 0; + virtual ~Call() {} }; diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc index 0ccfb611e4..a32a823943 100644 --- a/webrtc/call/call.cc +++ b/webrtc/call/call.cc @@ -77,6 +77,8 @@ class Call : public webrtc::Call, public PacketReceiver { const webrtc::Call::Config::BitrateConfig& bitrate_config) override; void SignalNetworkState(NetworkState state) override; + void OnSentPacket(const rtc::SentPacket& sent_packet) override; + private: DeliveryStatus DeliverRtcp(MediaType media_type, const uint8_t* packet, size_t length); @@ -411,6 +413,10 @@ void Call::SignalNetworkState(NetworkState state) { } } +void Call::OnSentPacket(const rtc::SentPacket& sent_packet) { + channel_group_->OnSentPacket(sent_packet); +} + void Call::ConfigureSync(const std::string& sync_group) { // Set sync only if there was no previous one. if (config_.voice_engine == nullptr || sync_group.empty()) diff --git a/webrtc/config.cc b/webrtc/config.cc index ddff931e24..3a74e5238e 100644 --- a/webrtc/config.cc +++ b/webrtc/config.cc @@ -36,7 +36,7 @@ const char* RtpExtension::kVideoRotation = "urn:3gpp:video-orientation"; const char* RtpExtension::kAudioLevel = "urn:ietf:params:rtp-hdrext:ssrc-audio-level"; const char* RtpExtension::kTransportSequenceNumber = - "http://www.webrtc.org/experiments/rtp-hdrext/transport-sequence-number"; + "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions"; bool RtpExtension::IsSupportedForAudio(const std::string& name) { return name == webrtc::RtpExtension::kAbsSendTime || diff --git a/webrtc/libjingle_examples.gyp b/webrtc/libjingle_examples.gyp index abe7e8a252..ab888184f6 100755 --- a/webrtc/libjingle_examples.gyp +++ b/webrtc/libjingle_examples.gyp @@ -81,6 +81,7 @@ ], 'dependencies': [ '../talk/libjingle.gyp:libjingle_peerconnection', + '<(webrtc_root)/system_wrappers/system_wrappers.gyp:field_trial_default', '<@(libjingle_tests_additional_deps)', ], 'conditions': [ @@ -139,6 +140,7 @@ 'target_name': 'apprtc_common', 'type': 'static_library', 'dependencies': [ + '<(webrtc_root)/system_wrappers/system_wrappers.gyp:field_trial_default', '../talk/libjingle.gyp:libjingle_peerconnection_objc', ], 'sources': [ diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc index 5f51bc55e9..11922d298e 100644 --- a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc +++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc @@ -49,11 +49,17 @@ void TransportFeedbackAdapter::SetBitrateEstimator( } } -void TransportFeedbackAdapter::OnPacketSent(const PacketInfo& info) { +void TransportFeedbackAdapter::OnSentPacket(const PacketInfo& info) { rtc::CritScope cs(&lock_); send_time_history_.AddAndRemoveOld(info); } +void TransportFeedbackAdapter::UpdateSendTime(uint16_t sequence_number, + int64_t send_time_ms) { + rtc::CritScope cs(&lock_); + send_time_history_.UpdateSendTime(sequence_number, send_time_ms); +} + void TransportFeedbackAdapter::OnTransportFeedback( const rtcp::TransportFeedback& feedback) { int64_t timestamp_us = feedback.GetBaseTimeUs(); diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h index 56b2c73873..7267ca03a4 100644 --- a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h +++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h @@ -33,7 +33,9 @@ class TransportFeedbackAdapter : public TransportFeedbackObserver, ProcessThread* process_thread); virtual ~TransportFeedbackAdapter(); - void OnPacketSent(const PacketInfo& info) override; + void OnSentPacket(const PacketInfo& info) override; + + void UpdateSendTime(uint16_t sequence_number, int64_t send_time_ms); void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override; diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc index 1bf4b1ec3e..3504ca7478 100644 --- a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter_unittest.cc @@ -103,9 +103,9 @@ class TransportFeedbackAdapterTest : public ::testing::Test { } // Utility method, to reset arrival_time_ms before adding send time. - void OnPacketSent(PacketInfo info) { + void OnSentPacket(PacketInfo info) { info.arrival_time_ms = 0; - adapter_->OnPacketSent(info); + adapter_->OnSentPacket(info); } SimulatedClock clock_; @@ -125,7 +125,7 @@ TEST_F(TransportFeedbackAdapterTest, AdaptsFeedbackAndPopulatesSendTimes) { packets.push_back(PacketInfo(140, 240, 4, 1500, true)); for (const PacketInfo& packet : packets) - OnPacketSent(packet); + OnSentPacket(packet); rtcp::TransportFeedback feedback; feedback.WithBase(packets[0].sequence_number, @@ -160,7 +160,7 @@ TEST_F(TransportFeedbackAdapterTest, HandlesDroppedPackets) { for (const PacketInfo& packet : packets) { if (packet.sequence_number >= kSendSideDropBefore) - OnPacketSent(packet); + OnSentPacket(packet); } rtcp::TransportFeedback feedback; @@ -199,7 +199,7 @@ TEST_F(TransportFeedbackAdapterTest, SendTimeWrapsBothWays) { packets.push_back(PacketInfo(kHighArrivalTimeMs, 220, 2, 1500, true)); for (const PacketInfo& packet : packets) - OnPacketSent(packet); + OnSentPacket(packet); for (size_t i = 0; i < packets.size(); ++i) { rtc::scoped_ptr feedback( @@ -263,8 +263,8 @@ TEST_F(TransportFeedbackAdapterTest, TimestampDeltas) { // Packets will be added to send history. for (const PacketInfo& packet : sent_packets) - OnPacketSent(packet); - OnPacketSent(info); + OnSentPacket(packet); + OnSentPacket(info); // Create expected feedback and send into adapter. rtc::scoped_ptr feedback( diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h index a262a07b62..7789743b14 100644 --- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h +++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h @@ -313,7 +313,7 @@ class TransportFeedbackObserver { // Note: Transport-wide sequence number as sequence number. Arrival time // must be set to 0. - virtual void OnPacketSent(const PacketInfo& info) = 0; + virtual void OnSentPacket(const PacketInfo& info) = 0; virtual void OnTransportFeedback(const rtcp::TransportFeedback& feedback) = 0; }; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index 0c67c6920f..2ddc356416 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -672,8 +672,8 @@ size_t RTPSender::SendPadData(size_t bytes, break; if (using_transport_seq && transport_feedback_observer_) { - transport_feedback_observer_->OnPacketSent(PacketInfo( - 0, now_ms, options.packet_id, length, true)); + transport_feedback_observer_->OnSentPacket( + PacketInfo(0, now_ms, options.packet_id, length, true)); } bytes_sent += padding_bytes_in_packet; @@ -934,7 +934,7 @@ bool RTPSender::PrepareAndSendPacket(uint8_t* buffer, media_has_been_sent_ = true; } if (using_transport_seq && transport_feedback_observer_) { - transport_feedback_observer_->OnPacketSent( + transport_feedback_observer_->OnSentPacket( PacketInfo(0, now_ms, options.packet_id, length, true)); } UpdateRtpStats(buffer_to_send_ptr, length, rtp_header, send_over_rtx, diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc index bba7eb9de7..148a19108d 100644 --- a/webrtc/p2p/base/dtlstransportchannel.cc +++ b/webrtc/p2p/base/dtlstransportchannel.cc @@ -101,6 +101,8 @@ DtlsTransportChannelWrapper::DtlsTransportChannelWrapper( &DtlsTransportChannelWrapper::OnWritableState); channel_->SignalReadPacket.connect(this, &DtlsTransportChannelWrapper::OnReadPacket); + channel_->SignalSentPacket.connect( + this, &DtlsTransportChannelWrapper::OnSentPacket); channel_->SignalReadyToSend.connect(this, &DtlsTransportChannelWrapper::OnReadyToSend); channel_->SignalGatheringState.connect( @@ -510,6 +512,14 @@ void DtlsTransportChannelWrapper::OnReadPacket( } } +void DtlsTransportChannelWrapper::OnSentPacket( + TransportChannel* channel, + const rtc::SentPacket& sent_packet) { + ASSERT(rtc::Thread::Current() == worker_thread_); + + SignalSentPacket(this, sent_packet); +} + void DtlsTransportChannelWrapper::OnReadyToSend(TransportChannel* channel) { if (writable()) { SignalReadyToSend(this); diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h index 9a2ccdee99..b445c69efa 100644 --- a/webrtc/p2p/base/dtlstransportchannel.h +++ b/webrtc/p2p/base/dtlstransportchannel.h @@ -209,6 +209,8 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl { void OnWritableState(TransportChannel* channel); void OnReadPacket(TransportChannel* channel, const char* data, size_t size, const rtc::PacketTime& packet_time, int flags); + void OnSentPacket(TransportChannel* channel, + const rtc::SentPacket& sent_packet); void OnReadyToSend(TransportChannel* channel); void OnReceivingState(TransportChannel* channel); void OnDtlsEvent(rtc::StreamInterface* stream_, int sig, int err); @@ -223,7 +225,8 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl { Transport* transport_; // The transport_ that created us. rtc::Thread* worker_thread_; // Everything should occur on this thread. - TransportChannelImpl* channel_; // Underlying channel, owned by transport_. + // Underlying channel, owned by transport_. + TransportChannelImpl* const channel_; rtc::scoped_ptr dtls_; // The DTLS stream StreamInterfaceChannel* downward_; // Wrapper for channel_, owned by dtls_. std::vector srtp_ciphers_; // SRTP ciphers to use with DTLS. diff --git a/webrtc/p2p/base/dtlstransportchannel_unittest.cc b/webrtc/p2p/base/dtlstransportchannel_unittest.cc index 460e294a00..07e3b87847 100644 --- a/webrtc/p2p/base/dtlstransportchannel_unittest.cc +++ b/webrtc/p2p/base/dtlstransportchannel_unittest.cc @@ -33,6 +33,7 @@ static const char kIceUfrag1[] = "TESTICEUFRAG0001"; static const char kIcePwd1[] = "TESTICEPWD00000000000001"; static const size_t kPacketNumOffset = 8; static const size_t kPacketHeaderLen = 12; +static const int kFakePacketId = 0x1234; static bool IsRtpLeadByte(uint8_t b) { return ((b & 0xC0) == 0x80); @@ -86,6 +87,8 @@ class DtlsTestClient : public sigslot::has_slots<> { &DtlsTestClient::OnTransportChannelWritableState); channel->SignalReadPacket.connect(this, &DtlsTestClient::OnTransportChannelReadPacket); + channel->SignalSentPacket.connect( + this, &DtlsTestClient::OnTransportChannelSentPacket); channels_.push_back(channel); // Hook the raw packets so that we can verify they are encrypted. @@ -259,6 +262,7 @@ class DtlsTestClient : public sigslot::has_slots<> { // Only set the bypass flag if we've activated DTLS. int flags = (certificate_ && srtp) ? cricket::PF_SRTP_BYPASS : 0; rtc::PacketOptions packet_options; + packet_options.packet_id = kFakePacketId; int rv = channels_[channel]->SendPacket( packet.get(), size, packet_options, flags); ASSERT_GT(rv, 0); @@ -338,6 +342,13 @@ class DtlsTestClient : public sigslot::has_slots<> { ASSERT_EQ(expected_flags, flags); } + void OnTransportChannelSentPacket(cricket::TransportChannel* channel, + const rtc::SentPacket& sent_packet) { + sent_packet_ = sent_packet; + } + + rtc::SentPacket sent_packet() const { return sent_packet_; } + // Hook into the raw packet stream to make sure DTLS packets are encrypted. void OnFakeTransportChannelReadPacket(cricket::TransportChannel* channel, const char* data, size_t size, @@ -378,6 +389,7 @@ class DtlsTestClient : public sigslot::has_slots<> { bool negotiated_dtls_; bool received_dtls_client_hello_; bool received_dtls_server_hello_; + rtc::SentPacket sent_packet_; }; @@ -558,6 +570,15 @@ TEST_F(DtlsTransportChannelTest, TestTransfer) { TestTransfer(0, 1000, 100, false); } +// Connect without DTLS, and transfer some data. +TEST_F(DtlsTransportChannelTest, TestOnSentPacket) { + ASSERT_TRUE(Connect()); + EXPECT_EQ(client1_.sent_packet().send_time_ms, -1); + TestTransfer(0, 1000, 100, false); + EXPECT_EQ(kFakePacketId, client1_.sent_packet().packet_id); + EXPECT_GE(client1_.sent_packet().send_time_ms, 0); +} + // Create two channels without DTLS, and transfer some data. TEST_F(DtlsTransportChannelTest, TestTransferTwoChannels) { SetChannelCount(2); diff --git a/webrtc/p2p/base/faketransportcontroller.h b/webrtc/p2p/base/faketransportcontroller.h index 7d8e3d77e8..3e656fa4a3 100644 --- a/webrtc/p2p/base/faketransportcontroller.h +++ b/webrtc/p2p/base/faketransportcontroller.h @@ -31,10 +31,12 @@ namespace cricket { class FakeTransport; +namespace { struct PacketMessageData : public rtc::MessageData { PacketMessageData(const char* data, size_t len) : packet(data, len) {} rtc::Buffer packet; }; +} // namespace // Fake transport channel class, which can be passed to anything that needs a // transport channel. Can be informed of another FakeTransportChannel via @@ -208,6 +210,8 @@ class FakeTransportChannel : public TransportChannelImpl, } else { rtc::Thread::Current()->Send(this, 0, packet); } + rtc::SentPacket sent_packet(options.packet_id, rtc::Time()); + SignalSentPacket(this, sent_packet); return static_cast(len); } int SetOption(rtc::Socket::Option opt, int value) override { return true; } diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc index fc72131233..9d598f57f3 100644 --- a/webrtc/p2p/base/p2ptransportchannel.cc +++ b/webrtc/p2p/base/p2ptransportchannel.cc @@ -435,6 +435,7 @@ void P2PTransportChannel::OnPortReady(PortAllocatorSession *session, port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed); port->SignalRoleConflict.connect( this, &P2PTransportChannel::OnRoleConflict); + port->SignalSentPacket.connect(this, &P2PTransportChannel::OnSentPacket); // Attempt to create a connection from this new port to all of the remote // candidates that we were given so far. @@ -1356,6 +1357,13 @@ void P2PTransportChannel::OnReadPacket(Connection* connection, } } +void P2PTransportChannel::OnSentPacket(PortInterface* port, + const rtc::SentPacket& sent_packet) { + ASSERT(worker_thread_ == rtc::Thread::Current()); + + SignalSentPacket(this, sent_packet); +} + void P2PTransportChannel::OnReadyToSend(Connection* connection) { if (connection == best_connection_ && writable()) { SignalReadyToSend(this); diff --git a/webrtc/p2p/base/p2ptransportchannel.h b/webrtc/p2p/base/p2ptransportchannel.h index 5249639763..51979df8d8 100644 --- a/webrtc/p2p/base/p2ptransportchannel.h +++ b/webrtc/p2p/base/p2ptransportchannel.h @@ -207,6 +207,7 @@ class P2PTransportChannel : public TransportChannelImpl, void OnConnectionStateChange(Connection* connection); void OnReadPacket(Connection *connection, const char *data, size_t len, const rtc::PacketTime& packet_time); + void OnSentPacket(PortInterface* port, const rtc::SentPacket& sent_packet); void OnReadyToSend(Connection* connection); void OnConnectionDestroyed(Connection *connection); diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc index 39fff5f648..d34b05f8e9 100644 --- a/webrtc/p2p/base/port.cc +++ b/webrtc/p2p/base/port.cc @@ -310,6 +310,10 @@ void Port::OnReadPacket( } } +void Port::OnSentPacket(const rtc::SentPacket& sent_packet) { + PortInterface::SignalSentPacket(this, sent_packet); +} + void Port::OnReadyToSend() { AddressMap::iterator iter = connections_.begin(); for (; iter != connections_.end(); ++iter) { diff --git a/webrtc/p2p/base/port.h b/webrtc/p2p/base/port.h index dc548763de..01c45f26d8 100644 --- a/webrtc/p2p/base/port.h +++ b/webrtc/p2p/base/port.h @@ -275,6 +275,9 @@ class Port : public PortInterface, public rtc::MessageHandler, IceMessage* stun_msg, const std::string& remote_ufrag); + // Called when a packet has been sent to the socket. + void OnSentPacket(const rtc::SentPacket& sent_packet); + // Called when the socket is currently able to send. void OnReadyToSend(); diff --git a/webrtc/p2p/base/portinterface.h b/webrtc/p2p/base/portinterface.h index 0c5948e8ae..0f77036ac1 100644 --- a/webrtc/p2p/base/portinterface.h +++ b/webrtc/p2p/base/portinterface.h @@ -14,6 +14,7 @@ #include #include "webrtc/p2p/base/transport.h" +#include "webrtc/base/asyncpacketsocket.h" #include "webrtc/base/socketaddress.h" namespace rtc { @@ -112,6 +113,9 @@ class PortInterface { sigslot::signal4 SignalReadPacket; + // Emitted each time a packet is sent on this port. + sigslot::signal2 SignalSentPacket; + virtual std::string ToString() const = 0; protected: diff --git a/webrtc/p2p/base/relayport.cc b/webrtc/p2p/base/relayport.cc index ccddab0e98..88adcf2f88 100644 --- a/webrtc/p2p/base/relayport.cc +++ b/webrtc/p2p/base/relayport.cc @@ -144,6 +144,10 @@ class RelayEntry : public rtc::MessageHandler, const char* data, size_t size, const rtc::SocketAddress& remote_addr, const rtc::PacketTime& packet_time); + + void OnSentPacket(rtc::AsyncPacketSocket* socket, + const rtc::SentPacket& sent_packet); + // Called when the socket is currently able to send. void OnReadyToSend(rtc::AsyncPacketSocket* socket); @@ -508,6 +512,7 @@ void RelayEntry::Connect() { // Otherwise, create the new connection and configure any socket options. socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket); + socket->SignalSentPacket.connect(this, &RelayEntry::OnSentPacket); socket->SignalReadyToSend.connect(this, &RelayEntry::OnReadyToSend); current_connection_ = new RelayConnection(ra, socket, port()->thread()); for (size_t i = 0; i < port_->options().size(); ++i) { @@ -747,6 +752,11 @@ void RelayEntry::OnReadPacket( PROTO_UDP, packet_time); } +void RelayEntry::OnSentPacket(rtc::AsyncPacketSocket* socket, + const rtc::SentPacket& sent_packet) { + port_->OnSentPacket(sent_packet); +} + void RelayEntry::OnReadyToSend(rtc::AsyncPacketSocket* socket) { if (connected()) { port_->OnReadyToSend(); diff --git a/webrtc/p2p/base/stunport.cc b/webrtc/p2p/base/stunport.cc index 615bbfe55a..1598fe43ce 100644 --- a/webrtc/p2p/base/stunport.cc +++ b/webrtc/p2p/base/stunport.cc @@ -217,6 +217,7 @@ bool UDPPort::Init() { } socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket); } + socket_->SignalSentPacket.connect(this, &UDPPort::OnSentPacket); socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend); socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady); requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket); @@ -329,6 +330,11 @@ void UDPPort::OnReadPacket( } } +void UDPPort::OnSentPacket(rtc::AsyncPacketSocket* socket, + const rtc::SentPacket& sent_packet) { + Port::OnSentPacket(sent_packet); +} + void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { Port::OnReadyToSend(); } diff --git a/webrtc/p2p/base/stunport.h b/webrtc/p2p/base/stunport.h index 488739c936..62b23cf074 100644 --- a/webrtc/p2p/base/stunport.h +++ b/webrtc/p2p/base/stunport.h @@ -140,6 +140,9 @@ class UDPPort : public Port { const rtc::SocketAddress& remote_addr, const rtc::PacketTime& packet_time); + void OnSentPacket(rtc::AsyncPacketSocket* socket, + const rtc::SentPacket& sent_packet); + void OnReadyToSend(rtc::AsyncPacketSocket* socket); // This method will send STUN binding request if STUN server address is set. diff --git a/webrtc/p2p/base/transportchannel.h b/webrtc/p2p/base/transportchannel.h index 1223618d0b..9dc9c3a495 100644 --- a/webrtc/p2p/base/transportchannel.h +++ b/webrtc/p2p/base/transportchannel.h @@ -48,7 +48,7 @@ enum TransportChannelState { // between the two sides of a session. class TransportChannel : public sigslot::has_slots<> { public: - explicit TransportChannel(const std::string& transport_name, int component) + TransportChannel(const std::string& transport_name, int component) : transport_name_(transport_name), component_(component), writable_(false), @@ -134,6 +134,9 @@ class TransportChannel : public sigslot::has_slots<> { sigslot::signal5 SignalReadPacket; + // Signalled each time a packet is sent on this channel. + sigslot::signal2 SignalSentPacket; + // This signal occurs when there is a change in the way that packets are // being routed, i.e. to a different remote location. The candidate // indicates where and how we are currently sending media. diff --git a/webrtc/transport.h b/webrtc/transport.h index 7b62f6543d..b9df7c31d1 100644 --- a/webrtc/transport.h +++ b/webrtc/transport.h @@ -17,6 +17,8 @@ namespace webrtc { +// TODO(holmer): Look into unifying this with the PacketOptions in +// asyncpacketsocket.h. struct PacketOptions { // A 16 bits positive id. Negative ids are invalid and should be interpreted // as packet_id not being set. diff --git a/webrtc/video_engine/vie_channel_group.cc b/webrtc/video_engine/vie_channel_group.cc index 7ed0341056..a76c50ac99 100644 --- a/webrtc/video_engine/vie_channel_group.cc +++ b/webrtc/video_engine/vie_channel_group.cc @@ -445,4 +445,11 @@ void ChannelGroup::OnNetworkChanged(uint32_t target_bitrate_bps, PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000, pad_up_to_bitrate_bps / 1000); } + +void ChannelGroup::OnSentPacket(const rtc::SentPacket& sent_packet) { + if (transport_feedback_adapter_) { + transport_feedback_adapter_->UpdateSendTime(sent_packet.packet_id, + sent_packet.send_time_ms); + } +} } // namespace webrtc diff --git a/webrtc/video_engine/vie_channel_group.h b/webrtc/video_engine/vie_channel_group.h index c2ae12745c..bb1a08ef85 100644 --- a/webrtc/video_engine/vie_channel_group.h +++ b/webrtc/video_engine/vie_channel_group.h @@ -18,6 +18,7 @@ #include "webrtc/base/criticalsection.h" #include "webrtc/base/scoped_ptr.h" +#include "webrtc/base/socket.h" #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" #include "webrtc/video_receive_stream.h" #include "webrtc/video_send_stream.h" @@ -82,6 +83,8 @@ class ChannelGroup : public BitrateObserver { uint8_t fraction_loss, int64_t rtt) override; + void OnSentPacket(const rtc::SentPacket& sent_packet); + private: typedef std::map ChannelMap; typedef std::map EncoderMap;