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/webrtc@6612 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/rtp_rtcp/interface/rtp_rtcp.h b/modules/rtp_rtcp/interface/rtp_rtcp.h
index 95c565f..da82b65 100644
--- a/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -203,6 +203,10 @@
     */
     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/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
index 6f99f93..e1bec5f 100644
--- a/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
+++ b/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
@@ -192,6 +192,20 @@
 
 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:
diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 03156c7..fe20c6a 100644
--- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -74,6 +74,9 @@
       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/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc
index 896bd5f..b38ae1f 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -1361,8 +1361,6 @@
 void RTCPReceiver::RegisterRtcpStatisticsCallback(
     RtcpStatisticsCallback* callback) {
   CriticalSectionScoped cs(_criticalSectionFeedbacks);
-  if (callback != NULL)
-    assert(stats_callback_ == NULL);
   stats_callback_ = callback;
 }
 
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 70fe717..aff4234 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -333,6 +333,42 @@
   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/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 55826b6..c169407 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -73,6 +73,10 @@
   // 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/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index c038393..919eb02 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -74,8 +74,8 @@
       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 @@
 }
 
 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 @@
   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 @@
     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 @@
   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 @@
     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 @@
         ++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 @@
     }
   }
 
+  CriticalSectionScoped lock(send_critsect_);
   return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
                               (rtx_ & kRtxRetransmitted) > 0, true) ?
       length : -1;
@@ -784,8 +794,15 @@
   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 @@
                                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 payload_type;
   int64_t capture_time_ms;
   uint32_t timestamp;
+  int rtx;
   {
     CriticalSectionScoped cs(send_critsect_);
     if (!sending_media_) {
@@ -889,8 +906,11 @@
       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 @@
                                    bytes,
                                    kDontStore,
                                    true,
-                                   rtx_ == kRtxOff);
+                                   rtx == kRtxOff);
     bytes_sent += padding_sent;
   }
   return bytes_sent;
@@ -975,6 +995,7 @@
 }
 
 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 @@
 }
 
 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 @@
   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 @@
     // 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 @@
 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 @@
 }
 
 void RTPSender::SetCSRCStatus(const bool include) {
+  CriticalSectionScoped lock(send_critsect_);
   include_csrcs_ = include;
 }
 
@@ -1635,8 +1667,6 @@
 
 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 @@
 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 @@
 
 void RTPSender::RegisterBitrateObserver(BitrateStatisticsObserver* observer) {
   CriticalSectionScoped cs(statistics_crit_.get());
-  if (observer != NULL)
-    assert(bitrate_callback_ == NULL);
   bitrate_callback_ = observer;
 }
 
@@ -1673,9 +1699,53 @@
 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/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
index 291e619..78d3a2a 100644
--- a/modules/rtp_rtcp/source/rtp_sender.h
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -43,12 +43,13 @@
   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 @@
   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 @@
 
   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 @@
 
   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 @@
 
   // 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
diff --git a/test/call_test.cc b/test/call_test.cc
index ec2f815..16dad71 100644
--- a/test/call_test.cc
+++ b/test/call_test.cc
@@ -15,8 +15,9 @@
 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 @@
                                            stream.width,
                                            stream.height,
                                            stream.max_framerate,
-                                           Clock::GetRealTimeClock()));
+                                           clock_));
 }
 void CallTest::CreateStreams() {
   assert(send_stream_ == NULL);
@@ -150,7 +151,8 @@
 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/test/call_test.h b/test/call_test.h
index 37a883d..e24d835 100644
--- a/test/call_test.h
+++ b/test/call_test.h
@@ -35,7 +35,7 @@
   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 @@
   void Stop();
   void DestroyStreams();
 
+  Clock* const clock_;
+
   scoped_ptr<Call> sender_call_;
   VideoSendStream::Config send_config_;
   std::vector<VideoStream> video_streams_;
diff --git a/video/call.cc b/video/call.cc
index 0e153e9..2ae0ae5 100644
--- a/video/call.cc
+++ b/video/call.cc
@@ -106,6 +106,8 @@
 
   scoped_ptr<CpuOveruseObserverProxy> overuse_observer_proxy_;
 
+  VideoSendStream::RtpStateMap suspended_send_ssrcs_;
+
   VideoEngine* video_engine_;
   ViERTP_RTCP* rtp_rtcp_;
   ViECodec* codec_;
@@ -184,6 +186,7 @@
       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 @@
 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;
 }
diff --git a/video/end_to_end_tests.cc b/video/end_to_end_tests.cc
index 71db199..748eb71 100644
--- a/video/end_to_end_tests.cc
+++ b/video/end_to_end_tests.cc
@@ -58,6 +58,7 @@
   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 @@
    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 @@
       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, 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 @@
   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
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index 4d32ab4..ff3fe50 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -108,18 +108,21 @@
 }
 
 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 @@
     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 @@
 
   // 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 @@
   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
diff --git a/video/video_send_stream.h b/video/video_send_stream.h
index df65b74..e177062 100644
--- a/video/video_send_stream.h
+++ b/video/video_send_stream.h
@@ -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 @@
                   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 @@
   // 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 @@
   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_;
diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc
index b1197ef..513bed2 100644
--- a/video/video_send_stream_tests.cc
+++ b/video/video_send_stream_tests.cc
@@ -470,7 +470,7 @@
 
 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/video_engine/include/vie_rtp_rtcp.h b/video_engine/include/vie_rtp_rtcp.h
index e715851..3a56561 100644
--- a/video_engine/include/vie_rtp_rtcp.h
+++ b/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 @@
   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/video_engine/vie_channel.cc b/video_engine/vie_channel.cc
index 3031376..5eb3607 100644
--- a/video_engine/vie_channel.cc
+++ b/video_engine/vie_channel.cc
@@ -893,6 +893,21 @@
   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/video_engine/vie_channel.h b/video_engine/vie_channel.h
index c76d129..0ec5043 100644
--- a/video_engine/vie_channel.h
+++ b/video_engine/vie_channel.h
@@ -152,6 +152,9 @@
   // 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/video_engine/vie_rtp_rtcp_impl.cc b/video_engine/vie_rtp_rtcp_impl.cc
index 53610b4..04f5e9b 100644
--- a/video_engine/vie_rtp_rtcp_impl.cc
+++ b/video_engine/vie_rtp_rtcp_impl.cc
@@ -256,6 +256,30 @@
   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/video_engine/vie_rtp_rtcp_impl.h b/video_engine/vie_rtp_rtcp_impl.h
index 5eec0ef..4afe1c5 100644
--- a/video_engine/vie_rtp_rtcp_impl.h
+++ b/video_engine/vie_rtp_rtcp_impl.h
@@ -46,6 +46,11 @@
                                        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/video_engine/vie_sender.cc b/video_engine/vie_sender.cc
index 349bc72..28bf390 100644
--- a/video_engine/vie_sender.cc
+++ b/video_engine/vie_sender.cc
@@ -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"