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:
parent
07fcc4f2fa
commit
0a3c1471b8
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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()");
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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_;
|
||||
|
@ -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() {}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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],
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user