diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 3d47b86132..0ae01a626b 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -246,6 +246,13 @@ struct RtcpStatistics { uint32_t cumulative_lost; uint32_t extended_max_sequence_number; uint32_t jitter; + + bool operator==(const RtcpStatistics& other) const { + return fraction_lost == other.fraction_lost && + cumulative_lost == other.cumulative_lost && + extended_max_sequence_number == other.extended_max_sequence_number && + jitter == other.jitter; + } }; // Callback, called whenever a new rtcp report block is transmitted. @@ -273,6 +280,13 @@ struct StreamDataCounters { uint32_t packets; // Number of packets. uint32_t retransmitted_packets; // Number of retransmitted packets. uint32_t fec_packets; // Number of redundancy packets. + + bool operator==(const StreamDataCounters& other) const { + return bytes == other.bytes && header_bytes == other.header_bytes && + padding_bytes == other.padding_bytes && packets == other.packets && + retransmitted_packets == other.retransmitted_packets && + fec_packets == other.fec_packets; + } }; // Callback, called whenever byte/packet counts have been updated. diff --git a/webrtc/config.h b/webrtc/config.h index 3ff3bb861f..f42895ae21 100644 --- a/webrtc/config.h +++ b/webrtc/config.h @@ -16,6 +16,7 @@ #include #include +#include "webrtc/common_types.h" #include "webrtc/typedefs.h" namespace webrtc { @@ -33,6 +34,22 @@ struct RtpStatistics { std::string c_name; }; +struct StreamStats { + StreamStats() : key_frames(0), delta_frames(0), bitrate_bps(0) {} + uint32_t key_frames; + uint32_t delta_frames; + int32_t bitrate_bps; + StreamDataCounters rtp_stats; + RtcpStatistics rtcp_stats; + + bool operator==(const StreamStats& other) const { + return key_frames == other.key_frames && + delta_frames == other.delta_frames && + bitrate_bps == other.bitrate_bps && rtp_stats == other.rtp_stats && + rtcp_stats == other.rtcp_stats; + } +}; + // Settings for NACK, see RFC 4585 for details. struct NackConfig { NackConfig() : rtp_history_ms(0) {} diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc new file mode 100644 index 0000000000..423d7146fc --- /dev/null +++ b/webrtc/video/send_statistics_proxy.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/video/send_statistics_proxy.h" + +#include + +#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" + +namespace webrtc { + +SendStatisticsProxy::SendStatisticsProxy( + const VideoSendStream::Config& config, + SendStatisticsProxy::StreamStatsProvider* stats_provider) + : config_(config), + lock_(CriticalSectionWrapper::CreateCriticalSection()), + stats_provider_(stats_provider) {} + +SendStatisticsProxy::~SendStatisticsProxy() {} + +void SendStatisticsProxy::OutgoingRate(const int video_channel, + const unsigned int framerate, + const unsigned int bitrate) { + CriticalSectionScoped cs(lock_.get()); + stats_.encode_frame_rate = framerate; +} + +void SendStatisticsProxy::CapturedFrameRate(const int capture_id, + const unsigned char frame_rate) { + CriticalSectionScoped cs(lock_.get()); + stats_.input_frame_rate = frame_rate; +} + +VideoSendStream::Stats SendStatisticsProxy::GetStats() const { + VideoSendStream::Stats stats = stats_; + CriticalSectionScoped cs(lock_.get()); + stats_provider_->GetSendSideDelay(&stats); + stats.c_name = stats_provider_->GetCName(); + return stats; +} + +StreamStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) { + std::map::iterator it = stats_.substreams.find(ssrc); + if (it != stats_.substreams.end()) + return &it->second; + + if (std::find(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc) == + config_.rtp.ssrcs.end()) + return NULL; + + return &stats_.substreams[ssrc]; // Insert new entry and return ptr. +} + +void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics, + uint32_t ssrc) { + CriticalSectionScoped cs(lock_.get()); + StreamStats* stats = GetStatsEntry(ssrc); + if (stats == NULL) + return; + + stats->rtcp_stats = statistics; +} + +void SendStatisticsProxy::DataCountersUpdated( + const StreamDataCounters& counters, + uint32_t ssrc) { + CriticalSectionScoped cs(lock_.get()); + StreamStats* stats = GetStatsEntry(ssrc); + if (stats == NULL) + return; + + stats->rtp_stats = counters; +} + +void SendStatisticsProxy::Notify(const BitrateStatistics& bitrate, + uint32_t ssrc) { + CriticalSectionScoped cs(lock_.get()); + StreamStats* stats = GetStatsEntry(ssrc); + if (stats == NULL) + return; + + stats->bitrate_bps = bitrate.bitrate_bps; +} + +void SendStatisticsProxy::FrameCountUpdated(FrameType frame_type, + uint32_t frame_count, + const unsigned int ssrc) { + CriticalSectionScoped cs(lock_.get()); + StreamStats* stats = GetStatsEntry(ssrc); + if (stats == NULL) + return; + + switch (frame_type) { + case kVideoFrameDelta: + stats->delta_frames = frame_count; + break; + case kVideoFrameKey: + stats->key_frames = frame_count; + break; + case kFrameEmpty: + case kAudioFrameSpeech: + case kAudioFrameCN: + break; + } +} + +} // namespace webrtc diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h new file mode 100644 index 0000000000..4f2fafbe8b --- /dev/null +++ b/webrtc/video/send_statistics_proxy.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VIDEO_SEND_STATISTICS_PROXY_H_ +#define WEBRTC_VIDEO_SEND_STATISTICS_PROXY_H_ + +#include + +#include "webrtc/common_types.h" +#include "webrtc/video_engine/include/vie_codec.h" +#include "webrtc/video_engine/include/vie_capture.h" +#include "webrtc/video_send_stream.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +class CriticalSectionWrapper; + +class SendStatisticsProxy : public RtcpStatisticsCallback, + public StreamDataCountersCallback, + public BitrateStatisticsObserver, + public FrameCountObserver, + public ViEEncoderObserver, + public ViECaptureObserver { + public: + class StreamStatsProvider { + public: + StreamStatsProvider() {} + virtual ~StreamStatsProvider() {} + + virtual bool GetSendSideDelay(VideoSendStream::Stats* stats) = 0; + virtual std::string GetCName() = 0; + }; + + SendStatisticsProxy(const VideoSendStream::Config& config, + StreamStatsProvider* stats_provider); + virtual ~SendStatisticsProxy(); + + VideoSendStream::Stats GetStats() const; + + protected: + // From RtcpStatisticsCallback. + virtual void StatisticsUpdated(const RtcpStatistics& statistics, + uint32_t ssrc) OVERRIDE; + // From StreamDataCountersCallback. + virtual void DataCountersUpdated(const StreamDataCounters& counters, + uint32_t ssrc) OVERRIDE; + + // From BitrateStatisticsObserver. + virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) OVERRIDE; + + // From FrameCountObserver. + virtual void FrameCountUpdated(FrameType frame_type, + uint32_t frame_count, + const unsigned int ssrc) OVERRIDE; + + // From ViEEncoderObserver. + virtual void OutgoingRate(const int video_channel, + const unsigned int framerate, + const unsigned int bitrate) OVERRIDE; + + virtual void SuspendChange(int video_channel, bool is_suspended) OVERRIDE {} + + // From ViECaptureObserver. + virtual void BrightnessAlarm(const int capture_id, + const Brightness brightness) OVERRIDE {} + + virtual void CapturedFrameRate(const int capture_id, + const unsigned char frame_rate) OVERRIDE; + + virtual void NoPictureAlarm(const int capture_id, + const CaptureAlarm alarm) OVERRIDE {} + + private: + StreamStats* GetStatsEntry(uint32_t ssrc); + + const VideoSendStream::Config config_; + scoped_ptr lock_; + VideoSendStream::Stats stats_; + StreamStatsProvider* stats_provider_; +}; + +} // namespace webrtc +#endif // WEBRTC_VIDEO_SEND_STATISTICS_PROXY_H_ diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc new file mode 100644 index 0000000000..6e921928c5 --- /dev/null +++ b/webrtc/video/send_statistics_proxy_unittest.cc @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// This file includes unit tests for SendStatisticsProxy. +#include "webrtc/video/send_statistics_proxy.h" + +#include +#include +#include + +#include "testing/gtest/include/gtest/gtest.h" + +namespace webrtc { + +class SendStatisticsProxyTest + : public ::testing::Test, + protected SendStatisticsProxy::StreamStatsProvider { + public: + SendStatisticsProxyTest() : avg_delay_ms_(0), max_delay_ms_(0) {} + virtual ~SendStatisticsProxyTest() {} + + protected: + virtual void SetUp() { + statistics_proxy_.reset( + new SendStatisticsProxy(GetTestConfig(), this)); + config_ = GetTestConfig(); + expected_ = VideoSendStream::Stats(); + } + + VideoSendStream::Config GetTestConfig() { + VideoSendStream::Config config; + config.rtp.ssrcs.push_back(17); + config.rtp.ssrcs.push_back(42); + return config; + } + + virtual bool GetSendSideDelay(VideoSendStream::Stats* stats) OVERRIDE { + stats->avg_delay_ms = avg_delay_ms_; + stats->max_delay_ms = max_delay_ms_; + return true; + } + + virtual std::string GetCName() { return cname_; } + + scoped_ptr statistics_proxy_; + VideoSendStream::Config config_; + int avg_delay_ms_; + int max_delay_ms_; + std::string cname_; + VideoSendStream::Stats expected_; + typedef std::map::const_iterator StreamIterator; +}; + +TEST_F(SendStatisticsProxyTest, RtcpStatistics) { + RtcpStatisticsCallback* callback = statistics_proxy_.get(); + for (std::vector::const_iterator it = config_.rtp.ssrcs.begin(); + it != config_.rtp.ssrcs.end(); + ++it) { + const uint32_t ssrc = *it; + StreamStats& ssrc_stats = expected_.substreams[ssrc]; + + // Add statistics with some arbitrary, but unique, numbers. + uint32_t offset = ssrc * sizeof(RtcpStatistics); + ssrc_stats.rtcp_stats.cumulative_lost = offset; + ssrc_stats.rtcp_stats.extended_max_sequence_number = offset + 1; + ssrc_stats.rtcp_stats.fraction_lost = offset + 2; + ssrc_stats.rtcp_stats.jitter = offset + 3; + callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc); + } + + VideoSendStream::Stats stats = statistics_proxy_->GetStats(); + EXPECT_EQ(expected_, stats); +} + +TEST_F(SendStatisticsProxyTest, FrameRates) { + const int capture_fps = 31; + const int encode_fps = 29; + + ViECaptureObserver* capture_observer = statistics_proxy_.get(); + capture_observer->CapturedFrameRate(0, capture_fps); + ViEEncoderObserver* encoder_observer = statistics_proxy_.get(); + encoder_observer->OutgoingRate(0, encode_fps, 0); + + VideoSendStream::Stats stats = statistics_proxy_->GetStats(); + EXPECT_EQ(capture_fps, stats.input_frame_rate); + EXPECT_EQ(encode_fps, stats.encode_frame_rate); +} + +TEST_F(SendStatisticsProxyTest, FrameCounts) { + FrameCountObserver* observer = statistics_proxy_.get(); + for (std::vector::const_iterator it = config_.rtp.ssrcs.begin(); + it != config_.rtp.ssrcs.end(); + ++it) { + const uint32_t ssrc = *it; + // Add statistics with some arbitrary, but unique, numbers. + StreamStats& stats = expected_.substreams[ssrc]; + uint32_t offset = ssrc * sizeof(StreamStats); + stats.key_frames = offset; + stats.delta_frames = offset + 1; + observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc); + observer->FrameCountUpdated(kVideoFrameDelta, stats.delta_frames, ssrc); + } + + VideoSendStream::Stats stats = statistics_proxy_->GetStats(); + EXPECT_EQ(expected_, stats); +} + +TEST_F(SendStatisticsProxyTest, DataCounters) { + StreamDataCountersCallback* callback = statistics_proxy_.get(); + for (std::vector::const_iterator it = config_.rtp.ssrcs.begin(); + it != config_.rtp.ssrcs.end(); + ++it) { + const uint32_t ssrc = *it; + StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats; + // Add statistics with some arbitrary, but unique, numbers. + uint32_t offset = ssrc * sizeof(StreamDataCounters); + counters.bytes = offset; + counters.header_bytes = offset + 1; + counters.fec_packets = offset + 2; + counters.padding_bytes = offset + 3; + counters.retransmitted_packets = offset + 4; + counters.packets = offset + 5; + callback->DataCountersUpdated(counters, ssrc); + } + + VideoSendStream::Stats stats = statistics_proxy_->GetStats(); + EXPECT_EQ(expected_, stats); +} + +TEST_F(SendStatisticsProxyTest, Bitrate) { + BitrateStatisticsObserver* observer = statistics_proxy_.get(); + for (std::vector::const_iterator it = config_.rtp.ssrcs.begin(); + it != config_.rtp.ssrcs.end(); + ++it) { + const uint32_t ssrc = *it; + BitrateStatistics bitrate; + bitrate.bitrate_bps = ssrc; + observer->Notify(bitrate, ssrc); + expected_.substreams[ssrc].bitrate_bps = ssrc; + } + + VideoSendStream::Stats stats = statistics_proxy_->GetStats(); + EXPECT_EQ(expected_, stats); +} + +TEST_F(SendStatisticsProxyTest, StreamStats) { + avg_delay_ms_ = 1; + max_delay_ms_ = 2; + cname_ = "qwertyuiop"; + + VideoSendStream::Stats stats = statistics_proxy_->GetStats(); + + EXPECT_EQ(avg_delay_ms_, stats.avg_delay_ms); + EXPECT_EQ(max_delay_ms_, stats.max_delay_ms); + EXPECT_EQ(cname_, stats.c_name); +} + +TEST_F(SendStatisticsProxyTest, NoSubstreams) { + uint32_t exluded_ssrc = + *std::max_element(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end()) + 1; + // From RtcpStatisticsCallback. + RtcpStatistics rtcp_stats; + RtcpStatisticsCallback* rtcp_callback = statistics_proxy_.get(); + rtcp_callback->StatisticsUpdated(rtcp_stats, exluded_ssrc); + + // From StreamDataCountersCallback. + StreamDataCounters rtp_stats; + StreamDataCountersCallback* rtp_callback = statistics_proxy_.get(); + rtp_callback->DataCountersUpdated(rtp_stats, exluded_ssrc); + + // From BitrateStatisticsObserver. + BitrateStatistics bitrate; + BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get(); + bitrate_observer->Notify(bitrate, exluded_ssrc); + + // From FrameCountObserver. + FrameCountObserver* fps_observer = statistics_proxy_.get(); + fps_observer->FrameCountUpdated(kVideoFrameKey, 1, exluded_ssrc); + + VideoSendStream::Stats stats = statistics_proxy_->GetStats(); + EXPECT_TRUE(stats.substreams.empty()); +} + +} // namespace webrtc diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index e18b346233..0ab70391fa 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -186,9 +186,32 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport, if (config.suspend_below_min_bitrate) { codec_->SuspendBelowMinBitrate(channel_); } + + stats_proxy_.reset( + new SendStatisticsProxy(config, this)); + + rtp_rtcp_->RegisterSendChannelRtcpStatisticsCallback(channel_, + stats_proxy_.get()); + rtp_rtcp_->RegisterSendChannelRtpStatisticsCallback(channel_, + stats_proxy_.get()); + rtp_rtcp_->RegisterSendBitrateObserver(channel_, stats_proxy_.get()); + rtp_rtcp_->RegisterSendFrameCountObserver(channel_, stats_proxy_.get()); + + codec_->RegisterEncoderObserver(channel_, *stats_proxy_); + capture_->RegisterObserver(capture_id_, *stats_proxy_); } VideoSendStream::~VideoSendStream() { + capture_->DeregisterObserver(capture_id_); + codec_->DeregisterEncoderObserver(channel_); + + rtp_rtcp_->DeregisterSendFrameCountObserver(channel_, stats_proxy_.get()); + rtp_rtcp_->DeregisterSendBitrateObserver(channel_, stats_proxy_.get()); + rtp_rtcp_->DeregisterSendChannelRtpStatisticsCallback(channel_, + stats_proxy_.get()); + rtp_rtcp_->DeregisterSendChannelRtcpStatisticsCallback(channel_, + stats_proxy_.get()); + image_process_->DeRegisterPreEncodeCallback(channel_); network_->DeregisterSendTransport(channel_); @@ -293,5 +316,21 @@ bool VideoSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { return network_->ReceivedRTCPPacket( channel_, packet, static_cast(length)) == 0; } + +VideoSendStream::Stats VideoSendStream::GetStats() const { + return stats_proxy_->GetStats(); +} + +bool VideoSendStream::GetSendSideDelay(VideoSendStream::Stats* stats) { + return codec_->GetSendSideDelay( + channel_, &stats->avg_delay_ms, &stats->max_delay_ms); +} + +std::string VideoSendStream::GetCName() { + char rtcp_cname[ViERTP_RTCP::KMaxRTCPCNameLength]; + rtp_rtcp_->GetRTCPCName(channel_, rtcp_cname); + return rtcp_cname; +} + } // namespace internal } // namespace webrtc diff --git a/webrtc/video/video_send_stream.h b/webrtc/video/video_send_stream.h index 7433e8a3b9..05c481f3f7 100644 --- a/webrtc/video/video_send_stream.h +++ b/webrtc/video/video_send_stream.h @@ -11,10 +11,9 @@ #ifndef WEBRTC_VIDEO_VIDEO_SEND_STREAM_H_ #define WEBRTC_VIDEO_VIDEO_SEND_STREAM_H_ -#include - #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" #include "webrtc/video/encoded_frame_callback_adapter.h" +#include "webrtc/video/send_statistics_proxy.h" #include "webrtc/video/transport_adapter.h" #include "webrtc/video_receive_stream.h" #include "webrtc/video_send_stream.h" @@ -37,7 +36,8 @@ namespace internal { class ResolutionAdaptor; class VideoSendStream : public webrtc::VideoSendStream, - public VideoSendStreamInput { + public VideoSendStreamInput, + public SendStatisticsProxy::StreamStatsProvider { public: VideoSendStream(newapi::Transport* transport, bool overuse_detection, @@ -47,12 +47,6 @@ class VideoSendStream : public webrtc::VideoSendStream, virtual ~VideoSendStream(); - virtual void PutFrame(const I420VideoFrame& frame) OVERRIDE; - - virtual void SwapFrame(I420VideoFrame* frame) OVERRIDE; - - virtual VideoSendStreamInput* Input() OVERRIDE; - virtual void StartSending() OVERRIDE; virtual void StopSending() OVERRIDE; @@ -60,9 +54,22 @@ class VideoSendStream : public webrtc::VideoSendStream, virtual bool SetCodec(const VideoCodec& codec) OVERRIDE; virtual VideoCodec GetCodec() OVERRIDE; - public: + virtual Stats GetStats() const OVERRIDE; + bool DeliverRtcp(const uint8_t* packet, size_t length); + // From VideoSendStreamInput. + virtual void PutFrame(const I420VideoFrame& frame) OVERRIDE; + virtual void SwapFrame(I420VideoFrame* frame) OVERRIDE; + + // From webrtc::VideoSendStream. + virtual VideoSendStreamInput* Input() OVERRIDE; + + protected: + // From SendStatisticsProxy::StreamStatsProvider. + virtual bool GetSendSideDelay(VideoSendStream::Stats* stats) OVERRIDE; + virtual std::string GetCName() OVERRIDE; + private: I420VideoFrame input_frame_; TransportAdapter transport_adapter_; @@ -82,6 +89,8 @@ class VideoSendStream : public webrtc::VideoSendStream, int channel_; int capture_id_; scoped_ptr overuse_observer_; + + scoped_ptr stats_proxy_; }; } // namespace internal } // namespace webrtc diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc index 42259e38a1..908632bba2 100644 --- a/webrtc/video/video_send_stream_tests.cc +++ b/webrtc/video/video_send_stream_tests.cc @@ -35,7 +35,8 @@ namespace webrtc { class VideoSendStreamTest : public ::testing::Test { public: - VideoSendStreamTest() : fake_encoder_(Clock::GetRealTimeClock()) {} + VideoSendStreamTest() + : send_stream_(NULL), fake_encoder_(Clock::GetRealTimeClock()) {} protected: void RunSendTest(Call* call, @@ -190,7 +191,7 @@ void VideoSendStreamTest::SendsSetSsrcs(size_t num_ssrcs, frame_generator_capturer->Stop(); send_stream_->StopSending(); call->DestroyVideoSendStream(send_stream_); -}; +} TEST_F(VideoSendStreamTest, SendsSetSsrc) { SendsSetSsrcs(1, false); } @@ -936,4 +937,64 @@ TEST_F(VideoSendStreamTest, NoPaddingWhenVideoIsMuted) { call->DestroyVideoSendStream(send_stream_); } +TEST_F(VideoSendStreamTest, ProducesStats) { + static std::string kCName = "PjQatC14dGfbVwGPUOA9IH7RlsFDbWl4AhXEiDsBizo="; + class StatsObserver : public test::RtpRtcpObserver { + public: + StatsObserver() : RtpRtcpObserver(30 * 1000), stream_(NULL) {} + + virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE { + VideoSendStream::Stats stats = stream_->GetStats(); + // Check that all applicable data sources have been used. + if (stats.input_frame_rate > 0 && stats.encode_frame_rate > 0 && + stats.avg_delay_ms > 0 && stats.c_name == kCName && + !stats.substreams.empty()) { + uint32_t ssrc = stats.substreams.begin()->first; + EXPECT_NE( + config_.rtp.ssrcs.end(), + std::find( + config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc)); + // Check for data populated by various sources. RTCP excluded as this + // data is received from remote side. Tested in call tests instead. + StreamStats& entry = stats.substreams[ssrc]; + if (entry.key_frames > 0u && entry.bitrate_bps > 0 && + entry.rtp_stats.packets > 0u) { + observation_complete_->Set(); + } + } + + return SEND_PACKET; + } + + void SetConfig(const VideoSendStream::Config& config) { config_ = config; } + + void SetSendStream(VideoSendStream* stream) { stream_ = stream; } + + VideoSendStream* stream_; + VideoSendStream::Config config_; + } observer; + + Call::Config call_config(observer.SendTransport()); + scoped_ptr call(Call::Create(call_config)); + + VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1); + send_config.rtp.c_name = kCName; + observer.SetConfig(send_config); + + send_stream_ = call->CreateVideoSendStream(send_config); + observer.SetSendStream(send_stream_); + scoped_ptr frame_generator_capturer( + test::FrameGeneratorCapturer::Create( + send_stream_->Input(), 320, 240, 30, Clock::GetRealTimeClock())); + send_stream_->StartSending(); + frame_generator_capturer->Start(); + + EXPECT_EQ(kEventSignaled, observer.Wait()); + + observer.StopSending(); + frame_generator_capturer->Stop(); + send_stream_->StopSending(); + call->DestroyVideoSendStream(send_stream_); +} + } // namespace webrtc diff --git a/webrtc/video/webrtc_video.gypi b/webrtc/video/webrtc_video.gypi index 5f7784d313..0d83a51414 100644 --- a/webrtc/video/webrtc_video.gypi +++ b/webrtc/video/webrtc_video.gypi @@ -14,6 +14,8 @@ 'video/call.cc', 'video/encoded_frame_callback_adapter.cc', 'video/encoded_frame_callback_adapter.h', + 'video/send_statistics_proxy.cc', + 'video/send_statistics_proxy.h', 'video/transport_adapter.cc', 'video/transport_adapter.h', 'video/video_receive_stream.cc', diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index 5473177513..6e58313b3a 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -345,8 +345,6 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, } rtp_rtcp->SetSendingStatus(rtp_rtcp_->Sending()); rtp_rtcp->SetSendingMediaStatus(rtp_rtcp_->SendingMedia()); - rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback( - rtp_rtcp_->GetSendChannelRtcpStatisticsCallback()); simulcast_rtp_rtcp_.push_back(rtp_rtcp); } // Remove last in list if we have too many. diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h index dd602eed40..9313fdc5a9 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -400,7 +400,6 @@ class ViEChannel scoped_ptr bandwidth_observer_; int send_timestamp_extension_id_; int absolute_send_time_extension_id_; - bool using_packet_spread_; Transport* external_transport_; diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h index 7c1a6fd029..e59ef60dee 100644 --- a/webrtc/video_send_stream.h +++ b/webrtc/video_send_stream.h @@ -11,8 +11,8 @@ #ifndef WEBRTC_VIDEO_SEND_STREAM_H_ #define WEBRTC_VIDEO_SEND_STREAM_H_ +#include #include -#include #include "webrtc/common_types.h" #include "webrtc/config.h" @@ -41,32 +41,28 @@ class VideoSendStream { struct Stats { Stats() : input_frame_rate(0), - encode_frame(0), - key_frames(0), - delta_frames(0), - video_packets(0), - retransmitted_packets(0), - fec_packets(0), - padding_packets(0), - send_bitrate_bps(0), - delay_ms(0) {} - RtpStatistics rtp; - int input_frame_rate; - int encode_frame; - uint32_t key_frames; - uint32_t delta_frames; - uint32_t video_packets; - uint32_t retransmitted_packets; - uint32_t fec_packets; - uint32_t padding_packets; - int32_t send_bitrate_bps; - int delay_ms; - }; + encode_frame_rate(0), + avg_delay_ms(0), + max_delay_ms(0) {} - class StatsCallback { - public: - virtual ~StatsCallback() {} - virtual void ReceiveStats(const std::vector& stats) = 0; + int input_frame_rate; + int encode_frame_rate; + int avg_delay_ms; + int max_delay_ms; + std::string c_name; + std::map substreams; + + bool operator==(const Stats& other) const { + if (input_frame_rate != other.input_frame_rate || + encode_frame_rate != other.encode_frame_rate || + avg_delay_ms != other.avg_delay_ms || + max_delay_ms != other.max_delay_ms || c_name != other.c_name || + substreams.size() != other.substreams.size()) { + return false; + } + return std::equal( + substreams.begin(), substreams.end(), other.substreams.begin()); + } }; struct Config { @@ -79,7 +75,6 @@ class VideoSendStream { internal_source(false), target_delay_ms(0), pacing(false), - stats_callback(NULL), suspend_below_min_bitrate(false) {} VideoCodec codec; @@ -140,9 +135,6 @@ class VideoSendStream { // packets onto the network. bool pacing; - // Callback for periodically receiving send stats. - StatsCallback* stats_callback; - // True if the stream should be suspended when the available bitrate fall // below the minimum configured bitrate. If this variable is false, the // stream may send at a rate higher than the estimated available bitrate. @@ -161,6 +153,8 @@ class VideoSendStream { virtual bool SetCodec(const VideoCodec& codec) = 0; virtual VideoCodec GetCodec() = 0; + virtual Stats GetStats() const = 0; + protected: virtual ~VideoSendStream() {} }; diff --git a/webrtc/webrtc_tests.gypi b/webrtc/webrtc_tests.gypi index 0d2b30ee18..b60660ac39 100644 --- a/webrtc/webrtc_tests.gypi +++ b/webrtc/webrtc_tests.gypi @@ -35,6 +35,7 @@ 'sources': [ 'video/bitrate_estimator_tests.cc', 'video/call_tests.cc', + 'video/send_statistics_proxy_unittest.cc', 'video/video_send_stream_tests.cc', 'test/common_unittest.cc', 'test/testsupport/metrics/video_metrics_unittest.cc',