Revert r5294 to re-roll r5293.

To fix races in test each stream now owns its own encoder/decoder.

R=mflodman@webrtc.org
BUG=

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5297 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index bcdb5e8..3d47b86 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -69,27 +69,28 @@
 
 enum TraceModule
 {
-    kTraceUndefined          = 0,
+    kTraceUndefined              = 0,
     // not a module, triggered from the engine code
-    kTraceVoice              = 0x0001,
+    kTraceVoice                  = 0x0001,
     // not a module, triggered from the engine code
-    kTraceVideo              = 0x0002,
+    kTraceVideo                  = 0x0002,
     // not a module, triggered from the utility code
-    kTraceUtility            = 0x0003,
-    kTraceRtpRtcp            = 0x0004,
-    kTraceTransport          = 0x0005,
-    kTraceSrtp               = 0x0006,
-    kTraceAudioCoding        = 0x0007,
-    kTraceAudioMixerServer   = 0x0008,
-    kTraceAudioMixerClient   = 0x0009,
-    kTraceFile               = 0x000a,
-    kTraceAudioProcessing    = 0x000b,
-    kTraceVideoCoding        = 0x0010,
-    kTraceVideoMixer         = 0x0011,
-    kTraceAudioDevice        = 0x0012,
-    kTraceVideoRenderer      = 0x0014,
-    kTraceVideoCapture       = 0x0015,
-    kTraceVideoPreocessing   = 0x0016
+    kTraceUtility                = 0x0003,
+    kTraceRtpRtcp                = 0x0004,
+    kTraceTransport              = 0x0005,
+    kTraceSrtp                   = 0x0006,
+    kTraceAudioCoding            = 0x0007,
+    kTraceAudioMixerServer       = 0x0008,
+    kTraceAudioMixerClient       = 0x0009,
+    kTraceFile                   = 0x000a,
+    kTraceAudioProcessing        = 0x000b,
+    kTraceVideoCoding            = 0x0010,
+    kTraceVideoMixer             = 0x0011,
+    kTraceAudioDevice            = 0x0012,
+    kTraceVideoRenderer          = 0x0014,
+    kTraceVideoCapture           = 0x0015,
+    kTraceVideoPreocessing       = 0x0016,
+    kTraceRemoteBitrateEstimator = 0x0017,
 };
 
 enum TraceLevel
diff --git a/webrtc/modules/interface/module_common_types.h b/webrtc/modules/interface/module_common_types.h
index 67c6cb4..2494d68 100644
--- a/webrtc/modules/interface/module_common_types.h
+++ b/webrtc/modules/interface/module_common_types.h
@@ -28,7 +28,9 @@
 namespace webrtc {
 
 struct RTPHeaderExtension {
+  bool hasTransmissionTimeOffset;
   int32_t transmissionTimeOffset;
+  bool hasAbsoluteSendTime;
   uint32_t absoluteSendTime;
 };
 
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
index 69b35c5..a544ee5d 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
@@ -17,6 +17,7 @@
 #include "webrtc/system_wrappers/interface/clock.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/system_wrappers/interface/trace.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
@@ -225,6 +226,8 @@
     RemoteBitrateObserver* observer,
     Clock* clock,
     uint32_t min_bitrate_bps) const {
+  WEBRTC_TRACE(kTraceStateInfo, kTraceRemoteBitrateEstimator, -1,
+      "RemoteBitrateEstimatorFactory: Instantiating.");
   return new RemoteBitrateEstimatorSingleStream(observer, clock,
                                                 min_bitrate_bps);
 }
@@ -233,6 +236,8 @@
     RemoteBitrateObserver* observer,
     Clock* clock,
     uint32_t min_bitrate_bps) const {
+  WEBRTC_TRACE(kTraceStateInfo, kTraceRemoteBitrateEstimator, -1,
+      "AbsoluteSendTimeRemoteBitrateEstimatorFactory: Instantiating.");
   return new RemoteBitrateEstimatorSingleStream(observer, clock,
                                                 min_bitrate_bps);
 }
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_utility.cc b/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
index f50b20a..102ebec 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
@@ -391,9 +391,11 @@
 
   // If in effect, MAY be omitted for those packets for which the offset
   // is zero.
+  header.extension.hasTransmissionTimeOffset = false;
   header.extension.transmissionTimeOffset = 0;
 
   // May not be present in packet.
+  header.extension.hasAbsoluteSendTime = false;
   header.extension.absoluteSendTime = 0;
 
   if (X) {
@@ -490,6 +492,7 @@
           // Negative offset, correct sign for Word24 to Word32.
           header.extension.transmissionTimeOffset |= 0xFF000000;
         }
+        header.extension.hasTransmissionTimeOffset = true;
         break;
       }
       case kRtpExtensionAudioLevel: {
@@ -524,6 +527,7 @@
         absoluteSendTime += *ptr++ << 8;
         absoluteSendTime += *ptr++;
         header.extension.absoluteSendTime = absoluteSendTime;
+        header.extension.hasAbsoluteSendTime = true;
         break;
       }
       default: {
diff --git a/webrtc/system_wrappers/source/trace_impl.cc b/webrtc/system_wrappers/source/trace_impl.cc
index 4d30bca..8dbe76b 100644
--- a/webrtc/system_wrappers/source/trace_impl.cc
+++ b/webrtc/system_wrappers/source/trace_impl.cc
@@ -273,6 +273,10 @@
         sprintf(trace_message, "  VIDEO PROC:%5ld %5ld;", id_engine,
                 id_channel);
         break;
+      case kTraceRemoteBitrateEstimator:
+        sprintf(trace_message, "     BWE RBE:%5ld %5ld;", id_engine,
+                id_channel);
+        break;
     }
   } else {
     switch (module) {
@@ -332,6 +336,9 @@
       case kTraceVideoPreocessing:
         sprintf(trace_message, "  VIDEO PROC:%11ld;", idl);
         break;
+      case kTraceRemoteBitrateEstimator:
+        sprintf(trace_message, "     BWE RBE:%11ld;", idl);
+        break;
     }
   }
   return kMessageLength;
diff --git a/webrtc/video/bitrate_estimator_tests.cc b/webrtc/video/bitrate_estimator_tests.cc
new file mode 100644
index 0000000..15bacd3
--- /dev/null
+++ b/webrtc/video/bitrate_estimator_tests.cc
@@ -0,0 +1,287 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include <functional>
+#include <list>
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/call.h"
+#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/interface/event_wrapper.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/test/direct_transport.h"
+#include "webrtc/test/fake_decoder.h"
+#include "webrtc/test/fake_encoder.h"
+#include "webrtc/test/frame_generator_capturer.h"
+
+namespace webrtc {
+
+static const int kTOFExtensionId = 4;
+static const int kASTExtensionId = 5;
+
+static unsigned int kDefaultTimeoutMs = 30 * 1000;
+static const uint32_t kSendSsrc = 0x654321;
+static const uint32_t kReceiverLocalSsrc = 0x123456;
+static const uint8_t kSendPayloadType = 125;
+
+class BitrateEstimatorTest : public ::testing::Test {
+ public:
+  BitrateEstimatorTest()
+      : receiver_trace_(),
+        send_transport_(),
+        receive_transport_(),
+        sender_call_(),
+        receiver_call_(),
+        send_config_(),
+        receive_config_(),
+        streams_() {
+  }
+
+  virtual ~BitrateEstimatorTest() {
+    EXPECT_TRUE(streams_.empty());
+  }
+
+  virtual void SetUp() {
+    // Create receiver call first so that we are guaranteed to have a trace
+    // callback when sender call is created.
+    Call::Config receiver_call_config(&receive_transport_);
+    receiver_call_config.trace_callback = &receiver_trace_;
+    receiver_call_.reset(Call::Create(receiver_call_config));
+
+    Call::Config sender_call_config(&send_transport_);
+    sender_call_.reset(Call::Create(sender_call_config));
+
+    send_transport_.SetReceiver(receiver_call_->Receiver());
+    receive_transport_.SetReceiver(sender_call_->Receiver());
+
+    send_config_ = sender_call_->GetDefaultSendConfig();
+    send_config_.rtp.ssrcs.push_back(kSendSsrc);
+    // send_config_.encoder will be set by every stream separately.
+    send_config_.internal_source = false;
+    test::FakeEncoder::SetCodecSettings(&send_config_.codec, 1);
+    send_config_.codec.plType = kSendPayloadType;
+
+    receive_config_ = receiver_call_->GetDefaultReceiveConfig();
+    receive_config_.codecs.clear();
+    receive_config_.codecs.push_back(send_config_.codec);
+    // receive_config_.external_decoders will be set by every stream separately.
+    receive_config_.rtp.remote_ssrc = send_config_.rtp.ssrcs[0];
+    receive_config_.rtp.local_ssrc = kReceiverLocalSsrc;
+    receive_config_.rtp.extensions.push_back(
+        RtpExtension(RtpExtension::kTOffset, kTOFExtensionId));
+    receive_config_.rtp.extensions.push_back(
+        RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId));
+  }
+
+  virtual void TearDown() {
+    std::for_each(streams_.begin(), streams_.end(),
+        std::mem_fun(&Stream::StopSending));
+
+    send_transport_.StopSending();
+    receive_transport_.StopSending();
+
+    while (!streams_.empty()) {
+      delete streams_.back();
+      streams_.pop_back();
+    }
+
+    // The TraceCallback instance MUST outlive Calls, destroy Calls explicitly.
+    receiver_call_.reset();
+  }
+
+ protected:
+  friend class Stream;
+
+  class TraceObserver : public TraceCallback {
+   public:
+    TraceObserver()
+        : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
+          received_log_lines_(),
+          expected_log_lines_(),
+          done_(EventWrapper::Create()) {
+    }
+
+    void PushExpectedLogLine(const std::string& expected_log_line) {
+      CriticalSectionScoped cs(crit_sect_.get());
+      expected_log_lines_.push_back(expected_log_line);
+    }
+
+    virtual void Print(TraceLevel level,
+                       const char* message,
+                       int length) OVERRIDE {
+      CriticalSectionScoped cs(crit_sect_.get());
+      if (!(level & kTraceStateInfo)) {
+        return;
+      }
+      std::string msg(message);
+      if (msg.find("BitrateEstimator") != std::string::npos) {
+        received_log_lines_.push_back(msg);
+      }
+      int num_popped = 0;
+      while (!received_log_lines_.empty() && !expected_log_lines_.empty()) {
+        std::string a = received_log_lines_.front();
+        std::string b = expected_log_lines_.front();
+        received_log_lines_.pop_front();
+        expected_log_lines_.pop_front();
+        num_popped++;
+        EXPECT_TRUE(a.find(b) != std::string::npos);
+      }
+      if (expected_log_lines_.size() <= 0) {
+        if (num_popped > 0) {
+          done_->Set();
+        }
+        return;
+      }
+    }
+
+    EventTypeWrapper Wait() { return done_->Wait(kDefaultTimeoutMs); }
+
+   private:
+    typedef std::list<std::string> Strings;
+    scoped_ptr<CriticalSectionWrapper> crit_sect_;
+    Strings received_log_lines_;
+    Strings expected_log_lines_;
+    scoped_ptr<EventWrapper> done_;
+  };
+
+  class Stream {
+   public:
+    explicit Stream(BitrateEstimatorTest* test)
+        : test_(test),
+          is_sending_receiving_(false),
+          send_stream_(NULL),
+          receive_stream_(NULL),
+          frame_generator_capturer_(),
+          fake_encoder_(Clock::GetRealTimeClock()),
+          fake_decoder_() {
+      test_->send_config_.rtp.ssrcs[0]++;
+      test_->send_config_.encoder = &fake_encoder_;
+      send_stream_ =
+          test_->sender_call_->CreateVideoSendStream(test_->send_config_);
+      frame_generator_capturer_.reset(
+          test::FrameGeneratorCapturer::Create(send_stream_->Input(),
+                                               test_->send_config_.codec.width,
+                                               test_->send_config_.codec.height,
+                                               30,
+                                               Clock::GetRealTimeClock()));
+      send_stream_->StartSending();
+      frame_generator_capturer_->Start();
+
+      ExternalVideoDecoder decoder;
+      decoder.decoder = &fake_decoder_;
+      decoder.payload_type = test_->send_config_.codec.plType;
+      test_->receive_config_.rtp.remote_ssrc = test_->send_config_.rtp.ssrcs[0];
+      test_->receive_config_.rtp.local_ssrc++;
+      test_->receive_config_.external_decoders.push_back(decoder);
+      receive_stream_ = test_->receiver_call_->CreateVideoReceiveStream(
+          test_->receive_config_);
+      receive_stream_->StartReceiving();
+
+      is_sending_receiving_ = true;
+    }
+
+    ~Stream() {
+      frame_generator_capturer_.reset(NULL);
+      test_->sender_call_->DestroyVideoSendStream(send_stream_);
+      send_stream_ = NULL;
+      test_->receiver_call_->DestroyVideoReceiveStream(receive_stream_);
+      receive_stream_ = NULL;
+    }
+
+    void StopSending() {
+      if (is_sending_receiving_) {
+        frame_generator_capturer_->Stop();
+        send_stream_->StopSending();
+        receive_stream_->StopReceiving();
+        is_sending_receiving_ = false;
+      }
+    }
+
+   private:
+    BitrateEstimatorTest* test_;
+    bool is_sending_receiving_;
+    VideoSendStream* send_stream_;
+    VideoReceiveStream* receive_stream_;
+    scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer_;
+    test::FakeEncoder fake_encoder_;
+    test::FakeDecoder fake_decoder_;
+  };
+
+  TraceObserver receiver_trace_;
+  test::DirectTransport send_transport_;
+  test::DirectTransport receive_transport_;
+  scoped_ptr<Call> sender_call_;
+  scoped_ptr<Call> receiver_call_;
+  VideoSendStream::Config send_config_;
+  VideoReceiveStream::Config receive_config_;
+  std::vector<Stream*> streams_;
+};
+
+TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefault) {
+  send_config_.rtp.extensions.push_back(
+      RtpExtension(RtpExtension::kTOffset, kTOFExtensionId));
+  receiver_trace_.PushExpectedLogLine(
+      "RemoteBitrateEstimatorFactory: Instantiating.");
+  receiver_trace_.PushExpectedLogLine(
+      "RemoteBitrateEstimatorFactory: Instantiating.");
+  streams_.push_back(new Stream(this));
+  EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+}
+
+TEST_F(BitrateEstimatorTest, SwitchesToAST) {
+  send_config_.rtp.extensions.push_back(
+      RtpExtension(RtpExtension::kTOffset, kTOFExtensionId));
+  receiver_trace_.PushExpectedLogLine(
+      "RemoteBitrateEstimatorFactory: Instantiating.");
+  receiver_trace_.PushExpectedLogLine(
+      "RemoteBitrateEstimatorFactory: Instantiating.");
+  streams_.push_back(new Stream(this));
+  EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+
+  send_config_.rtp.extensions[0] =
+      RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId);
+  receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE.");
+  receiver_trace_.PushExpectedLogLine(
+      "AbsoluteSendTimeRemoteBitrateEstimatorFactory: Instantiating.");
+  streams_.push_back(new Stream(this));
+  EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+}
+
+TEST_F(BitrateEstimatorTest, SwitchesToASTThenBackToTOF) {
+  send_config_.rtp.extensions.push_back(
+      RtpExtension(RtpExtension::kTOffset, kTOFExtensionId));
+  receiver_trace_.PushExpectedLogLine(
+      "RemoteBitrateEstimatorFactory: Instantiating.");
+  receiver_trace_.PushExpectedLogLine(
+      "RemoteBitrateEstimatorFactory: Instantiating.");
+  streams_.push_back(new Stream(this));
+  EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+
+  send_config_.rtp.extensions[0] =
+      RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId);
+  receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE.");
+  receiver_trace_.PushExpectedLogLine(
+      "AbsoluteSendTimeRemoteBitrateEstimatorFactory: Instantiating.");
+  streams_.push_back(new Stream(this));
+  EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+
+  send_config_.rtp.extensions[0] =
+      RtpExtension(RtpExtension::kTOffset, kTOFExtensionId);
+  receiver_trace_.PushExpectedLogLine(
+      "WrappingBitrateEstimator: Switching to transmission time offset RBE.");
+  receiver_trace_.PushExpectedLogLine(
+      "RemoteBitrateEstimatorFactory: Instantiating.");
+  streams_.push_back(new Stream(this));
+  streams_[0]->StopSending();
+  streams_[1]->StopSending();
+  EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+}
+}  // namespace webrtc
diff --git a/webrtc/video/call_tests.cc b/webrtc/video/call_tests.cc
index 96ad832..2e902a4 100644
--- a/webrtc/video/call_tests.cc
+++ b/webrtc/video/call_tests.cc
@@ -49,7 +49,7 @@
         receive_stream_(NULL),
         fake_encoder_(Clock::GetRealTimeClock()) {}
 
-  ~CallTest() {
+  virtual ~CallTest() {
     EXPECT_EQ(NULL, send_stream_);
     EXPECT_EQ(NULL, receive_stream_);
   }
@@ -861,7 +861,7 @@
 
   sender_transport.StopSending();
   receiver_transport.StopSending();
-}
+};
 
 TEST_F(CallTest, ObserversEncodedFrames) {
   class EncodedFrameTestObserver : public EncodedFrameObserver {
diff --git a/webrtc/video/rampup_tests.cc b/webrtc/video/rampup_tests.cc
index 08676a2..0386bd0 100644
--- a/webrtc/video/rampup_tests.cc
+++ b/webrtc/video/rampup_tests.cc
@@ -36,7 +36,7 @@
 namespace webrtc {
 
 namespace {
-  static const int kTOffsetExtensionId = 7;
+  static const int kAbsoluteSendTimeExtensionId = 7;
   static const int kMaxPacketSize = 1500;
 }
 
@@ -74,8 +74,8 @@
     rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
     rtp_rtcp_->SetREMBStatus(true);
     rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
-    rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
-                                            kTOffsetExtensionId);
+    rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
+                                            kAbsoluteSendTimeExtensionId);
     AbsoluteSendTimeRemoteBitrateEstimatorFactory rbe_factory;
     const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
     remote_bitrate_estimator_.reset(
@@ -220,7 +220,7 @@
                                        kRtxSsrcs + kNumberOfStreams);
     }
     send_config.rtp.extensions.push_back(
-        RtpExtension(RtpExtension::kTOffset, kTOffsetExtensionId));
+        RtpExtension(RtpExtension::kAbsSendTime, kAbsoluteSendTimeExtensionId));
 
     VideoSendStream* send_stream = call->CreateVideoSendStream(send_config);
 
diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc
index 31c8524..8d4dfd6 100644
--- a/webrtc/video/video_receive_stream.cc
+++ b/webrtc/video/video_receive_stream.cc
@@ -63,6 +63,20 @@
   rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.local_ssrc);
   rtp_rtcp_->SetRembStatus(channel_, false, config_.rtp.remb);
 
+  for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
+    const std::string& extension = config_.rtp.extensions[i].name;
+    int id = config_.rtp.extensions[i].id;
+    if (extension == RtpExtension::kTOffset) {
+      if (rtp_rtcp_->SetReceiveTimestampOffsetStatus(channel_, true, id) != 0)
+        abort();
+    } else if (extension == RtpExtension::kAbsSendTime) {
+      if (rtp_rtcp_->SetReceiveAbsoluteSendTimeStatus(channel_, true, id) != 0)
+        abort();
+    } else {
+      abort();  // Unsupported extension.
+    }
+  }
+
   network_ = ViENetwork::GetInterface(video_engine);
   assert(network_ != NULL);
 
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index 713cdb9..e18b346 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -10,8 +10,6 @@
 
 #include "webrtc/video/video_send_stream.h"
 
-#include <string.h>
-
 #include <string>
 #include <vector>
 
diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc
index ae33e81..25f334f 100644
--- a/webrtc/video/video_send_stream_tests.cc
+++ b/webrtc/video/video_send_stream_tests.cc
@@ -190,7 +190,7 @@
   frame_generator_capturer->Stop();
   send_stream_->StopSending();
   call->DestroyVideoSendStream(send_stream_);
-}
+};
 
 TEST_F(VideoSendStreamTest, SendsSetSsrc) { SendsSetSsrcs(1, false); }
 
@@ -249,8 +249,11 @@
       EXPECT_TRUE(
           parser_->Parse(packet, static_cast<int>(length), &header));
 
-      if (header.extension.absoluteSendTime > 0)
-        observation_complete_->Set();
+      EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
+      EXPECT_TRUE(header.extension.hasAbsoluteSendTime);
+      EXPECT_EQ(header.extension.transmissionTimeOffset, 0);
+      EXPECT_GT(header.extension.absoluteSendTime, 0u);
+      observation_complete_->Set();
 
       return SEND_PACKET;
     }
@@ -294,7 +297,10 @@
       EXPECT_TRUE(
           parser_->Parse(packet, static_cast<int>(length), &header));
 
+      EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
+      EXPECT_FALSE(header.extension.hasAbsoluteSendTime);
       EXPECT_GT(header.extension.transmissionTimeOffset, 0);
+      EXPECT_EQ(header.extension.absoluteSendTime, 0u);
       observation_complete_->Set();
 
       return SEND_PACKET;
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index 44b90f4..2305ea7 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -92,7 +92,6 @@
       bandwidth_observer_(bandwidth_observer),
       send_timestamp_extension_id_(kInvalidRtpExtensionId),
       absolute_send_time_extension_id_(kInvalidRtpExtensionId),
-      receive_absolute_send_time_enabled_(false),
       external_transport_(NULL),
       decoder_reset_(true),
       wait_for_key_frame_(false),
@@ -934,14 +933,9 @@
 }
 
 int ViEChannel::SetReceiveAbsoluteSendTimeStatus(bool enable, int id) {
-  receive_absolute_send_time_enabled_ = enable;
   return vie_receiver_.SetReceiveAbsoluteSendTimeStatus(enable, id) ? 0 : -1;
 }
 
-bool ViEChannel::GetReceiveAbsoluteSendTimeStatus() const {
-  return receive_absolute_send_time_enabled_;
-}
-
 void ViEChannel::SetRtcpXrRrtrStatus(bool enable) {
   CriticalSectionScoped cs(rtp_rtcp_cs_.get());
   rtp_rtcp_->SetRtcpXrRrtrStatus(enable);
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index de16731..33bf7bf 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -396,7 +396,6 @@
   scoped_ptr<RtcpBandwidthObserver> bandwidth_observer_;
   int send_timestamp_extension_id_;
   int absolute_send_time_extension_id_;
-  bool receive_absolute_send_time_enabled_;
   bool using_packet_spread_;
 
   Transport* external_transport_;
diff --git a/webrtc/video_engine/vie_channel_group.cc b/webrtc/video_engine/vie_channel_group.cc
index d90d7c2..f079a10 100644
--- a/webrtc/video_engine/vie_channel_group.cc
+++ b/webrtc/video_engine/vie_channel_group.cc
@@ -16,6 +16,7 @@
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
 #include "webrtc/modules/utility/interface/process_thread.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/interface/trace.h"
 #include "webrtc/video_engine/call_stats.h"
 #include "webrtc/video_engine/encoder_state_feedback.h"
 #include "webrtc/video_engine/vie_channel.h"
@@ -25,18 +26,22 @@
 namespace webrtc {
 namespace {
 
+static const uint32_t kTimeOffsetSwitchThreshold = 30;
+
 class WrappingBitrateEstimator : public RemoteBitrateEstimator {
  public:
-  WrappingBitrateEstimator(RemoteBitrateObserver* observer, Clock* clock,
-                           ProcessThread* process_thread)
+  WrappingBitrateEstimator(int engine_id, RemoteBitrateObserver* observer,
+                           Clock* clock, ProcessThread* process_thread)
       : observer_(observer),
         clock_(clock),
         process_thread_(process_thread),
         crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
+        engine_id_(engine_id),
         min_bitrate_bps_(30000),
         rbe_(RemoteBitrateEstimatorFactory().Create(observer_, clock_,
                                                     min_bitrate_bps_)),
-        receive_absolute_send_time_(false) {
+        using_absolute_send_time_(false),
+        packets_since_absolute_send_time_(0) {
     assert(process_thread_ != NULL);
     process_thread_->RegisterModule(rbe_.get());
   }
@@ -44,29 +49,11 @@
     process_thread_->DeRegisterModule(rbe_.get());
   }
 
-  void SetReceiveAbsoluteSendTimeStatus(bool enable) {
-    CriticalSectionScoped cs(crit_sect_.get());
-    if (enable == receive_absolute_send_time_) {
-      return;
-    }
-
-    process_thread_->DeRegisterModule(rbe_.get());
-    if (enable) {
-      rbe_.reset(AbsoluteSendTimeRemoteBitrateEstimatorFactory().Create(
-          observer_, clock_, min_bitrate_bps_));
-    } else {
-      rbe_.reset(RemoteBitrateEstimatorFactory().Create(observer_, clock_,
-                                                        min_bitrate_bps_));
-    }
-    process_thread_->RegisterModule(rbe_.get());
-
-    receive_absolute_send_time_ = enable;
-  }
-
   virtual void IncomingPacket(int64_t arrival_time_ms,
                               int payload_size,
                               const RTPHeader& header) {
     CriticalSectionScoped cs(crit_sect_.get());
+    PickEstimator(header);
     rbe_->IncomingPacket(arrival_time_ms, payload_size, header);
   }
 
@@ -97,25 +84,60 @@
   }
 
  private:
+  // Instantiate RBE for Time Offset or Absolute Send Time extensions.
+  void PickEstimator(const RTPHeader& header) {
+    if (header.extension.hasAbsoluteSendTime) {
+      // If we see AST in header, switch RBE strategy immediately.
+      if (!using_absolute_send_time_) {
+        process_thread_->DeRegisterModule(rbe_.get());
+        WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, ViEId(engine_id_),
+            "WrappingBitrateEstimator: Switching to absolute send time RBE.");
+        rbe_.reset(AbsoluteSendTimeRemoteBitrateEstimatorFactory().Create(
+            observer_, clock_, min_bitrate_bps_));
+        process_thread_->RegisterModule(rbe_.get());
+        using_absolute_send_time_ = true;
+      }
+      packets_since_absolute_send_time_ = 0;
+    } else {
+      // When we don't see AST, wait for a few packets before going back to TOF.
+      if (using_absolute_send_time_) {
+        ++packets_since_absolute_send_time_;
+        if (packets_since_absolute_send_time_ >= kTimeOffsetSwitchThreshold) {
+          process_thread_->DeRegisterModule(rbe_.get());
+          WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, ViEId(engine_id_),
+              "WrappingBitrateEstimator: Switching to transmission time offset "
+              "RBE.");
+          rbe_.reset(RemoteBitrateEstimatorFactory().Create(observer_, clock_,
+              min_bitrate_bps_));
+          process_thread_->RegisterModule(rbe_.get());
+          using_absolute_send_time_ = false;
+        }
+      }
+    }
+  }
+
   RemoteBitrateObserver* observer_;
   Clock* clock_;
   ProcessThread* process_thread_;
   scoped_ptr<CriticalSectionWrapper> crit_sect_;
+  const int engine_id_;
   const uint32_t min_bitrate_bps_;
   scoped_ptr<RemoteBitrateEstimator> rbe_;
-  bool receive_absolute_send_time_;
+  bool using_absolute_send_time_;
+  uint32_t packets_since_absolute_send_time_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(WrappingBitrateEstimator);
 };
 }  // namespace
 
-ChannelGroup::ChannelGroup(ProcessThread* process_thread,
+ChannelGroup::ChannelGroup(int engine_id, ProcessThread* process_thread,
                            const Config& config)
     : remb_(new VieRemb()),
       bitrate_controller_(BitrateController::CreateBitrateController(true)),
       call_stats_(new CallStats()),
-      remote_bitrate_estimator_(new WrappingBitrateEstimator(remb_.get(),
-                                Clock::GetRealTimeClock(), process_thread)),
+      remote_bitrate_estimator_(new WrappingBitrateEstimator(engine_id,
+                                remb_.get(), Clock::GetRealTimeClock(),
+                                process_thread)),
       encoder_state_feedback_(new EncoderStateFeedback()),
       process_thread_(process_thread) {
   call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get());
@@ -186,9 +208,4 @@
   }
   return true;
 }
-
-void ChannelGroup::SetReceiveAbsoluteSendTimeStatus(bool enable) {
-  static_cast<WrappingBitrateEstimator*>(remote_bitrate_estimator_.get())->
-      SetReceiveAbsoluteSendTimeStatus(enable);
-}
 }  // namespace webrtc
diff --git a/webrtc/video_engine/vie_channel_group.h b/webrtc/video_engine/vie_channel_group.h
index d46a30a..95a042e 100644
--- a/webrtc/video_engine/vie_channel_group.h
+++ b/webrtc/video_engine/vie_channel_group.h
@@ -31,7 +31,7 @@
 // group are assumed to send/receive data to the same end-point.
 class ChannelGroup {
  public:
-  ChannelGroup(ProcessThread* process_thread,
+  ChannelGroup(int engine_id, ProcessThread* process_thread,
                const Config& config);
   ~ChannelGroup();
 
@@ -42,7 +42,6 @@
 
   bool SetChannelRembStatus(int channel_id, bool sender, bool receiver,
                             ViEChannel* channel);
-  void SetReceiveAbsoluteSendTimeStatus(bool enable);
 
   BitrateController* GetBitrateController();
   CallStats* GetCallStats();
diff --git a/webrtc/video_engine/vie_channel_manager.cc b/webrtc/video_engine/vie_channel_manager.cc
index 5fdbde5..b62e282 100644
--- a/webrtc/video_engine/vie_channel_manager.cc
+++ b/webrtc/video_engine/vie_channel_manager.cc
@@ -89,7 +89,7 @@
   }
 
   // Create a new channel group and add this channel.
-  ChannelGroup* group = new ChannelGroup(module_process_thread_,
+  ChannelGroup* group = new ChannelGroup(engine_id_, module_process_thread_,
                                          config_);
   BitrateController* bitrate_controller = group->GetBitrateController();
   ViEEncoder* vie_encoder = new ViEEncoder(engine_id_, new_channel_id,
@@ -366,35 +366,6 @@
   return group->SetChannelRembStatus(channel_id, sender, receiver, channel);
 }
 
-bool ViEChannelManager::SetReceiveAbsoluteSendTimeStatus(int channel_id,
-                                                         bool enable,
-                                                         int id) {
-  CriticalSectionScoped cs(channel_id_critsect_);
-  ViEChannel* channel = ViEChannelPtr(channel_id);
-  if (!channel) {
-    return false;
-  }
-  if (channel->SetReceiveAbsoluteSendTimeStatus(enable, id) != 0) {
-    return false;
-  }
-
-  // Enable absolute send time extension on the group if at least one of the
-  // channels use it.
-  ChannelGroup* group = FindGroup(channel_id);
-  assert(group);
-  bool any_enabled = false;
-  for (ChannelMap::const_iterator c_it = channel_map_.begin();
-       c_it != channel_map_.end(); ++c_it) {
-    if (group->HasChannel(c_it->first) &&
-        c_it->second->GetReceiveAbsoluteSendTimeStatus()) {
-      any_enabled = true;
-      break;
-    }
-  }
-  group->SetReceiveAbsoluteSendTimeStatus(any_enabled);
-  return true;
-}
-
 void ViEChannelManager::UpdateSsrcs(int channel_id,
                                     const std::list<unsigned int>& ssrcs) {
   CriticalSectionScoped cs(channel_id_critsect_);
diff --git a/webrtc/video_engine/vie_channel_manager.h b/webrtc/video_engine/vie_channel_manager.h
index 9776435..db9eb11 100644
--- a/webrtc/video_engine/vie_channel_manager.h
+++ b/webrtc/video_engine/vie_channel_manager.h
@@ -74,10 +74,6 @@
   // Adds a channel to include when sending REMB.
   bool SetRembStatus(int channel_id, bool sender, bool receiver);
 
-  // Switches a channel and its associated group to use (or not) the absolute
-  // send time header extension with |id|.
-  bool SetReceiveAbsoluteSendTimeStatus(int channel_id, bool enable, int id);
-
   // Updates the SSRCs for a channel. If one of the SSRCs already is registered,
   // it will simply be ignored and no error is returned.
   void UpdateSsrcs(int channel_id, const std::list<unsigned int>& ssrcs);
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
index e07ab6c..2bd47be 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
@@ -796,8 +796,16 @@
                ViEId(shared_data_->instance_id(), video_channel),
                "ViERTP_RTCPImpl::SetReceiveAbsoluteSendTimeStatus(%d, %d, %d)",
                video_channel, enable, id);
-  if (!shared_data_->channel_manager()->SetReceiveAbsoluteSendTimeStatus(
-      video_channel, enable, id)) {
+  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+  ViEChannel* vie_channel = cs.Channel(video_channel);
+  if (!vie_channel) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo,
+                 ViEId(shared_data_->instance_id(), video_channel),
+                 "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
+    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
+    return -1;
+  }
+  if (vie_channel->SetReceiveAbsoluteSendTimeStatus(enable, id) != 0) {
     shared_data_->SetLastError(kViERtpRtcpUnknownError);
     return -1;
   }
diff --git a/webrtc/webrtc_tests.gypi b/webrtc/webrtc_tests.gypi
index 17ff23e..0d2b30e 100644
--- a/webrtc/webrtc_tests.gypi
+++ b/webrtc/webrtc_tests.gypi
@@ -33,6 +33,7 @@
       'target_name': 'video_engine_tests',
       'type': '<(gtest_target_type)',
       'sources': [
+        'video/bitrate_estimator_tests.cc',
         'video/call_tests.cc',
         'video/video_send_stream_tests.cc',
         'test/common_unittest.cc',