Wire up RTX in VideoReceiveStream.

Also adds a test to make sure that a retransmitted frame is actually
received and decoded on the remote side. The previous NACK test checked
retransmission, but not that the receiver actually takes care of the
retransmitted packet.

BUG=2399
R=mflodman@webrtc.org, stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5422 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org
2014-01-24 09:30:53 +00:00
parent 8d375c95b7
commit c279a5d72c
10 changed files with 253 additions and 124 deletions

View File

@ -71,16 +71,6 @@ struct FecConfig {
int red_payload_type;
};
// Settings for RTP retransmission payload format, see RFC 4588 for details.
struct RtxConfig {
RtxConfig() : rtx_payload_type(0) {}
// SSRCs to use for the RTX streams.
std::vector<uint32_t> ssrcs;
// Payload type to use for the RTX stream.
int rtx_payload_type;
};
// RTP header extension to use for the video stream, see RFC 5285.
struct RtpExtension {
static const char* kTOffset;

View File

@ -13,6 +13,8 @@
#include <map>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/typedefs.h"
#include "webrtc/video_send_stream.h"
@ -123,6 +125,7 @@ class RtpRtcpObserver {
private:
virtual bool SendRtp(const uint8_t* packet, size_t length) OVERRIDE {
EXPECT_FALSE(RtpHeaderParser::IsRtcp(packet, static_cast<int>(length)));
Action action;
{
CriticalSectionScoped crit_(lock_);
@ -139,6 +142,7 @@ class RtpRtcpObserver {
}
virtual bool SendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
EXPECT_TRUE(RtpHeaderParser::IsRtcp(packet, static_cast<int>(length)));
Action action;
{
CriticalSectionScoped crit_(lock_);

View File

@ -170,8 +170,9 @@ void CreateTraceDispatcher() {
Call* Call::Create(const Call::Config& config) {
CreateTraceDispatcher();
VideoEngine* video_engine = config.webrtc_config != NULL ?
VideoEngine::Create(*config.webrtc_config) : VideoEngine::Create();
VideoEngine* video_engine = config.webrtc_config != NULL
? VideoEngine::Create(*config.webrtc_config)
: VideoEngine::Create();
assert(video_engine != NULL);
return new internal::Call(video_engine, config);
@ -294,6 +295,12 @@ VideoReceiveStream* Call::CreateVideoReceiveStream(
WriteLockScoped write_lock(*receive_lock_);
assert(receive_ssrcs_.find(config.rtp.remote_ssrc) == receive_ssrcs_.end());
receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
// TODO(pbos): Configure different RTX payloads per receive payload.
VideoReceiveStream::Config::Rtp::RtxMap::const_iterator it =
config.rtp.rtx.begin();
if (it != config.rtp.rtx.end())
receive_ssrcs_[it->second.ssrc] = receive_stream;
return receive_stream;
}
@ -304,14 +311,16 @@ void Call::DestroyVideoReceiveStream(
VideoReceiveStream* receive_stream_impl = NULL;
{
WriteLockScoped write_lock(*receive_lock_);
for (std::map<uint32_t, VideoReceiveStream*>::iterator it =
receive_ssrcs_.begin();
it != receive_ssrcs_.end();
++it) {
// Remove all ssrcs pointing to a receive stream. As RTX retransmits on a
// separate SSRC there can be either one or two.
std::map<uint32_t, VideoReceiveStream*>::iterator it =
receive_ssrcs_.begin();
while (it != receive_ssrcs_.end()) {
if (it->second == static_cast<VideoReceiveStream*>(receive_stream)) {
receive_stream_impl = it->second;
receive_ssrcs_.erase(it);
break;
receive_ssrcs_.erase(it++);
} else {
++it;
}
}
}

View File

@ -18,7 +18,6 @@
#include "webrtc/call.h"
#include "webrtc/frame_callback.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
@ -41,8 +40,10 @@ namespace webrtc {
static unsigned int kDefaultTimeoutMs = 30 * 1000;
static unsigned int kLongTimeoutMs = 120 * 1000;
static const uint32_t kSendSsrc = 0x654321;
static const uint32_t kSendRtxSsrc = 0x424242;
static const uint32_t kReceiverLocalSsrc = 0x123456;
static const uint8_t kSendPayloadType = 125;
static const uint8_t kSendRtxPayloadType = 126;
class CallTest : public ::testing::Test {
public:
@ -125,6 +126,7 @@ class CallTest : public ::testing::Test {
receive_stream_ = NULL;
}
void DecodesRetransmittedFrame(bool retransmit_over_rtx);
void ReceivesPliAndRecovers(int rtp_history_ms);
void RespectsRtcpMode(newapi::RtcpMode rtcp_mode);
void TestXrReceiverReferenceTimeReport(bool enable_rrtr);
@ -159,8 +161,6 @@ class NackObserver : public test::RtpRtcpObserver {
private:
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
EXPECT_FALSE(RtpHeaderParser::IsRtcp(packet, static_cast<int>(length)));
RTPHeader header;
EXPECT_TRUE(rtp_parser_->Parse(packet, static_cast<int>(length), &header));
@ -328,7 +328,7 @@ TEST_F(CallTest, RendersSingleDelayedFrame) {
EventTypeWrapper Wait() { return event_->Wait(kDefaultTimeoutMs); }
private:
virtual void FrameCallback(I420VideoFrame* frame) {
virtual void FrameCallback(I420VideoFrame* frame) OVERRIDE {
SleepMs(kDelayRenderCallbackMs);
event_->Set();
}
@ -485,6 +485,99 @@ TEST_F(CallTest, ReceivesAndRetransmitsNack) {
DestroyStreams();
}
// This test drops second RTP packet with a marker bit set, makes sure it's
// retransmitted and renders. Retransmission SSRCs are also checked.
void CallTest::DecodesRetransmittedFrame(bool retransmit_over_rtx) {
static const int kDroppedFrameNumber = 2;
class RetransmissionObserver : public test::RtpRtcpObserver,
public I420FrameCallback {
public:
RetransmissionObserver(bool expect_rtx)
: RtpRtcpObserver(kDefaultTimeoutMs),
retransmission_ssrc_(expect_rtx ? kSendRtxSsrc : kSendSsrc),
retransmission_payload_type_(expect_rtx ? kSendRtxPayloadType
: kSendPayloadType),
marker_bits_observed_(0),
retransmitted_timestamp_(0),
frame_retransmitted_(false) {}
private:
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
if (header.timestamp == retransmitted_timestamp_) {
EXPECT_EQ(retransmission_ssrc_, header.ssrc);
EXPECT_EQ(retransmission_payload_type_, header.payloadType);
frame_retransmitted_ = true;
return SEND_PACKET;
}
EXPECT_EQ(kSendSsrc, header.ssrc);
EXPECT_EQ(kSendPayloadType, header.payloadType);
// Found the second frame's final packet, drop this and expect a
// retransmission.
if (header.markerBit && ++marker_bits_observed_ == kDroppedFrameNumber) {
retransmitted_timestamp_ = header.timestamp;
return DROP_PACKET;
}
return SEND_PACKET;
}
virtual void FrameCallback(I420VideoFrame* frame) OVERRIDE {
CriticalSectionScoped crit_(lock_.get());
if (frame->timestamp() == retransmitted_timestamp_) {
EXPECT_TRUE(frame_retransmitted_);
observation_complete_->Set();
}
}
const uint32_t retransmission_ssrc_;
const int retransmission_payload_type_;
int marker_bits_observed_;
uint32_t retransmitted_timestamp_;
bool frame_retransmitted_;
} observer(retransmit_over_rtx);
CreateCalls(Call::Config(observer.SendTransport()),
Call::Config(observer.ReceiveTransport()));
observer.SetReceivers(receiver_call_->Receiver(), sender_call_->Receiver());
CreateTestConfigs();
send_config_.rtp.nack.rtp_history_ms =
receive_config_.rtp.nack.rtp_history_ms = 1000;
if (retransmit_over_rtx) {
send_config_.rtp.rtx.ssrcs.push_back(kSendRtxSsrc);
send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
int payload_type = send_config_.codec.plType;
receive_config_.rtp.rtx[payload_type].ssrc = kSendRtxSsrc;
receive_config_.rtp.rtx[payload_type].payload_type = kSendRtxPayloadType;
}
receive_config_.pre_render_callback = &observer;
CreateStreams();
CreateFrameGenerator();
StartSending();
EXPECT_EQ(kEventSignaled, observer.Wait())
<< "Timed out while waiting for retransmission to render.";
StopSending();
observer.StopSending();
DestroyStreams();
}
TEST_F(CallTest, DecodesRetransmittedFrame) {
DecodesRetransmittedFrame(false);
}
TEST_F(CallTest, DecodesRetransmittedFrameOverRtx) {
DecodesRetransmittedFrame(true);
}
TEST_F(CallTest, UsesFrameCallbacks) {
static const int kWidth = 320;
static const int kHeight = 240;
@ -588,7 +681,6 @@ class PliObserver : public test::RtpRtcpObserver, public VideoRenderer {
public:
explicit PliObserver(bool nack_enabled)
: test::RtpRtcpObserver(kLongTimeoutMs),
rtp_header_parser_(RtpHeaderParser::Create()),
nack_enabled_(nack_enabled),
highest_dropped_timestamp_(0),
frames_to_drop_(0),
@ -596,8 +688,7 @@ class PliObserver : public test::RtpRtcpObserver, public VideoRenderer {
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
EXPECT_TRUE(
rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
// Drop all retransmitted packets to force a PLI.
if (header.timestamp <= highest_dropped_timestamp_)
@ -643,7 +734,6 @@ class PliObserver : public test::RtpRtcpObserver, public VideoRenderer {
private:
static const int kPacketsToDrop = 1;
scoped_ptr<RtpHeaderParser> rtp_header_parser_;
bool nack_enabled_;
uint32_t highest_dropped_timestamp_;
int frames_to_drop_;
@ -933,9 +1023,10 @@ TEST_F(CallTest, SendsAndReceivesMultipleStreams) {
TEST_F(CallTest, ObserversEncodedFrames) {
class EncodedFrameTestObserver : public EncodedFrameObserver {
public:
EncodedFrameTestObserver() : length_(0),
frame_type_(kFrameEmpty),
called_(EventWrapper::Create()) {}
EncodedFrameTestObserver()
: length_(0),
frame_type_(kFrameEmpty),
called_(EventWrapper::Create()) {}
virtual ~EncodedFrameTestObserver() {}
virtual void EncodedFrameCallback(const EncodedFrame& encoded_frame) {
@ -946,9 +1037,7 @@ TEST_F(CallTest, ObserversEncodedFrames) {
called_->Set();
}
EventTypeWrapper Wait() {
return called_->Wait(kDefaultTimeoutMs);
}
EventTypeWrapper Wait() { return called_->Wait(kDefaultTimeoutMs); }
void ExpectEqualFrames(const EncodedFrameTestObserver& observer) {
ASSERT_EQ(length_, observer.length_)
@ -1064,6 +1153,7 @@ void CallTest::TestXrReceiverReferenceTimeReport(bool enable_rrtr) {
sent_rtcp_rr_(0),
sent_rtcp_rrtr_(0),
sent_rtcp_dlrr_(0) {}
private:
// Receive stream should send RR packets (and RRTR packets if enabled).
virtual Action OnReceiveRtcp(const uint8_t* packet,
@ -1075,8 +1165,8 @@ void CallTest::TestXrReceiverReferenceTimeReport(bool enable_rrtr) {
while (packet_type != RTCPUtility::kRtcpNotValidCode) {
if (packet_type == RTCPUtility::kRtcpRrCode) {
++sent_rtcp_rr_;
} else if (
packet_type == RTCPUtility::kRtcpXrReceiverReferenceTimeCode) {
} else if (packet_type ==
RTCPUtility::kRtcpXrReceiverReferenceTimeCode) {
++sent_rtcp_rrtr_;
}
EXPECT_NE(packet_type, RTCPUtility::kRtcpSrCode);
@ -1122,8 +1212,7 @@ void CallTest::TestXrReceiverReferenceTimeReport(bool enable_rrtr) {
CreateCalls(Call::Config(observer.SendTransport()),
Call::Config(observer.ReceiveTransport()));
observer.SetReceivers(receiver_call_->Receiver(),
sender_call_->Receiver());
observer.SetReceivers(receiver_call_->Receiver(), sender_call_->Receiver());
CreateTestConfigs();
receive_config_.rtp.rtcp_mode = newapi::kRtcpReducedSize;

View File

@ -36,8 +36,8 @@
namespace webrtc {
namespace {
static const int kAbsoluteSendTimeExtensionId = 7;
static const int kMaxPacketSize = 1500;
static const int kAbsoluteSendTimeExtensionId = 7;
static const int kMaxPacketSize = 1500;
}
class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
@ -53,8 +53,9 @@ class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
rtp_parser_(RtpHeaderParser::Create()),
feedback_transport_(feedback_transport),
receive_stats_(ReceiveStatistics::Create(clock)),
payload_registry_(new RTPPayloadRegistry(
-1, RTPPayloadStrategy::CreateStrategy(false))),
payload_registry_(
new RTPPayloadRegistry(-1,
RTPPayloadStrategy::CreateStrategy(false))),
clock_(clock),
num_expected_ssrcs_(num_expected_ssrcs),
rtx_media_ssrcs_(rtx_media_ssrcs),
@ -88,19 +89,39 @@ class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
if (ssrcs.size() == num_expected_ssrcs_ && bitrate >= kExpectedBitrateBps) {
if (rtx_media_ssrcs_.empty() || rtx_media_sent_ > 0) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
webrtc::test::PrintResult("total-sent", "", test_info->name(),
total_sent_, "bytes", false);
webrtc::test::PrintResult("padding-sent", "", test_info->name(),
padding_sent_, "bytes", false);
webrtc::test::PrintResult("rtx-media-sent", "", test_info->name(),
rtx_media_sent_, "bytes", false);
webrtc::test::PrintResult("total-packets-sent", "", test_info->name(),
total_packets_sent_, "packets", false);
webrtc::test::PrintResult("padding-packets-sent", "", test_info->name(),
padding_packets_sent_, "packets", false);
webrtc::test::PrintResult("rtx-packets-sent", "", test_info->name(),
rtx_media_packets_sent_, "packets", false);
::testing::UnitTest::GetInstance()->current_test_info();
webrtc::test::PrintResult(
"total-sent", "", test_info->name(), total_sent_, "bytes", false);
webrtc::test::PrintResult("padding-sent",
"",
test_info->name(),
padding_sent_,
"bytes",
false);
webrtc::test::PrintResult("rtx-media-sent",
"",
test_info->name(),
rtx_media_sent_,
"bytes",
false);
webrtc::test::PrintResult("total-packets-sent",
"",
test_info->name(),
total_packets_sent_,
"packets",
false);
webrtc::test::PrintResult("padding-packets-sent",
"",
test_info->name(),
padding_packets_sent_,
"packets",
false);
webrtc::test::PrintResult("rtx-packets-sent",
"",
test_info->name(),
rtx_media_packets_sent_,
"packets",
false);
all_ssrcs_sent_->Set();
}
}
@ -132,13 +153,14 @@ class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
uint8_t restored_packet[kMaxPacketSize];
uint8_t* restored_packet_ptr = restored_packet;
int restored_length = static_cast<int>(length);
payload_registry_->RestoreOriginalPacket(
&restored_packet_ptr, packet, &restored_length,
rtx_media_ssrcs_[header.ssrc],
header);
payload_registry_->RestoreOriginalPacket(&restored_packet_ptr,
packet,
&restored_length,
rtx_media_ssrcs_[header.ssrc],
header);
length = restored_length;
EXPECT_TRUE(rtp_parser_->Parse(restored_packet, static_cast<int>(length),
&header));
EXPECT_TRUE(rtp_parser_->Parse(
restored_packet, static_cast<int>(length), &header));
} else {
rtp_rtcp_->SetRemoteSSRC(header.ssrc);
}
@ -191,9 +213,10 @@ class RampUpTest : public ::testing::TestWithParam<bool> {
}
test::DirectTransport receiver_transport;
int num_expected_ssrcs = kNumberOfStreams + (rtx ? 1 : 0);
StreamObserver stream_observer(
num_expected_ssrcs, rtx_ssrc_map, &receiver_transport,
Clock::GetRealTimeClock());
StreamObserver stream_observer(num_expected_ssrcs,
rtx_ssrc_map,
&receiver_transport,
Clock::GetRealTimeClock());
Call::Config call_config(&stream_observer);
webrtc::Config webrtc_config;
@ -211,10 +234,10 @@ class RampUpTest : public ::testing::TestWithParam<bool> {
send_config.codec.plType = 125;
send_config.pacing = pacing;
send_config.rtp.nack.rtp_history_ms = 1000;
send_config.rtp.ssrcs.insert(send_config.rtp.ssrcs.begin(), ssrcs.begin(),
ssrcs.end());
send_config.rtp.ssrcs.insert(
send_config.rtp.ssrcs.begin(), ssrcs.begin(), ssrcs.end());
if (rtx) {
send_config.rtp.rtx.rtx_payload_type = 96;
send_config.rtp.rtx.payload_type = 96;
send_config.rtp.rtx.ssrcs.insert(send_config.rtp.rtx.ssrcs.begin(),
kRtxSsrcs,
kRtxSsrcs + kNumberOfStreams);
@ -244,16 +267,10 @@ class RampUpTest : public ::testing::TestWithParam<bool> {
std::map<uint32_t, bool> reserved_ssrcs_;
};
TEST_F(RampUpTest, WithoutPacing) {
RunRampUpTest(false, false);
}
TEST_F(RampUpTest, WithoutPacing) { RunRampUpTest(false, false); }
TEST_F(RampUpTest, WithPacing) {
RunRampUpTest(true, false);
}
TEST_F(RampUpTest, WithPacing) { RunRampUpTest(true, false); }
TEST_F(RampUpTest, WithPacingAndRtx) {
RunRampUpTest(true, true);
}
TEST_F(RampUpTest, WithPacingAndRtx) { RunRampUpTest(true, true); }
} // namespace webrtc

View File

@ -59,10 +59,21 @@ VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
}
assert(config_.rtp.remote_ssrc != 0);
// TODO(pbos): What's an appropriate local_ssrc for receive-only streams?
assert(config_.rtp.local_ssrc != 0);
assert(config_.rtp.remote_ssrc != config_.rtp.local_ssrc);
rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.local_ssrc);
// TODO(pbos): Support multiple RTX, per video payload.
Config::Rtp::RtxMap::const_iterator it = config_.rtp.rtx.begin();
if (it != config_.rtp.rtx.end()) {
assert(it->second.ssrc != 0);
assert(it->second.payload_type != 0);
rtp_rtcp_->SetRemoteSSRCType(channel_, kViEStreamTypeRtx, it->second.ssrc);
rtp_rtcp_->SetRtxReceivePayloadType(channel_, it->second.payload_type);
}
rtp_rtcp_->SetRembStatus(channel_, false, config_.rtp.remb);
for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
@ -102,8 +113,7 @@ VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
decoder->payload_type,
decoder->decoder,
decoder->renderer,
decoder->expected_delay_ms) !=
0) {
decoder->expected_delay_ms) != 0) {
// TODO(pbos): Abort gracefully? Can this be a runtime error?
abort();
}
@ -182,8 +192,7 @@ bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
bool VideoReceiveStream::DeliverRtp(const uint8_t* packet, size_t length) {
return network_->ReceivedRTPPacket(
channel_, packet, static_cast<int>(length),
PacketTime()) == 0;
channel_, packet, static_cast<int>(length), PacketTime()) == 0;
}
int32_t VideoReceiveStream::RenderFrame(const uint32_t stream_id,

View File

@ -156,9 +156,11 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
if (config.encoder) {
external_codec_ = ViEExternalCodec::GetInterface(video_engine);
if (external_codec_->RegisterExternalSendCodec(
channel_, config.codec.plType, config.encoder,
config.internal_source) != 0) {
if (external_codec_->RegisterExternalSendCodec(channel_,
config.codec.plType,
config.encoder,
config.internal_source) !=
0) {
abort();
}
}
@ -168,9 +170,8 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
abort();
if (overuse_detection) {
overuse_observer_.reset(
new ResolutionAdaptor(codec_, channel_, config_.codec.width,
config_.codec.height));
overuse_observer_.reset(new ResolutionAdaptor(
codec_, channel_, config_.codec.width, config_.codec.height));
video_engine_base_->RegisterCpuOveruseObserver(channel_,
overuse_observer_.get());
}
@ -187,8 +188,7 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
codec_->SuspendBelowMinBitrate(channel_);
}
stats_proxy_.reset(
new SendStatisticsProxy(config, this));
stats_proxy_.reset(new SendStatisticsProxy(config, this));
rtp_rtcp_->RegisterSendChannelRtcpStatisticsCallback(channel_,
stats_proxy_.get());
@ -282,7 +282,9 @@ bool VideoSendStream::SetCodec(const VideoCodec& codec) {
static_cast<unsigned char>(i));
}
config_.codec = codec;
if (&config_.codec != &codec)
config_.codec = codec;
if (config_.rtp.rtx.ssrcs.empty())
return true;
@ -295,10 +297,8 @@ bool VideoSendStream::SetCodec(const VideoCodec& codec) {
static_cast<unsigned char>(i));
}
if (config_.rtp.rtx.rtx_payload_type != 0) {
rtp_rtcp_->SetRtxSendPayloadType(channel_,
config_.rtp.rtx.rtx_payload_type);
}
if (config_.rtp.rtx.payload_type != 0)
rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type);
return true;
}

View File

@ -93,8 +93,8 @@ const uint8_t VideoSendStreamTest::kSendPayloadType = 100;
const uint8_t VideoSendStreamTest::kFakeSendPayloadType = 125;
const uint8_t VideoSendStreamTest::kSendRtxPayloadType = 98;
const uint32_t VideoSendStreamTest::kSendRtxSsrc = 0xBADCAFE;
const uint32_t VideoSendStreamTest::kSendSsrcs[kNumSendSsrcs] = { 0xC0FFED,
0xC0FFEE, 0xC0FFEF };
const uint32_t VideoSendStreamTest::kSendSsrcs[kNumSendSsrcs] = {
0xC0FFED, 0xC0FFEE, 0xC0FFEF};
const uint32_t VideoSendStreamTest::kSendSsrc =
VideoSendStreamTest::kSendSsrcs[0];
@ -121,10 +121,10 @@ void VideoSendStreamTest::SendsSetSsrcs(size_t num_ssrcs,
// to fail on TSan as the codec gets set before the SSRCs are
// set up and some frames are sent on a random-generated SSRC
// before the correct SSRC gets set.
//EXPECT_TRUE(valid_ssrcs_[header.ssrc])
// EXPECT_TRUE(valid_ssrcs_[header.ssrc])
// << "Received unknown SSRC: " << header.ssrc;
//
//if (!valid_ssrcs_[header.ssrc])
// if (!valid_ssrcs_[header.ssrc])
// observation_complete_->Set();
if (!is_observed_[header.ssrc]) {
@ -271,8 +271,7 @@ TEST_F(VideoSendStreamTest, SupportsAbsoluteSendTime) {
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
EXPECT_TRUE(
parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
EXPECT_TRUE(header.extension.hasAbsoluteSendTime);
@ -299,10 +298,10 @@ TEST_F(VideoSendStreamTest, SupportsTransmissionTimeOffset) {
class DelayedEncoder : public test::FakeEncoder {
public:
explicit DelayedEncoder(Clock* clock) : test::FakeEncoder(clock) {}
virtual int32_t Encode(
const I420VideoFrame& input_image,
const CodecSpecificInfo* codec_specific_info,
const std::vector<VideoFrameType>* frame_types) OVERRIDE {
virtual int32_t Encode(const I420VideoFrame& input_image,
const CodecSpecificInfo* codec_specific_info,
const std::vector<VideoFrameType>* frame_types)
OVERRIDE {
// A delay needs to be introduced to assure that we get a timestamp
// offset.
SleepMs(5);
@ -319,8 +318,7 @@ TEST_F(VideoSendStreamTest, SupportsTransmissionTimeOffset) {
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
EXPECT_TRUE(
parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
EXPECT_FALSE(header.extension.hasAbsoluteSendTime);
@ -439,8 +437,7 @@ TEST_F(VideoSendStreamTest, SupportsFec) {
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
EXPECT_TRUE(
parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
// Send lossy receive reports to trigger FEC enabling.
if (send_count_++ % 2 != 0) {
@ -511,8 +508,7 @@ void VideoSendStreamTest::TestNackRetransmission(
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
EXPECT_TRUE(
parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
// Nack second packet after receiving the third one.
if (++send_count_ == 3) {
@ -564,7 +560,7 @@ void VideoSendStreamTest::TestNackRetransmission(
VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1);
send_config.rtp.nack.rtp_history_ms = 1000;
send_config.rtp.rtx.rtx_payload_type = retransmit_payload_type;
send_config.rtp.rtx.payload_type = retransmit_payload_type;
send_config.pacing = enable_pacing;
if (retransmit_ssrc != kSendSsrc)
send_config.rtp.rtx.ssrcs.push_back(retransmit_ssrc);
@ -611,8 +607,7 @@ TEST_F(VideoSendStreamTest, FragmentsAccordingToMaxPacketSize) {
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
EXPECT_TRUE(
parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
EXPECT_LE(length, max_packet_size_);
@ -721,9 +716,7 @@ TEST_F(VideoSendStreamTest, CanChangeSendCodec) {
return kEventSignaled;
}
void SetSecondCodec(const VideoCodec& codec) {
second_codec_ = codec;
}
void SetSecondCodec(const VideoCodec& codec) { second_codec_ = codec; }
private:
scoped_ptr<EventWrapper> received_first_payload_;
@ -913,8 +906,9 @@ TEST_F(VideoSendStreamTest, NoPaddingWhenVideoIsMuted) {
virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
CriticalSectionScoped lock(crit_sect_.get());
const int kVideoMutedThresholdMs = 10000;
if (last_packet_time_ms_ > 0 && clock_->TimeInMilliseconds() -
last_packet_time_ms_ > kVideoMutedThresholdMs)
if (last_packet_time_ms_ > 0 &&
clock_->TimeInMilliseconds() - last_packet_time_ms_ >
kVideoMutedThresholdMs)
observation_complete_->Set();
// Receive statistics reporting having lost 50% of the packets.
FakeReceiveStatistics receive_stats(kSendSsrcs[0], 1, 1, 0);

View File

@ -26,10 +26,7 @@ namespace webrtc {
namespace newapi {
// RTCP mode to use. Compound mode is described by RFC 4585 and reduced-size
// RTCP mode is described by RFC 5506.
enum RtcpMode {
kRtcpCompound,
kRtcpReducedSize
};
enum RtcpMode { kRtcpCompound, kRtcpReducedSize };
} // namespace newapi
class VideoDecoder;
@ -138,9 +135,21 @@ class VideoReceiveStream {
// See FecConfig for description.
FecConfig fec;
// RTX settings for video payloads that may be received. RTX is disabled
// if there's no config present.
std::map<int, RtxConfig> rtx;
// RTX settings for incoming video payloads that may be received. RTX is
// disabled if there's no config present.
struct Rtx {
Rtx() : ssrc(0), payload_type(0) {}
// SSRCs to use for the RTX streams.
uint32_t ssrc;
// Payload type to use for the RTX stream.
int payload_type;
};
// Map from video RTP payload type -> RTX config.
typedef std::map<int, Rtx> RtxMap;
RtxMap rtx;
// RTP header extensions used for the received stream.
std::vector<RtpExtension> extensions;

View File

@ -96,8 +96,16 @@ class VideoSendStream {
// See FecConfig for description.
FecConfig fec;
// See RtxConfig for description.
RtxConfig rtx;
// Settings for RTP retransmission payload format, see RFC 4588 for
// details.
struct Rtx {
Rtx() : payload_type(0) {}
// SSRCs to use for the RTX streams.
std::vector<uint32_t> ssrcs;
// Payload type to use for the RTX stream.
int payload_type;
} rtx;
// RTCP CNAME, see RFC 3550.
std::string c_name;