Add API to query video engine for the send-side delay.

R=mflodman@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/4559005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5225 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2013-12-05 14:05:07 +00:00
parent 07fcc4f2fa
commit 0a3c1471b8
12 changed files with 129 additions and 4 deletions

View File

@ -335,6 +335,9 @@ class RtpRtcp : public Module {
FrameCountObserver* observer) = 0;
virtual FrameCountObserver* GetSendFrameCountObserver() const = 0;
virtual bool GetSendSideDelay(int* avg_send_delay_ms,
int* max_send_delay_ms) const = 0;
/**************************************************************************
*
* RTCP

View File

@ -116,6 +116,8 @@ class MockRtpRtcp : public RtpRtcp {
bool retransmission));
MOCK_METHOD1(TimeToSendPadding,
int(int bytes));
MOCK_CONST_METHOD2(GetSendSideDelay,
bool(int* avg_send_delay_ms, int* max_send_delay_ms));
MOCK_METHOD3(RegisterRtcpObservers,
void(RtcpIntraFrameObserver* intraFrameCallback,
RtcpBandwidthObserver* bandwidthCallback,

View File

@ -732,6 +732,18 @@ int ModuleRtpRtcpImpl::TimeToSendPadding(int bytes) {
return 0;
}
bool ModuleRtpRtcpImpl::GetSendSideDelay(int* avg_send_delay_ms,
int* max_send_delay_ms) const {
assert(avg_send_delay_ms);
assert(max_send_delay_ms);
if (!child_modules_.empty()) {
// This API is only supported for child modules.
return false;
}
return rtp_sender_.GetSendSideDelay(avg_send_delay_ms, max_send_delay_ms);
}
uint16_t ModuleRtpRtcpImpl::MaxPayloadLength() const {
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "MaxPayloadLength()");

View File

@ -134,6 +134,10 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
// Returns the number of padding bytes actually sent, which can be more or
// less than |bytes|.
virtual int TimeToSendPadding(int bytes) OVERRIDE;
virtual bool GetSendSideDelay(int* avg_send_delay_ms,
int* max_send_delay_ms) const OVERRIDE;
// RTCP part.
// Get RTCP status.

View File

@ -22,6 +22,7 @@ namespace webrtc {
// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
const int kMaxPaddingLength = 224;
const int kSendSideDelayWindowMs = 1000;
namespace {
@ -127,6 +128,23 @@ uint32_t RTPSender::NackOverheadRate() const {
return nack_bitrate_.BitrateLast();
}
bool RTPSender::GetSendSideDelay(int* avg_send_delay_ms,
int* max_send_delay_ms) const {
CriticalSectionScoped cs(statistics_crit_.get());
SendDelayMap::const_iterator it = send_delays_.upper_bound(
clock_->TimeInMilliseconds() - kSendSideDelayWindowMs);
if (!sending_media_ || it == send_delays_.end())
return false;
int num_delays = 0;
for (; it != send_delays_.end(); ++it) {
*max_send_delay_ms = std::max(*max_send_delay_ms, it->second);
*avg_send_delay_ms += it->second;
++num_delays;
}
*avg_send_delay_ms = (*avg_send_delay_ms + num_delays / 2) / num_delays;
return true;
}
int32_t RTPSender::SetTransmissionTimeOffset(
const int32_t transmission_time_offset) {
if (transmission_time_offset > (0x800000 - 1) ||
@ -756,6 +774,9 @@ bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
// Packet cannot be found. Allow sending to continue.
return true;
}
if (!retransmission && capture_time_ms > 0) {
UpdateDelayStatistics(capture_time_ms, clock_->TimeInMilliseconds());
}
return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
retransmission && (rtx_ & kRtxRetransmitted) > 0);
}
@ -871,12 +892,22 @@ int32_t RTPSender::SendToNetwork(
return 0;
}
}
if (capture_time_ms > 0) {
UpdateDelayStatistics(capture_time_ms, now_ms);
}
if (SendPacketToNetwork(buffer, payload_length + rtp_header_length)) {
return 0;
}
return -1;
}
void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
CriticalSectionScoped cs(statistics_crit_.get());
send_delays_[now_ms] = now_ms - capture_time_ms;
send_delays_.erase(send_delays_.begin(),
send_delays_.lower_bound(now_ms - kSendSideDelayWindowMs));
}
void RTPSender::ProcessBitrate() {
CriticalSectionScoped cs(send_critsect_);
Bitrate::Process();

View File

@ -78,6 +78,10 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
uint32_t FecOverheadRate() const;
uint32_t NackOverheadRate() const;
// Returns true if the statistics have been calculated, and false if no frame
// was sent within the statistics window.
bool GetSendSideDelay(int* avg_send_delay_ms, int* max_send_delay_ms) const;
void SetTargetSendBitrate(const uint32_t bits);
virtual uint16_t MaxDataPayloadLength() const
@ -272,6 +276,11 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
RtpVideoCodecTypes *video_type);
private:
// Maps capture time in milliseconds to send-side delay in milliseconds.
// Send-side delay is the difference between transmission time and capture
// time.
typedef std::map<int64_t, int> SendDelayMap;
int CreateRTPHeader(uint8_t* header, int8_t payload_type,
uint32_t ssrc, bool marker_bit,
uint32_t timestamp, uint16_t sequence_number,
@ -296,6 +305,8 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
bool SendPacketToNetwork(const uint8_t *packet, uint32_t size);
void UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms);
int32_t id_;
const bool audio_configured_;
RTPSenderAudio *audio_;
@ -329,6 +340,7 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
scoped_ptr<CriticalSectionWrapper> statistics_crit_;
uint32_t packets_sent_;
uint32_t payload_bytes_sent_;
SendDelayMap send_delays_;
// RTP variables
bool start_time_stamp_forced_;

View File

@ -198,6 +198,10 @@ class WEBRTC_DLLEXPORT ViECodec {
// This is under development; not tested.
virtual void SuspendBelowMinBitrate(int video_channel) = 0;
// TODO(holmer): Remove this default implementation when possible.
virtual bool GetSendSideDelay(int video_channel, int* avg_delay_ms,
int* max_delay_ms) const { return false; }
protected:
ViECodec() {}
virtual ~ViECodec() {}

View File

@ -258,10 +258,16 @@ void ViEAutoTest::ViECodecStandardTest() {
}
AutoTestSleep(kAutoTestSleepTimeMs);
// Verify the delay estimate is larger than 0.
int delay_ms = 0;
EXPECT_EQ(0, codec->GetReceiveSideDelay(video_channel, &delay_ms));
EXPECT_GT(delay_ms, 0);
// Verify the delay estimates are larger than 0.
int avg_send_delay = 0;
int max_send_delay = 0;
EXPECT_TRUE(codec->GetSendSideDelay(video_channel, &avg_send_delay,
&max_send_delay));
EXPECT_GT(avg_send_delay, 0);
EXPECT_GE(max_send_delay, avg_send_delay);
int receive_delay_ms = 0;
EXPECT_EQ(0, codec->GetReceiveSideDelay(video_channel, &receive_delay_ms));
EXPECT_GT(receive_delay_ms, 0);
EXPECT_EQ(0, base->StopSend(video_channel));
EXPECT_EQ(0, codec->DeregisterEncoderObserver(video_channel));

View File

@ -1374,6 +1374,40 @@ void ViEChannel::GetBandwidthUsage(uint32_t* total_bitrate_sent,
}
}
bool ViEChannel::GetSendSideDelay(int* avg_send_delay,
int* max_send_delay) const {
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
__FUNCTION__);
*avg_send_delay = 0;
*max_send_delay = 0;
bool valid_estimate = false;
int num_send_delays = 0;
if (rtp_rtcp_->GetSendSideDelay(avg_send_delay, max_send_delay)) {
++num_send_delays;
valid_estimate = true;
}
CriticalSectionScoped cs(rtp_rtcp_cs_.get());
for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
it != simulcast_rtp_rtcp_.end(); it++) {
RtpRtcp* rtp_rtcp = *it;
int sub_stream_avg_delay = 0;
int sub_stream_max_delay = 0;
if (rtp_rtcp->GetSendSideDelay(&sub_stream_avg_delay,
&sub_stream_max_delay)) {
*avg_send_delay += sub_stream_avg_delay;
*max_send_delay = std::max(*max_send_delay, sub_stream_max_delay);
++num_send_delays;
}
}
if (num_send_delays > 0) {
valid_estimate = true;
*avg_send_delay = *avg_send_delay / num_send_delays;
*avg_send_delay = (*avg_send_delay + num_send_delays / 2) / num_send_delays;
}
return valid_estimate;
}
void ViEChannel::GetEstimatedReceiveBandwidth(
uint32_t* estimated_bandwidth) const {
vie_receiver_.EstimatedReceiveBandwidth(estimated_bandwidth);

View File

@ -194,6 +194,7 @@ class ViEChannel
uint32_t* video_bitrate_sent,
uint32_t* fec_bitrate_sent,
uint32_t* nackBitrateSent) const;
bool GetSendSideDelay(int* avg_send_delay, int* max_send_delay) const;
void GetEstimatedReceiveBandwidth(uint32_t* estimated_bandwidth) const;
int32_t StartRTPDump(const char file_nameUTF8[1024],

View File

@ -738,6 +738,20 @@ void ViECodecImpl::SuspendBelowMinBitrate(int video_channel) {
vie_channel->SetTransmissionSmoothingStatus(true);
}
bool ViECodecImpl::GetSendSideDelay(int video_channel, int* avg_delay_ms,
int* max_delay_ms) const {
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: No channel %d", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViECodecInvalidChannelId);
return false;
}
return vie_channel->GetSendSideDelay(avg_delay_ms, max_delay_ms);
}
bool ViECodecImpl::CodecValid(const VideoCodec& video_codec) {
// Check pl_name matches codec_type.
if (video_codec.codecType == kVideoCodecRED) {

View File

@ -71,6 +71,8 @@ class ViECodecImpl
const char* file_name_utf8);
virtual int StopDebugRecording(int video_channel);
virtual void SuspendBelowMinBitrate(int video_channel);
virtual bool GetSendSideDelay(int video_channel, int* avg_delay_ms,
int* max_delay_ms) const;
protected:
explicit ViECodecImpl(ViESharedData* shared_data);