Preserve RTP states for restarted VideoSendStreams.

A restarted VideoSendStream would previously be completely reset,
causing gaps in sequence numbers and potentially RTP timestamps as well.
This broke SRTP which requires fairly sequential sequence numbers.
Presumably, were this sent without SRTP, we'd still have problems on the
receiving end as the corresponding receiver is unaware of this reset.

Also adding annotation to RTPSender and addressing some unlocked
access to ssrc_, ssrc_rtx_ and rtx_.

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

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6612 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org 2014-07-07 13:06:48 +00:00
parent 73823cafa4
commit 2bb1bdab8d
21 changed files with 530 additions and 108 deletions

View File

@ -203,6 +203,10 @@ class RtpRtcp : public Module {
*/
virtual int32_t SetSequenceNumber(const uint16_t seq) = 0;
virtual void SetRtpStateForSsrc(uint32_t ssrc,
const RtpState& rtp_state) = 0;
virtual bool GetRtpStateForSsrc(uint32_t ssrc, RtpState* rtp_state) = 0;
/*
* Get SSRC
*/

View File

@ -192,6 +192,20 @@ struct RtcpReceiveTimeInfo {
typedef std::list<RTCPReportBlock> ReportBlockList;
struct RtpState {
RtpState()
: sequence_number(0),
start_timestamp(0),
timestamp(0),
capture_time_ms(-1),
last_timestamp_time_ms(-1) {}
uint16_t sequence_number;
uint32_t start_timestamp;
uint32_t timestamp;
int64_t capture_time_ms;
int64_t last_timestamp_time_ms;
};
class RtpData
{
public:

View File

@ -74,6 +74,9 @@ class MockRtpRtcp : public RtpRtcp {
uint16_t());
MOCK_METHOD1(SetSequenceNumber,
int32_t(const uint16_t seq));
MOCK_METHOD2(SetRtpStateForSsrc,
void(uint32_t ssrc, const RtpState& rtp_state));
MOCK_METHOD2(GetRtpStateForSsrc, bool(uint32_t ssrc, RtpState* rtp_state));
MOCK_CONST_METHOD0(SSRC,
uint32_t());
MOCK_METHOD1(SetSSRC,

View File

@ -1361,8 +1361,6 @@ int32_t RTCPReceiver::UpdateTMMBR() {
void RTCPReceiver::RegisterRtcpStatisticsCallback(
RtcpStatisticsCallback* callback) {
CriticalSectionScoped cs(_criticalSectionFeedbacks);
if (callback != NULL)
assert(stats_callback_ == NULL);
stats_callback_ = callback;
}

View File

@ -333,6 +333,42 @@ int32_t ModuleRtpRtcpImpl::SetSequenceNumber(
return 0; // TODO(pwestin): change to void.
}
void ModuleRtpRtcpImpl::SetRtpStateForSsrc(uint32_t ssrc,
const RtpState& rtp_state) {
if (rtp_sender_.SSRC() == ssrc) {
rtp_sender_.SetRtpState(rtp_state);
return;
}
if (rtp_sender_.RtxSsrc() == ssrc) {
rtp_sender_.SetRtxRtpState(rtp_state);
return;
}
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
for (size_t i = 0; i < child_modules_.size(); ++i) {
child_modules_[i]->SetRtpStateForSsrc(ssrc, rtp_state);
}
}
bool ModuleRtpRtcpImpl::GetRtpStateForSsrc(uint32_t ssrc, RtpState* rtp_state) {
if (rtp_sender_.SSRC() == ssrc) {
*rtp_state = rtp_sender_.GetRtpState();
return true;
}
if (rtp_sender_.RtxSsrc() == ssrc) {
*rtp_state = rtp_sender_.GetRtxRtpState();
return true;
}
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
for (size_t i = 0; i < child_modules_.size(); ++i) {
if (child_modules_[i]->GetRtpStateForSsrc(ssrc, rtp_state))
return true;
}
return false;
}
uint32_t ModuleRtpRtcpImpl::SSRC() const {
return rtp_sender_.SSRC();
}

View File

@ -73,6 +73,10 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
// Set SequenceNumber, default is a random number.
virtual int32_t SetSequenceNumber(const uint16_t seq) OVERRIDE;
virtual void SetRtpStateForSsrc(uint32_t ssrc,
const RtpState& rtp_state) OVERRIDE;
virtual bool GetRtpStateForSsrc(uint32_t ssrc, RtpState* rtp_state) OVERRIDE;
virtual uint32_t SSRC() const OVERRIDE;
// Configure SSRC, default is a random number.

View File

@ -74,8 +74,8 @@ RTPSender::RTPSender(const int32_t id,
rtp_stats_callback_(NULL),
bitrate_callback_(NULL),
// RTP variables
start_time_stamp_forced_(false),
start_time_stamp_(0),
start_timestamp_forced_(false),
start_timestamp_(0),
ssrc_db_(*SSRCDatabase::GetSSRCDatabase()),
remote_ssrc_(0),
sequence_number_forced_(false),
@ -304,12 +304,17 @@ int32_t RTPSender::SetMaxPayloadLength(
}
uint16_t RTPSender::MaxDataPayloadLength() const {
int rtx;
{
CriticalSectionScoped rtx_lock(send_critsect_);
rtx = rtx_;
}
if (audio_configured_) {
return max_payload_length_ - RTPHeaderLength();
} else {
return max_payload_length_ - RTPHeaderLength() // RTP overhead.
- video_->FECPacketOverhead() // FEC/ULP/RED overhead.
- ((rtx_) ? 2 : 0); // RTX overhead.
- ((rtx) ? 2 : 0); // RTX overhead.
}
}
@ -329,6 +334,11 @@ void RTPSender::SetRtxSsrc(uint32_t ssrc) {
ssrc_rtx_ = ssrc;
}
uint32_t RTPSender::RtxSsrc() const {
CriticalSectionScoped cs(send_critsect_);
return ssrc_rtx_;
}
void RTPSender::RTXStatus(int* mode, uint32_t* ssrc,
int* payload_type) const {
CriticalSectionScoped cs(send_critsect_);
@ -389,9 +399,11 @@ int32_t RTPSender::SendOutgoingData(
const uint8_t *payload_data, const uint32_t payload_size,
const RTPFragmentationHeader *fragmentation,
VideoCodecInformation *codec_info, const RTPVideoTypeHeader *rtp_type_hdr) {
uint32_t ssrc;
{
// Drop this packet if we're not sending media packets.
CriticalSectionScoped cs(send_critsect_);
ssrc = ssrc_;
if (!sending_media_) {
return 0;
}
@ -435,17 +447,13 @@ int32_t RTPSender::SendOutgoingData(
CriticalSectionScoped cs(statistics_crit_.get());
uint32_t frame_count = ++frame_counts_[frame_type];
if (frame_count_observer_) {
frame_count_observer_->FrameCountUpdated(frame_type,
frame_count,
ssrc_);
frame_count_observer_->FrameCountUpdated(frame_type, frame_count, ssrc);
}
return ret_val;
}
int RTPSender::SendRedundantPayloads(int payload_type, int bytes_to_send) {
if (!(rtx_ & kRtxRedundantPayloads))
return 0;
uint8_t buffer[IP_PACKET_SIZE];
int bytes_left = bytes_to_send;
while (bytes_left > 0) {
@ -493,7 +501,7 @@ bool RTPSender::SendPaddingAccordingToBitrate(
CriticalSectionScoped cs(send_critsect_);
// Add the random RTP timestamp offset and store the capture time for
// later calculation of the send time offset.
timestamp = start_time_stamp_ + capture_timestamp;
timestamp = start_timestamp_ + capture_timestamp;
timestamp_ = timestamp;
capture_time_ms_ = capture_time_ms;
last_timestamp_time_ms_ = clock_->TimeInMilliseconds();
@ -567,6 +575,7 @@ int RTPSender::SendPadData(int payload_type, uint32_t timestamp,
++sequence_number_rtx_;
}
}
uint8_t padding_packet[IP_PACKET_SIZE];
int header_length = CreateRTPHeader(padding_packet, payload_type, ssrc,
false, timestamp, sequence_number, NULL,
@ -628,6 +637,7 @@ int32_t RTPSender::ReSendPacket(uint16_t packet_id, uint32_t min_resend_time) {
}
}
CriticalSectionScoped lock(send_critsect_);
return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
(rtx_ & kRtxRetransmitted) > 0, true) ?
length : -1;
@ -784,8 +794,15 @@ bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
if (!retransmission && capture_time_ms > 0) {
UpdateDelayStatistics(capture_time_ms, clock_->TimeInMilliseconds());
}
return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
retransmission && (rtx_ & kRtxRetransmitted) > 0,
int rtx;
{
CriticalSectionScoped lock(send_critsect_);
rtx = rtx_;
}
return PrepareAndSendPacket(data_buffer,
length,
capture_time_ms,
retransmission && (rtx & kRtxRetransmitted) > 0,
retransmission);
}
@ -827,12 +844,11 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer,
bool is_retransmit) {
StreamDataCounters* counters;
// Get ssrc before taking statistics_crit_ to avoid possible deadlock.
uint32_t ssrc = SSRC();
uint32_t ssrc = is_rtx ? RtxSsrc() : SSRC();
CriticalSectionScoped lock(statistics_crit_.get());
if (is_rtx) {
counters = &rtx_rtp_stats_;
ssrc = ssrc_rtx_;
} else {
counters = &rtp_stats_;
}
@ -874,6 +890,7 @@ int RTPSender::TimeToSendPadding(int bytes) {
int payload_type;
int64_t capture_time_ms;
uint32_t timestamp;
int rtx;
{
CriticalSectionScoped cs(send_critsect_);
if (!sending_media_) {
@ -889,8 +906,11 @@ int RTPSender::TimeToSendPadding(int bytes) {
capture_time_ms +=
(clock_->TimeInMilliseconds() - last_timestamp_time_ms_);
}
rtx = rtx_;
}
int bytes_sent = SendRedundantPayloads(payload_type, bytes);
int bytes_sent = 0;
if ((rtx & kRtxRedundantPayloads) != 0)
bytes_sent = SendRedundantPayloads(payload_type, bytes);
bytes -= bytes_sent;
if (bytes > 0) {
int padding_sent = SendPadData(payload_type,
@ -899,7 +919,7 @@ int RTPSender::TimeToSendPadding(int bytes) {
bytes,
kDontStore,
true,
rtx_ == kRtxOff);
rtx == kRtxOff);
bytes_sent += padding_sent;
}
return bytes_sent;
@ -975,6 +995,7 @@ void RTPSender::ProcessBitrate() {
}
uint16_t RTPSender::RTPHeaderLength() const {
CriticalSectionScoped lock(send_critsect_);
uint16_t rtp_header_length = 12;
if (include_csrcs_) {
rtp_header_length += sizeof(uint32_t) * num_csrcs_;
@ -989,12 +1010,19 @@ uint16_t RTPSender::IncrementSequenceNumber() {
}
void RTPSender::ResetDataCounters() {
uint32_t ssrc;
uint32_t ssrc_rtx;
{
CriticalSectionScoped ssrc_lock(send_critsect_);
ssrc = ssrc_;
ssrc_rtx = ssrc_rtx_;
}
CriticalSectionScoped lock(statistics_crit_.get());
rtp_stats_ = StreamDataCounters();
rtx_rtp_stats_ = StreamDataCounters();
if (rtp_stats_callback_) {
rtp_stats_callback_->DataCountersUpdated(rtp_stats_, ssrc_);
rtp_stats_callback_->DataCountersUpdated(rtx_rtp_stats_, ssrc_rtx_);
rtp_stats_callback_->DataCountersUpdated(rtp_stats_, ssrc);
rtp_stats_callback_->DataCountersUpdated(rtx_rtp_stats_, ssrc_rtx);
}
}
@ -1049,16 +1077,18 @@ int RTPSender::CreateRTPHeader(
return rtp_header_length;
}
int32_t RTPSender::BuildRTPheader(
uint8_t *data_buffer, const int8_t payload_type,
const bool marker_bit, const uint32_t capture_timestamp,
int64_t capture_time_ms, const bool time_stamp_provided,
const bool inc_sequence_number) {
int32_t RTPSender::BuildRTPheader(uint8_t* data_buffer,
const int8_t payload_type,
const bool marker_bit,
const uint32_t capture_timestamp,
int64_t capture_time_ms,
const bool timestamp_provided,
const bool inc_sequence_number) {
assert(payload_type >= 0);
CriticalSectionScoped cs(send_critsect_);
if (time_stamp_provided) {
timestamp_ = start_time_stamp_ + capture_timestamp;
if (timestamp_provided) {
timestamp_ = start_timestamp_ + capture_timestamp;
} else {
// Make a unique time stamp.
// We can't inc by the actual time, since then we increase the risk of back
@ -1380,6 +1410,7 @@ void RTPSender::SetSendingStatus(bool enabled) {
// Will be ignored if it's already configured via API.
SetStartTimestamp(RTPtime, false);
} else {
CriticalSectionScoped lock(send_critsect_);
if (!ssrc_forced_) {
// Generate a new SSRC.
ssrc_db_.ReturnSSRC(ssrc_);
@ -1412,18 +1443,18 @@ uint32_t RTPSender::Timestamp() const {
void RTPSender::SetStartTimestamp(uint32_t timestamp, bool force) {
CriticalSectionScoped cs(send_critsect_);
if (force) {
start_time_stamp_forced_ = force;
start_time_stamp_ = timestamp;
start_timestamp_forced_ = true;
start_timestamp_ = timestamp;
} else {
if (!start_time_stamp_forced_) {
start_time_stamp_ = timestamp;
if (!start_timestamp_forced_) {
start_timestamp_ = timestamp;
}
}
}
uint32_t RTPSender::StartTimestamp() const {
CriticalSectionScoped cs(send_critsect_);
return start_time_stamp_;
return start_timestamp_;
}
uint32_t RTPSender::GenerateNewSSRC() {
@ -1460,6 +1491,7 @@ uint32_t RTPSender::SSRC() const {
}
void RTPSender::SetCSRCStatus(const bool include) {
CriticalSectionScoped lock(send_critsect_);
include_csrcs_ = include;
}
@ -1635,8 +1667,6 @@ void RTPSender::BuildRtxPacket(uint8_t* buffer, uint16_t* length,
void RTPSender::RegisterFrameCountObserver(FrameCountObserver* observer) {
CriticalSectionScoped cs(statistics_crit_.get());
if (observer != NULL)
assert(frame_count_observer_ == NULL);
frame_count_observer_ = observer;
}
@ -1648,8 +1678,6 @@ FrameCountObserver* RTPSender::GetFrameCountObserver() const {
void RTPSender::RegisterRtpStatisticsCallback(
StreamDataCountersCallback* callback) {
CriticalSectionScoped cs(statistics_crit_.get());
if (callback != NULL)
assert(rtp_stats_callback_ == NULL);
rtp_stats_callback_ = callback;
}
@ -1660,8 +1688,6 @@ StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const {
void RTPSender::RegisterBitrateObserver(BitrateStatisticsObserver* observer) {
CriticalSectionScoped cs(statistics_crit_.get());
if (observer != NULL)
assert(bitrate_callback_ == NULL);
bitrate_callback_ = observer;
}
@ -1673,9 +1699,53 @@ BitrateStatisticsObserver* RTPSender::GetBitrateObserver() const {
uint32_t RTPSender::BitrateSent() const { return bitrate_sent_.BitrateLast(); }
void RTPSender::BitrateUpdated(const BitrateStatistics& stats) {
uint32_t ssrc;
{
CriticalSectionScoped ssrc_lock(send_critsect_);
ssrc = ssrc_;
}
CriticalSectionScoped cs(statistics_crit_.get());
if (bitrate_callback_) {
bitrate_callback_->Notify(stats, ssrc_);
bitrate_callback_->Notify(stats, ssrc);
}
}
void RTPSender::SetRtpState(const RtpState& rtp_state) {
SetStartTimestamp(rtp_state.start_timestamp, true);
CriticalSectionScoped lock(send_critsect_);
sequence_number_ = rtp_state.sequence_number;
sequence_number_forced_ = true;
timestamp_ = rtp_state.timestamp;
capture_time_ms_ = rtp_state.capture_time_ms;
last_timestamp_time_ms_ = rtp_state.last_timestamp_time_ms;
}
RtpState RTPSender::GetRtpState() const {
CriticalSectionScoped lock(send_critsect_);
RtpState state;
state.sequence_number = sequence_number_;
state.start_timestamp = start_timestamp_;
state.timestamp = timestamp_;
state.capture_time_ms = capture_time_ms_;
state.last_timestamp_time_ms = last_timestamp_time_ms_;
return state;
}
void RTPSender::SetRtxRtpState(const RtpState& rtp_state) {
CriticalSectionScoped lock(send_critsect_);
sequence_number_rtx_ = rtp_state.sequence_number;
}
RtpState RTPSender::GetRtxRtpState() const {
CriticalSectionScoped lock(send_critsect_);
RtpState state;
state.sequence_number = sequence_number_rtx_;
state.start_timestamp = start_timestamp_;
return state;
}
} // namespace webrtc

View File

@ -43,12 +43,13 @@ class RTPSenderInterface {
virtual uint32_t SSRC() const = 0;
virtual uint32_t Timestamp() const = 0;
virtual int32_t BuildRTPheader(
uint8_t *data_buffer, const int8_t payload_type,
const bool marker_bit, const uint32_t capture_time_stamp,
int64_t capture_time_ms,
const bool time_stamp_provided = true,
const bool inc_sequence_number = true) = 0;
virtual int32_t BuildRTPheader(uint8_t* data_buffer,
const int8_t payload_type,
const bool marker_bit,
const uint32_t capture_timestamp,
int64_t capture_time_ms,
const bool timestamp_provided = true,
const bool inc_sequence_number = true) = 0;
virtual uint16_t RTPHeaderLength() const = 0;
virtual uint16_t IncrementSequenceNumber() = 0;
@ -132,13 +133,15 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
int32_t SetMaxPayloadLength(const uint16_t length,
const uint16_t packet_over_head);
int32_t SendOutgoingData(
const FrameType frame_type, const int8_t payload_type,
const uint32_t time_stamp, int64_t capture_time_ms,
const uint8_t *payload_data, const uint32_t payload_size,
const RTPFragmentationHeader *fragmentation,
VideoCodecInformation *codec_info = NULL,
const RTPVideoTypeHeader * rtp_type_hdr = NULL);
int32_t SendOutgoingData(const FrameType frame_type,
const int8_t payload_type,
const uint32_t timestamp,
int64_t capture_time_ms,
const uint8_t* payload_data,
const uint32_t payload_size,
const RTPFragmentationHeader* fragmentation,
VideoCodecInformation* codec_info = NULL,
const RTPVideoTypeHeader* rtp_type_hdr = NULL);
// RTP header extension
int32_t SetTransmissionTimeOffset(
@ -189,16 +192,19 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
void RTXStatus(int* mode, uint32_t* ssrc, int* payload_type) const;
uint32_t RtxSsrc() const;
void SetRtxSsrc(uint32_t ssrc);
void SetRtxPayloadType(int payloadType);
// Functions wrapping RTPSenderInterface.
virtual int32_t BuildRTPheader(
uint8_t *data_buffer, const int8_t payload_type,
const bool marker_bit, const uint32_t capture_time_stamp,
uint8_t* data_buffer,
const int8_t payload_type,
const bool marker_bit,
const uint32_t capture_timestamp,
int64_t capture_time_ms,
const bool time_stamp_provided = true,
const bool timestamp_provided = true,
const bool inc_sequence_number = true) OVERRIDE;
virtual uint16_t RTPHeaderLength() const OVERRIDE;
@ -277,6 +283,11 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
virtual void BitrateUpdated(const BitrateStatistics& stats) OVERRIDE;
void SetRtpState(const RtpState& rtp_state);
RtpState GetRtpState() const;
void SetRtxRtpState(const RtpState& rtp_state);
RtpState GetRtxRtpState() const;
protected:
int32_t CheckPayloadType(const int8_t payload_type,
RtpVideoCodecTypes *video_type);
@ -363,34 +374,34 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
// Statistics
scoped_ptr<CriticalSectionWrapper> statistics_crit_;
SendDelayMap send_delays_;
std::map<FrameType, uint32_t> frame_counts_;
FrameCountObserver* frame_count_observer_;
StreamDataCounters rtp_stats_;
StreamDataCounters rtx_rtp_stats_;
StreamDataCountersCallback* rtp_stats_callback_;
BitrateStatisticsObserver* bitrate_callback_;
SendDelayMap send_delays_ GUARDED_BY(statistics_crit_);
std::map<FrameType, uint32_t> frame_counts_ GUARDED_BY(statistics_crit_);
FrameCountObserver* frame_count_observer_ GUARDED_BY(statistics_crit_);
StreamDataCounters rtp_stats_ GUARDED_BY(statistics_crit_);
StreamDataCounters rtx_rtp_stats_ GUARDED_BY(statistics_crit_);
StreamDataCountersCallback* rtp_stats_callback_ GUARDED_BY(statistics_crit_);
BitrateStatisticsObserver* bitrate_callback_ GUARDED_BY(statistics_crit_);
// RTP variables
bool start_time_stamp_forced_;
uint32_t start_time_stamp_;
SSRCDatabase &ssrc_db_;
uint32_t remote_ssrc_;
bool sequence_number_forced_;
uint16_t sequence_number_;
uint16_t sequence_number_rtx_;
bool ssrc_forced_;
uint32_t ssrc_;
uint32_t timestamp_;
int64_t capture_time_ms_;
int64_t last_timestamp_time_ms_;
bool last_packet_marker_bit_;
uint8_t num_csrcs_;
uint32_t csrcs_[kRtpCsrcSize];
bool include_csrcs_;
int rtx_;
uint32_t ssrc_rtx_;
int payload_type_rtx_;
bool start_timestamp_forced_ GUARDED_BY(send_critsect_);
uint32_t start_timestamp_ GUARDED_BY(send_critsect_);
SSRCDatabase& ssrc_db_ GUARDED_BY(send_critsect_);
uint32_t remote_ssrc_ GUARDED_BY(send_critsect_);
bool sequence_number_forced_ GUARDED_BY(send_critsect_);
uint16_t sequence_number_ GUARDED_BY(send_critsect_);
uint16_t sequence_number_rtx_ GUARDED_BY(send_critsect_);
bool ssrc_forced_ GUARDED_BY(send_critsect_);
uint32_t ssrc_ GUARDED_BY(send_critsect_);
uint32_t timestamp_ GUARDED_BY(send_critsect_);
int64_t capture_time_ms_ GUARDED_BY(send_critsect_);
int64_t last_timestamp_time_ms_ GUARDED_BY(send_critsect_);
bool last_packet_marker_bit_ GUARDED_BY(send_critsect_);
uint8_t num_csrcs_ GUARDED_BY(send_critsect_);
uint32_t csrcs_[kRtpCsrcSize] GUARDED_BY(send_critsect_);
bool include_csrcs_ GUARDED_BY(send_critsect_);
int rtx_ GUARDED_BY(send_critsect_);
uint32_t ssrc_rtx_ GUARDED_BY(send_critsect_);
int payload_type_rtx_ GUARDED_BY(send_critsect_);
// Note: Don't access this variable directly, always go through
// SetTargetBitrateKbps or GetTargetBitrateKbps. Also remember

View File

@ -15,8 +15,9 @@ namespace webrtc {
namespace test {
CallTest::CallTest()
: send_stream_(NULL),
fake_encoder_(Clock::GetRealTimeClock()) {
: clock_(Clock::GetRealTimeClock()),
send_stream_(NULL),
fake_encoder_(clock_) {
}
CallTest::~CallTest() {
}
@ -121,7 +122,7 @@ void CallTest::CreateFrameGeneratorCapturer() {
stream.width,
stream.height,
stream.max_framerate,
Clock::GetRealTimeClock()));
clock_));
}
void CallTest::CreateStreams() {
assert(send_stream_ == NULL);
@ -150,7 +151,8 @@ const unsigned int CallTest::kLongTimeoutMs = 120 * 1000;
const uint8_t CallTest::kSendPayloadType = 100;
const uint8_t CallTest::kFakeSendPayloadType = 125;
const uint8_t CallTest::kSendRtxPayloadType = 98;
const uint32_t CallTest::kSendRtxSsrc = 0xBADCAFE;
const uint32_t CallTest::kSendRtxSsrcs[kNumSsrcs] = {0xBADCAFD, 0xBADCAFE,
0xBADCAFF};
const uint32_t CallTest::kSendSsrcs[kNumSsrcs] = {0xC0FFED, 0xC0FFEE, 0xC0FFEF};
const uint32_t CallTest::kReceiverLocalSsrc = 0x123456;
const int CallTest::kNackRtpHistoryMs = 1000;

View File

@ -35,7 +35,7 @@ class CallTest : public ::testing::Test {
static const uint8_t kSendPayloadType;
static const uint8_t kSendRtxPayloadType;
static const uint8_t kFakeSendPayloadType;
static const uint32_t kSendRtxSsrc;
static const uint32_t kSendRtxSsrcs[kNumSsrcs];
static const uint32_t kSendSsrcs[kNumSsrcs];
static const uint32_t kReceiverLocalSsrc;
static const int kNackRtpHistoryMs;
@ -58,6 +58,8 @@ class CallTest : public ::testing::Test {
void Stop();
void DestroyStreams();
Clock* const clock_;
scoped_ptr<Call> sender_call_;
VideoSendStream::Config send_config_;
std::vector<VideoStream> video_streams_;

View File

@ -106,6 +106,8 @@ class Call : public webrtc::Call, public PacketReceiver {
scoped_ptr<CpuOveruseObserverProxy> overuse_observer_proxy_;
VideoSendStream::RtpStateMap suspended_send_ssrcs_;
VideoEngine* video_engine_;
ViERTP_RTCP* rtp_rtcp_;
ViECodec* codec_;
@ -184,6 +186,7 @@ VideoSendStream* Call::CreateVideoSendStream(
config,
video_streams,
encoder_settings,
suspended_send_ssrcs_,
base_channel_id_,
config_.start_bitrate_bps != -1 ? config_.start_bitrate_bps
: kDefaultVideoStreamBitrateBps);
@ -199,21 +202,30 @@ VideoSendStream* Call::CreateVideoSendStream(
void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
assert(send_stream != NULL);
send_stream->Stop();
VideoSendStream* send_stream_impl = NULL;
{
WriteLockScoped write_lock(*send_lock_);
for (std::map<uint32_t, VideoSendStream*>::iterator it =
send_ssrcs_.begin();
it != send_ssrcs_.end();
++it) {
std::map<uint32_t, VideoSendStream*>::iterator it = send_ssrcs_.begin();
while (it != send_ssrcs_.end()) {
if (it->second == static_cast<VideoSendStream*>(send_stream)) {
send_stream_impl = it->second;
send_ssrcs_.erase(it);
break;
send_ssrcs_.erase(it++);
} else {
++it;
}
}
}
VideoSendStream::RtpStateMap rtp_state = send_stream_impl->GetRtpStates();
for (VideoSendStream::RtpStateMap::iterator it = rtp_state.begin();
it != rtp_state.end();
++it) {
suspended_send_ssrcs_[it->first] = it->second;
}
assert(send_stream_impl != NULL);
delete send_stream_impl;
}

View File

@ -58,6 +58,7 @@ class EndToEndTest : public test::CallTest {
void RespectsRtcpMode(newapi::RtcpMode rtcp_mode);
void TestXrReceiverReferenceTimeReport(bool enable_rrtr);
void TestSendsSetSsrcs(size_t num_ssrcs, bool send_single_ssrc_first);
void TestRtpStatePreservation(bool use_rtx);
};
TEST_F(EndToEndTest, ReceiverCanBeStartedTwice) {
@ -434,7 +435,7 @@ void EndToEndTest::DecodesRetransmittedFrame(bool retransmit_over_rtx) {
public:
explicit RetransmissionObserver(bool expect_rtx)
: EndToEndTest(kDefaultTimeoutMs),
retransmission_ssrc_(expect_rtx ? kSendRtxSsrc : kSendSsrcs[0]),
retransmission_ssrc_(expect_rtx ? kSendRtxSsrcs[0] : kSendSsrcs[0]),
retransmission_payload_type_(expect_rtx ? kSendRtxPayloadType
: kFakeSendPayloadType),
marker_bits_observed_(0),
@ -481,10 +482,11 @@ void EndToEndTest::DecodesRetransmittedFrame(bool retransmit_over_rtx) {
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
(*receive_configs)[0].pre_render_callback = this;
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
if (retransmission_ssrc_ == kSendRtxSsrc) {
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrc);
if (retransmission_ssrc_ == kSendRtxSsrcs[0]) {
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
(*receive_configs)[0].rtp.rtx[kSendRtxPayloadType].ssrc = kSendRtxSsrc;
(*receive_configs)[0].rtp.rtx[kSendRtxPayloadType].ssrc =
kSendRtxSsrcs[0];
(*receive_configs)[0].rtp.rtx[kSendRtxPayloadType].payload_type =
kSendRtxPayloadType;
}
@ -1543,9 +1545,6 @@ TEST_F(EndToEndTest, CanSwitchToUseAllSsrcs) {
}
TEST_F(EndToEndTest, RedundantPayloadsTransmittedOnAllSsrcs) {
// TODO(pbos): Use CallTest::kSendRtxSsrcs when they're an array (pending CL).
static const uint32_t kSendRtxSsrcs[kNumSsrcs] = {
0xBADCAFD, 0xBADCAFE, 0xBADCAFF};
class ObserveRedundantPayloads: public test::EndToEndTest {
public:
ObserveRedundantPayloads()
@ -1618,4 +1617,178 @@ TEST_F(EndToEndTest, RedundantPayloadsTransmittedOnAllSsrcs) {
RunBaseTest(&test);
}
void EndToEndTest::TestRtpStatePreservation(bool use_rtx) {
static const uint32_t kMaxSequenceNumberGap = 100;
static const uint64_t kMaxTimestampGap = kDefaultTimeoutMs * 90;
class RtpSequenceObserver : public test::RtpRtcpObserver {
public:
RtpSequenceObserver(bool use_rtx)
: test::RtpRtcpObserver(kDefaultTimeoutMs),
crit_(CriticalSectionWrapper::CreateCriticalSection()),
ssrcs_to_observe_(kNumSsrcs) {
for (size_t i = 0; i < kNumSsrcs; ++i) {
configured_ssrcs_[kSendSsrcs[i]] = true;
if (use_rtx)
configured_ssrcs_[kSendRtxSsrcs[i]] = true;
}
}
void ResetExpectedSsrcs(size_t num_expected_ssrcs) {
CriticalSectionScoped lock(crit_.get());
ssrc_observed_.clear();
ssrcs_to_observe_ = num_expected_ssrcs;
}
private:
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
RTPHeader header;
EXPECT_TRUE(parser_->Parse(packet, static_cast<int>(length), &header));
const uint32_t ssrc = header.ssrc;
const uint16_t sequence_number = header.sequenceNumber;
const uint32_t timestamp = header.timestamp;
const bool only_padding =
static_cast<size_t>(header.headerLength + header.paddingLength) ==
length;
EXPECT_TRUE(configured_ssrcs_[ssrc])
<< "Received SSRC that wasn't configured: " << ssrc;
std::map<uint32_t, uint16_t>::iterator it =
last_observed_sequence_number_.find(header.ssrc);
if (it == last_observed_sequence_number_.end()) {
last_observed_sequence_number_[ssrc] = sequence_number;
last_observed_timestamp_[ssrc] = timestamp;
} else {
// Verify sequence numbers are reasonably close.
uint32_t extended_sequence_number = sequence_number;
// Check for roll-over.
if (sequence_number < last_observed_sequence_number_[ssrc])
extended_sequence_number += 0xFFFFu + 1;
EXPECT_LE(
extended_sequence_number - last_observed_sequence_number_[ssrc],
kMaxSequenceNumberGap)
<< "Gap in sequence numbers ("
<< last_observed_sequence_number_[ssrc] << " -> " << sequence_number
<< ") too large for SSRC: " << ssrc << ".";
last_observed_sequence_number_[ssrc] = sequence_number;
// TODO(pbos): Remove this check if we ever have monotonically
// increasing timestamps. Right now padding packets add a delta which
// can cause reordering between padding packets and regular packets,
// hence we drop padding-only packets to not flake.
if (only_padding) {
// Verify that timestamps are reasonably close.
uint64_t extended_timestamp = timestamp;
// Check for roll-over.
if (timestamp < last_observed_timestamp_[ssrc])
extended_timestamp += static_cast<uint64_t>(0xFFFFFFFFu) + 1;
EXPECT_LE(extended_timestamp - last_observed_timestamp_[ssrc],
kMaxTimestampGap)
<< "Gap in timestamps (" << last_observed_timestamp_[ssrc]
<< " -> " << timestamp << ") too large for SSRC: " << ssrc << ".";
}
last_observed_timestamp_[ssrc] = timestamp;
}
CriticalSectionScoped lock(crit_.get());
// Wait for media packets on all ssrcs.
if (!ssrc_observed_[ssrc] && !only_padding) {
ssrc_observed_[ssrc] = true;
if (--ssrcs_to_observe_ == 0)
observation_complete_->Set();
}
return SEND_PACKET;
}
std::map<uint32_t, uint16_t> last_observed_sequence_number_;
std::map<uint32_t, uint32_t> last_observed_timestamp_;
std::map<uint32_t, bool> configured_ssrcs_;
scoped_ptr<CriticalSectionWrapper> crit_;
size_t ssrcs_to_observe_ GUARDED_BY(crit_);
std::map<uint32_t, bool> ssrc_observed_ GUARDED_BY(crit_);
} observer(use_rtx);
CreateCalls(Call::Config(observer.SendTransport()),
Call::Config(observer.ReceiveTransport()));
observer.SetReceivers(sender_call_->Receiver(), NULL);
CreateSendConfig(kNumSsrcs);
if (use_rtx) {
for (size_t i = 0; i < kNumSsrcs; ++i) {
send_config_.rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[i]);
}
send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
}
// Lower bitrates so that all streams send initially.
for (size_t i = 0; i < video_streams_.size(); ++i) {
video_streams_[i].min_bitrate_bps = 10000;
video_streams_[i].target_bitrate_bps = 15000;
video_streams_[i].max_bitrate_bps = 20000;
}
CreateMatchingReceiveConfigs();
CreateStreams();
CreateFrameGeneratorCapturer();
Start();
EXPECT_EQ(kEventSignaled, observer.Wait())
<< "Timed out waiting for all SSRCs to send packets.";
// Test stream resetting more than once to make sure that the state doesn't
// get set once (this could be due to using std::map::insert for instance).
for (size_t i = 0; i < 3; ++i) {
frame_generator_capturer_->Stop();
sender_call_->DestroyVideoSendStream(send_stream_);
// Re-create VideoSendStream with only one stream.
std::vector<VideoStream> one_stream = video_streams_;
one_stream.resize(1);
send_stream_ =
sender_call_->CreateVideoSendStream(send_config_, one_stream, NULL);
send_stream_->Start();
CreateFrameGeneratorCapturer();
frame_generator_capturer_->Start();
observer.ResetExpectedSsrcs(1);
EXPECT_EQ(kEventSignaled, observer.Wait())
<< "Timed out waiting for single RTP packet.";
// Reconfigure back to use all streams.
send_stream_->ReconfigureVideoEncoder(video_streams_, NULL);
observer.ResetExpectedSsrcs(kNumSsrcs);
EXPECT_EQ(kEventSignaled, observer.Wait())
<< "Timed out waiting for all SSRCs to send packets.";
// Reconfigure down to one stream.
send_stream_->ReconfigureVideoEncoder(one_stream, NULL);
observer.ResetExpectedSsrcs(1);
EXPECT_EQ(kEventSignaled, observer.Wait())
<< "Timed out waiting for single RTP packet.";
// Reconfigure back to use all streams.
send_stream_->ReconfigureVideoEncoder(video_streams_, NULL);
observer.ResetExpectedSsrcs(kNumSsrcs);
EXPECT_EQ(kEventSignaled, observer.Wait())
<< "Timed out waiting for all SSRCs to send packets.";
}
observer.StopSending();
Stop();
DestroyStreams();
}
TEST_F(EndToEndTest, RestartingSendStreamPreservesRtpState) {
TestRtpStatePreservation(false);
}
TEST_F(EndToEndTest, RestartingSendStreamPreservesRtpStatesWithRtx) {
TestRtpStatePreservation(true);
}
} // namespace webrtc

View File

@ -108,18 +108,21 @@ std::string VideoSendStream::Config::ToString() const {
}
namespace internal {
VideoSendStream::VideoSendStream(newapi::Transport* transport,
CpuOveruseObserver* overuse_observer,
webrtc::VideoEngine* video_engine,
const VideoSendStream::Config& config,
const std::vector<VideoStream> video_streams,
const void* encoder_settings,
int base_channel,
int start_bitrate_bps)
VideoSendStream::VideoSendStream(
newapi::Transport* transport,
CpuOveruseObserver* overuse_observer,
webrtc::VideoEngine* video_engine,
const VideoSendStream::Config& config,
const std::vector<VideoStream> video_streams,
const void* encoder_settings,
const std::map<uint32_t, RtpState>& suspended_ssrcs,
int base_channel,
int start_bitrate_bps)
: transport_adapter_(transport),
encoded_frame_proxy_(config.post_encode_callback),
config_(config),
start_bitrate_bps_(start_bitrate_bps),
suspended_ssrcs_(suspended_ssrcs),
external_codec_(NULL),
channel_(-1),
stats_proxy_(new SendStatisticsProxy(config, this)) {
@ -403,6 +406,9 @@ void VideoSendStream::ConfigureSsrcs() {
uint32_t ssrc = config_.rtp.ssrcs[i];
rtp_rtcp_->SetLocalSSRC(
channel_, ssrc, kViEStreamTypeNormal, static_cast<unsigned char>(i));
RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
if (it != suspended_ssrcs_.end())
rtp_rtcp_->SetRtpStateForSsrc(channel_, ssrc, it->second);
}
if (config_.rtp.rtx.ssrcs.empty()) {
@ -412,11 +418,15 @@ void VideoSendStream::ConfigureSsrcs() {
// Set up RTX.
assert(config_.rtp.rtx.ssrcs.size() == config_.rtp.ssrcs.size());
for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
rtp_rtcp_->SetLocalSSRC(channel_,
config_.rtp.rtx.ssrcs[i],
kViEStreamTypeRtx,
static_cast<unsigned char>(i));
RtpStateMap::iterator it = suspended_ssrcs_.find(ssrc);
if (it != suspended_ssrcs_.end())
rtp_rtcp_->SetRtpStateForSsrc(channel_, ssrc, it->second);
}
if (config_.rtp.rtx.pad_with_redundant_payloads) {
@ -427,5 +437,20 @@ void VideoSendStream::ConfigureSsrcs() {
rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type);
}
std::map<uint32_t, RtpState> VideoSendStream::GetRtpStates() const {
std::map<uint32_t, RtpState> rtp_states;
for (size_t i = 0; i < config_.rtp.ssrcs.size(); ++i) {
uint32_t ssrc = config_.rtp.ssrcs[i];
rtp_states[ssrc] = rtp_rtcp_->GetRtpStateForSsrc(channel_, ssrc);
}
for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
rtp_states[ssrc] = rtp_rtcp_->GetRtpStateForSsrc(channel_, ssrc);
}
return rtp_states;
}
} // namespace internal
} // namespace webrtc

View File

@ -11,7 +11,10 @@
#ifndef WEBRTC_VIDEO_VIDEO_SEND_STREAM_H_
#define WEBRTC_VIDEO_VIDEO_SEND_STREAM_H_
#include <map>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/video/encoded_frame_callback_adapter.h"
#include "webrtc/video/send_statistics_proxy.h"
#include "webrtc/video/transport_adapter.h"
@ -44,6 +47,7 @@ class VideoSendStream : public webrtc::VideoSendStream,
const VideoSendStream::Config& config,
const std::vector<VideoStream> video_streams,
const void* encoder_settings,
const std::map<uint32_t, RtpState>& suspended_ssrcs,
int base_channel,
int start_bitrate);
@ -65,6 +69,9 @@ class VideoSendStream : public webrtc::VideoSendStream,
// From webrtc::VideoSendStream.
virtual VideoSendStreamInput* Input() OVERRIDE;
typedef std::map<uint32_t, RtpState> RtpStateMap;
RtpStateMap GetRtpStates() const;
protected:
// From SendStatisticsProxy::StreamStatsProvider.
virtual bool GetSendSideDelay(VideoSendStream::Stats* stats) OVERRIDE;
@ -76,6 +83,7 @@ class VideoSendStream : public webrtc::VideoSendStream,
EncodedFrameCallbackAdapter encoded_frame_proxy_;
const VideoSendStream::Config config_;
const int start_bitrate_bps_;
std::map<uint32_t, RtpState> suspended_ssrcs_;
ViEBase* video_engine_base_;
ViECapture* capture_;

View File

@ -470,7 +470,7 @@ TEST_F(VideoSendStreamTest, RetransmitsNack) {
TEST_F(VideoSendStreamTest, RetransmitsNackOverRtx) {
// NACKs over RTX should use a separate SSRC.
TestNackRetransmission(kSendRtxSsrc, kSendRtxPayloadType);
TestNackRetransmission(kSendRtxSsrcs[0], kSendRtxPayloadType);
}
void VideoSendStreamTest::TestPacketFragmentationSize(VideoFormat format,

View File

@ -23,6 +23,7 @@
#define WEBRTC_VIDEO_ENGINE_INCLUDE_VIE_RTP_RTCP_H_
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
namespace webrtc {
@ -151,6 +152,17 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP {
virtual int SetStartSequenceNumber(const int video_channel,
unsigned short sequence_number) = 0;
// TODO(pbos): Remove default implementation once this has been implemented
// in libjingle.
virtual void SetRtpStateForSsrc(int video_channel,
uint32_t ssrc,
const RtpState& rtp_state) {}
// TODO(pbos): Remove default implementation once this has been implemented
// in libjingle.
virtual RtpState GetRtpStateForSsrc(int video_channel, uint32_t ssrc) {
return RtpState();
}
// This function sets the RTCP status for the specified channel.
// Default mode is kRtcpCompound_RFC4585.
virtual int SetRTCPStatus(const int video_channel,

View File

@ -893,6 +893,21 @@ int32_t ViEChannel::SetStartSequenceNumber(uint16_t sequence_number) {
return rtp_rtcp_->SetSequenceNumber(sequence_number);
}
void ViEChannel::SetRtpStateForSsrc(uint32_t ssrc, const RtpState& rtp_state) {
assert(!rtp_rtcp_->Sending());
default_rtp_rtcp_->SetRtpStateForSsrc(ssrc, rtp_state);
}
RtpState ViEChannel::GetRtpStateForSsrc(uint32_t ssrc) {
assert(!rtp_rtcp_->Sending());
RtpState rtp_state;
if (!default_rtp_rtcp_->GetRtpStateForSsrc(ssrc, &rtp_state)) {
LOG(LS_ERROR) << "Couldn't get RTP state for ssrc: " << ssrc;
}
return rtp_state;
}
int32_t ViEChannel::SetRTCPCName(const char rtcp_cname[]) {
if (rtp_rtcp_->Sending()) {
return -1;

View File

@ -152,6 +152,9 @@ class ViEChannel
// Sets the starting sequence number, must be called before StartSend.
int32_t SetStartSequenceNumber(uint16_t sequence_number);
void SetRtpStateForSsrc(uint32_t ssrc, const RtpState& rtp_state);
RtpState GetRtpStateForSsrc(uint32_t ssrc);
// Sets the CName for the outgoing stream on the channel.
int32_t SetRTCPCName(const char rtcp_cname[]);

View File

@ -256,6 +256,30 @@ int ViERTP_RTCPImpl::SetStartSequenceNumber(const int video_channel,
return 0;
}
void ViERTP_RTCPImpl::SetRtpStateForSsrc(int video_channel,
uint32_t ssrc,
const RtpState& rtp_state) {
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel)
return;
if (vie_channel->Sending()) {
LOG_F(LS_ERROR) << "channel " << video_channel << " is already sending.";
return;
}
vie_channel->SetRtpStateForSsrc(ssrc, rtp_state);
}
RtpState ViERTP_RTCPImpl::GetRtpStateForSsrc(int video_channel, uint32_t ssrc) {
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel)
return RtpState();
return vie_channel->GetRtpStateForSsrc(ssrc);
}
int ViERTP_RTCPImpl::SetRTCPStatus(const int video_channel,
const ViERTCPMode rtcp_mode) {
LOG_F(LS_INFO) << "channel: " << video_channel

View File

@ -46,6 +46,11 @@ class ViERTP_RTCPImpl
const uint8_t payload_type);
virtual int SetStartSequenceNumber(const int video_channel,
uint16_t sequence_number);
virtual void SetRtpStateForSsrc(int video_channel,
uint32_t ssrc,
const RtpState& rtp_state) OVERRIDE;
virtual RtpState GetRtpStateForSsrc(int video_channel,
uint32_t ssrc) OVERRIDE;
virtual int SetRTCPStatus(const int video_channel,
const ViERTCPMode rtcp_mode);
virtual int GetRTCPStatus(const int video_channel,

View File

@ -11,6 +11,7 @@
#include "webrtc/video_engine/vie_sender.h"
#include <assert.h>
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
#include "webrtc/modules/utility/interface/rtp_dump.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"