diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h index 95c565f01..da82b65e1 100644 --- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h @@ -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 */ diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h index 6f99f938d..e1bec5fc8 100644 --- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h +++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h @@ -192,6 +192,20 @@ struct RtcpReceiveTimeInfo { typedef std::list 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: diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h index 03156c79d..fe20c6a36 100644 --- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -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, diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc index 896bd5f4d..b38ae1f0d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -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; } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 70fe71743..aff423425 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -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(); } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h index 55826b6fe..c1694078c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -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. diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index c0383934f..919eb029c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -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 diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index 291e619b4..78d3a2a8a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -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 statistics_crit_; - SendDelayMap send_delays_; - std::map 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 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 diff --git a/webrtc/test/call_test.cc b/webrtc/test/call_test.cc index ec2f815fb..16dad7191 100644 --- a/webrtc/test/call_test.cc +++ b/webrtc/test/call_test.cc @@ -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; diff --git a/webrtc/test/call_test.h b/webrtc/test/call_test.h index 37a883d68..e24d83593 100644 --- a/webrtc/test/call_test.h +++ b/webrtc/test/call_test.h @@ -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 sender_call_; VideoSendStream::Config send_config_; std::vector video_streams_; diff --git a/webrtc/video/call.cc b/webrtc/video/call.cc index 0e153e91e..2ae0ae564 100644 --- a/webrtc/video/call.cc +++ b/webrtc/video/call.cc @@ -106,6 +106,8 @@ class Call : public webrtc::Call, public PacketReceiver { scoped_ptr 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::iterator it = - send_ssrcs_.begin(); - it != send_ssrcs_.end(); - ++it) { + std::map::iterator it = send_ssrcs_.begin(); + while (it != send_ssrcs_.end()) { if (it->second == static_cast(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; } diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc index 71db199f2..748eb7152 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc @@ -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(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(header.headerLength + header.paddingLength) == + length; + + EXPECT_TRUE(configured_ssrcs_[ssrc]) + << "Received SSRC that wasn't configured: " << ssrc; + + std::map::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(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 last_observed_sequence_number_; + std::map last_observed_timestamp_; + std::map configured_ssrcs_; + + scoped_ptr crit_; + size_t ssrcs_to_observe_ GUARDED_BY(crit_); + std::map 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 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 diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index 4d32ab401..ff3fe5081 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -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 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 video_streams, + const void* encoder_settings, + const std::map& 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(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(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 VideoSendStream::GetRtpStates() const { + std::map 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 diff --git a/webrtc/video/video_send_stream.h b/webrtc/video/video_send_stream.h index df65b74ef..e17706248 100644 --- a/webrtc/video/video_send_stream.h +++ b/webrtc/video/video_send_stream.h @@ -11,7 +11,10 @@ #ifndef WEBRTC_VIDEO_VIDEO_SEND_STREAM_H_ #define WEBRTC_VIDEO_VIDEO_SEND_STREAM_H_ +#include + #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 video_streams, const void* encoder_settings, + const std::map& 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 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 suspended_ssrcs_; ViEBase* video_engine_base_; ViECapture* capture_; diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc index b1197ef64..513bed2c4 100644 --- a/webrtc/video/video_send_stream_tests.cc +++ b/webrtc/video/video_send_stream_tests.cc @@ -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, diff --git a/webrtc/video_engine/include/vie_rtp_rtcp.h b/webrtc/video_engine/include/vie_rtp_rtcp.h index e71585167..3a565610e 100644 --- a/webrtc/video_engine/include/vie_rtp_rtcp.h +++ b/webrtc/video_engine/include/vie_rtp_rtcp.h @@ -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, diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index 3031376da..5eb36076c 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -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; diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h index c76d1298e..0ec504370 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -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[]); diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc index 53610b4a3..04f5e9b0e 100644 --- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc +++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc @@ -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 diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.h b/webrtc/video_engine/vie_rtp_rtcp_impl.h index 5eec0efe1..4afe1c584 100644 --- a/webrtc/video_engine/vie_rtp_rtcp_impl.h +++ b/webrtc/video_engine/vie_rtp_rtcp_impl.h @@ -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, diff --git a/webrtc/video_engine/vie_sender.cc b/webrtc/video_engine/vie_sender.cc index 349bc72fb..28bf39033 100644 --- a/webrtc/video_engine/vie_sender.cc +++ b/webrtc/video_engine/vie_sender.cc @@ -11,6 +11,7 @@ #include "webrtc/video_engine/vie_sender.h" #include +#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"