Add APIs to enable padding with redundant payloads.

Also makes a small change to the tests to remove flakiness. We can't do
BWE only based on rtp timestamps if we preemptively resend packets instead
of sending padding packets.

BUG=1812,2992
R=mflodman@webrtc.org, pbos@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6400 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2014-06-11 13:41:36 +00:00
parent 5d223a7d2d
commit fbb567dacd
8 changed files with 86 additions and 22 deletions

View File

@ -38,7 +38,7 @@
namespace webrtc { namespace webrtc {
namespace { namespace {
static const int kAbsoluteSendTimeExtensionId = 7; static const int kTransmissionTimeOffsetExtensionId = 6;
static const int kMaxPacketSize = 1500; static const int kMaxPacketSize = 1500;
class StreamObserver : public newapi::Transport, public RemoteBitrateObserver { class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
@ -75,8 +75,8 @@ class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config)); rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
rtp_rtcp_->SetREMBStatus(true); rtp_rtcp_->SetREMBStatus(true);
rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound); rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
kAbsoluteSendTimeExtensionId); kTransmissionTimeOffsetExtensionId);
AbsoluteSendTimeRemoteBitrateEstimatorFactory rbe_factory; AbsoluteSendTimeRemoteBitrateEstimatorFactory rbe_factory;
const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000; const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
remote_bitrate_estimator_.reset( remote_bitrate_estimator_.reset(
@ -218,8 +218,8 @@ class LowRateStreamObserver : public test::DirectTransport,
rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config)); rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
rtp_rtcp_->SetREMBStatus(true); rtp_rtcp_->SetREMBStatus(true);
rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound); rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime, rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
kAbsoluteSendTimeExtensionId); kTransmissionTimeOffsetExtensionId);
AbsoluteSendTimeRemoteBitrateEstimatorFactory rbe_factory; AbsoluteSendTimeRemoteBitrateEstimatorFactory rbe_factory;
const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 10000; const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 10000;
remote_bitrate_estimator_.reset( remote_bitrate_estimator_.reset(
@ -421,9 +421,6 @@ class RampUpTest : public ::testing::Test {
Clock::GetRealTimeClock()); Clock::GetRealTimeClock());
Call::Config call_config(&stream_observer); Call::Config call_config(&stream_observer);
webrtc::Config webrtc_config;
call_config.webrtc_config = &webrtc_config;
webrtc_config.Set<PaddingStrategy>(new PaddingStrategy(rtx));
scoped_ptr<Call> call(Call::Create(call_config)); scoped_ptr<Call> call(Call::Create(call_config));
VideoSendStream::Config send_config = call->GetDefaultSendConfig(); VideoSendStream::Config send_config = call->GetDefaultSendConfig();
@ -447,9 +444,11 @@ class RampUpTest : public ::testing::Test {
if (rtx) { if (rtx) {
send_config.rtp.rtx.payload_type = 96; send_config.rtp.rtx.payload_type = 96;
send_config.rtp.rtx.ssrcs = rtx_ssrcs; send_config.rtp.rtx.ssrcs = rtx_ssrcs;
send_config.rtp.rtx.pad_with_redundant_payloads = true;
} }
send_config.rtp.extensions.push_back( send_config.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsoluteSendTimeExtensionId)); RtpExtension(RtpExtension::kTOffset,
kTransmissionTimeOffsetExtensionId));
if (num_streams == 1) { if (num_streams == 1) {
// For single stream rampup until 1mbps // For single stream rampup until 1mbps
@ -514,7 +513,8 @@ class RampUpTest : public ::testing::Test {
send_config.rtp.ssrcs.insert( send_config.rtp.ssrcs.insert(
send_config.rtp.ssrcs.begin(), ssrcs.begin(), ssrcs.end()); send_config.rtp.ssrcs.begin(), ssrcs.begin(), ssrcs.end());
send_config.rtp.extensions.push_back( send_config.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsoluteSendTimeExtensionId)); RtpExtension(RtpExtension::kTOffset,
kTransmissionTimeOffsetExtensionId));
send_config.suspend_below_min_bitrate = true; send_config.suspend_below_min_bitrate = true;
send_config.pacing = true; send_config.pacing = true;
@ -581,8 +581,7 @@ TEST_F(RampUpTest, SimulcastWithPacing) {
RunRampUpTest(true, false, 3); RunRampUpTest(true, false, 3);
} }
// TODO(pbos): Re-enable, webrtc:2992. TEST_F(RampUpTest, SimulcastWithPacingAndRtx) {
TEST_F(RampUpTest, DISABLED_SimulcastWithPacingAndRtx) {
RunRampUpTest(true, true, 3); RunRampUpTest(true, true, 3);
} }

View File

@ -381,8 +381,10 @@ bool VideoSendStream::ReconfigureVideoEncoder(
static_cast<unsigned char>(i)); static_cast<unsigned char>(i));
} }
if (config_.rtp.rtx.ssrcs.empty()) if (config_.rtp.rtx.ssrcs.empty()) {
assert(!config_.rtp.rtx.pad_with_redundant_payloads);
return true; return true;
}
// Set up RTX. // Set up RTX.
assert(config_.rtp.rtx.ssrcs.size() == config_.rtp.ssrcs.size()); assert(config_.rtp.rtx.ssrcs.size() == config_.rtp.ssrcs.size());
@ -393,6 +395,10 @@ bool VideoSendStream::ReconfigureVideoEncoder(
static_cast<unsigned char>(i)); static_cast<unsigned char>(i));
} }
if (config_.rtp.rtx.pad_with_redundant_payloads) {
rtp_rtcp_->SetPadWithRedundantPayloads(channel_, true);
}
assert(config_.rtp.rtx.payload_type >= 0); assert(config_.rtp.rtx.payload_type >= 0);
rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type); rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type);

View File

@ -134,6 +134,15 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP {
virtual int SetRtxSendPayloadType(const int video_channel, virtual int SetRtxSendPayloadType(const int video_channel,
const uint8_t payload_type) = 0; const uint8_t payload_type) = 0;
// This enables sending redundant payloads when padding up the bitrate instead
// of sending dummy padding packets. This feature is off by default and will
// only have an effect if RTX is also enabled.
// TODO(holmer): Remove default implementation once this has been implemented
// in libjingle.
virtual int SetPadWithRedundantPayloads(int video_channel, bool enable) {
return 0;
}
virtual int SetRtxReceivePayloadType(const int video_channel, virtual int SetRtxReceivePayloadType(const int video_channel,
const uint8_t payload_type) = 0; const uint8_t payload_type) = 0;

View File

@ -89,6 +89,7 @@ ViEChannel::ViEChannel(int32_t channel_id,
intra_frame_observer_(intra_frame_observer), intra_frame_observer_(intra_frame_observer),
rtt_stats_(rtt_stats), rtt_stats_(rtt_stats),
paced_sender_(paced_sender), paced_sender_(paced_sender),
pad_with_redundant_payloads_(false),
bandwidth_observer_(bandwidth_observer), bandwidth_observer_(bandwidth_observer),
send_timestamp_extension_id_(kInvalidRtpExtensionId), send_timestamp_extension_id_(kInvalidRtpExtensionId),
absolute_send_time_extension_id_(kInvalidRtpExtensionId), absolute_send_time_extension_id_(kInvalidRtpExtensionId),
@ -102,8 +103,7 @@ ViEChannel::ViEChannel(int32_t channel_id,
sender_(sender), sender_(sender),
nack_history_size_sender_(kSendSidePacketHistorySize), nack_history_size_sender_(kSendSidePacketHistorySize),
max_nack_reordering_threshold_(kMaxPacketAgeToNack), max_nack_reordering_threshold_(kMaxPacketAgeToNack),
pre_render_callback_(NULL), pre_render_callback_(NULL) {
config_(config) {
RtpRtcp::Configuration configuration; RtpRtcp::Configuration configuration;
configuration.id = ViEModuleId(engine_id, channel_id); configuration.id = ViEModuleId(engine_id, channel_id);
configuration.audio = false; configuration.audio = false;
@ -860,19 +860,46 @@ int32_t ViEChannel::GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]) {
return 0; return 0;
} }
void ViEChannel::SetPadWithRedundantPayloads(bool enable) {
{
CriticalSectionScoped cs(callback_cs_.get());
pad_with_redundant_payloads_ = enable;
}
int mode;
uint32_t ssrc;
int payload_type;
rtp_rtcp_->RTXSendStatus(&mode, &ssrc, &payload_type);
if (mode != kRtxOff) {
// Since RTX was already enabled we have to reset it with payload-based
// padding on.
SetRtxSendStatus(true);
}
}
int ViEChannel::SetRtxSendPayloadType(int payload_type) { int ViEChannel::SetRtxSendPayloadType(int payload_type) {
int rtx_settings = kRtxRetransmitted;
if (config_.Get<PaddingStrategy>().redundant_payloads)
rtx_settings |= kRtxRedundantPayloads;
rtp_rtcp_->SetRtxSendPayloadType(payload_type); rtp_rtcp_->SetRtxSendPayloadType(payload_type);
for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
it != simulcast_rtp_rtcp_.end(); it++) {
(*it)->SetRtxSendPayloadType(payload_type);
}
SetRtxSendStatus(true);
return 0;
}
void ViEChannel::SetRtxSendStatus(bool enable) {
int rtx_settings = kRtxOff;
if (enable) {
CriticalSectionScoped cs(callback_cs_.get());
rtx_settings = kRtxRetransmitted;
if (pad_with_redundant_payloads_)
rtx_settings |= kRtxRedundantPayloads;
}
rtp_rtcp_->SetRTXSendStatus(rtx_settings); rtp_rtcp_->SetRTXSendStatus(rtx_settings);
CriticalSectionScoped cs(rtp_rtcp_cs_.get()); CriticalSectionScoped cs(rtp_rtcp_cs_.get());
for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin(); for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
it != simulcast_rtp_rtcp_.end(); it++) { it != simulcast_rtp_rtcp_.end(); it++) {
(*it)->SetRtxSendPayloadType(payload_type);
(*it)->SetRTXSendStatus(rtx_settings); (*it)->SetRTXSendStatus(rtx_settings);
} }
return 0;
} }
void ViEChannel::SetRtxReceivePayloadType(int payload_type) { void ViEChannel::SetRtxReceivePayloadType(int payload_type) {

View File

@ -145,6 +145,8 @@ class ViEChannel
int32_t GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]); int32_t GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]);
int SetRtxSendPayloadType(int payload_type); int SetRtxSendPayloadType(int payload_type);
// Only has an effect once RTX is enabled.
void SetPadWithRedundantPayloads(bool enable);
void SetRtxReceivePayloadType(int payload_type); void SetRtxReceivePayloadType(int payload_type);
// Sets the starting sequence number, must be called before StartSend. // Sets the starting sequence number, must be called before StartSend.
@ -370,6 +372,7 @@ class ViEChannel
const unsigned char payload_typeFEC); const unsigned char payload_typeFEC);
// Compute NACK list parameters for the buffering mode. // Compute NACK list parameters for the buffering mode.
int GetRequiredNackListSize(int target_delay_ms); int GetRequiredNackListSize(int target_delay_ms);
void SetRtxSendStatus(bool enable);
int32_t channel_id_; int32_t channel_id_;
int32_t engine_id_; int32_t engine_id_;
@ -403,6 +406,7 @@ class ViEChannel
RtcpIntraFrameObserver* intra_frame_observer_; RtcpIntraFrameObserver* intra_frame_observer_;
RtcpRttStats* rtt_stats_; RtcpRttStats* rtt_stats_;
PacedSender* paced_sender_; PacedSender* paced_sender_;
bool pad_with_redundant_payloads_;
scoped_ptr<RtcpBandwidthObserver> bandwidth_observer_; scoped_ptr<RtcpBandwidthObserver> bandwidth_observer_;
int send_timestamp_extension_id_; int send_timestamp_extension_id_;
@ -426,7 +430,6 @@ class ViEChannel
int nack_history_size_sender_; int nack_history_size_sender_;
int max_nack_reordering_threshold_; int max_nack_reordering_threshold_;
I420FrameCallback* pre_render_callback_; I420FrameCallback* pre_render_callback_;
const Config& config_;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -207,6 +207,21 @@ int ViERTP_RTCPImpl::SetRtxSendPayloadType(const int video_channel,
return 0; return 0;
} }
int ViERTP_RTCPImpl::SetPadWithRedundantPayloads(int video_channel,
bool enable) {
LOG_F(LS_INFO) << "channel: " << video_channel
<< " pad with redundant payloads: " << (enable ? "enable" :
"disable");
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
return -1;
}
vie_channel->SetPadWithRedundantPayloads(enable);
return 0;
}
int ViERTP_RTCPImpl::SetRtxReceivePayloadType(const int video_channel, int ViERTP_RTCPImpl::SetRtxReceivePayloadType(const int video_channel,
const uint8_t payload_type) { const uint8_t payload_type) {
LOG_F(LS_INFO) << "channel: " << video_channel LOG_F(LS_INFO) << "channel: " << video_channel

View File

@ -41,6 +41,7 @@ class ViERTP_RTCPImpl
unsigned int CSRCs[kRtpCsrcSize]) const; unsigned int CSRCs[kRtpCsrcSize]) const;
virtual int SetRtxSendPayloadType(const int video_channel, virtual int SetRtxSendPayloadType(const int video_channel,
const uint8_t payload_type); const uint8_t payload_type);
virtual int SetPadWithRedundantPayloads(int video_channel, bool enable);
virtual int SetRtxReceivePayloadType(const int video_channel, virtual int SetRtxReceivePayloadType(const int video_channel,
const uint8_t payload_type); const uint8_t payload_type);
virtual int SetStartSequenceNumber(const int video_channel, virtual int SetStartSequenceNumber(const int video_channel,

View File

@ -106,13 +106,17 @@ class VideoSendStream {
// Settings for RTP retransmission payload format, see RFC 4588 for // Settings for RTP retransmission payload format, see RFC 4588 for
// details. // details.
struct Rtx { struct Rtx {
Rtx() : payload_type(-1) {} Rtx() : payload_type(-1), pad_with_redundant_payloads(false) {}
std::string ToString() const; std::string ToString() const;
// SSRCs to use for the RTX streams. // SSRCs to use for the RTX streams.
std::vector<uint32_t> ssrcs; std::vector<uint32_t> ssrcs;
// Payload type to use for the RTX stream. // Payload type to use for the RTX stream.
int payload_type; int payload_type;
// Use redundant payloads to pad the bitrate. Instead of padding with
// randomized packets, we will preemptively retransmit media packets on
// the RTX stream.
bool pad_with_redundant_payloads;
} rtx; } rtx;
// RTCP CNAME, see RFC 3550. // RTCP CNAME, see RFC 3550.